Thursday, 27 February 2020

C64 quickie - autorun assembly code


One thing my previously mentioned Snake 1K game didn't do was automatically launch. Typing in SYS 4096 every time is not a huge task, but it nonetheless gets old fast.

It's actually a very simple issue to solve, though - so I thought I'd hammer out a very quick explanation of how to do this for any assembly code program.

On the C64, BASIC starts at memory location 2048 (or $0800 in Hex). All we need to do to create a launcher for our code is to "assemble" in some data at that location that forms a BASIC program, that in turn runs our code.

This doesn't take that much effort to do:

You can easily change the ASCII values for the SYS address to any address you wish to place your code at. Each value is simply represented as Hex code $3x, where 'x' is the value between 0 and 9, forming (in this case) 2062.

If you assemble a program built with this at 2048, the .prg (or a.out) file produced will automatically create the BASIC code when loaded. If you drag the file into VICE's window, you won't even need to type RUN as VICE does this automatically in this situation.


Anyway, I hope that is useful! Until next time :)

[Copy-Paste-able version of code now follows...]

   processor 6502

    org 2048 ; start of BASIC program area in memory

    ; BASIC launcher

    .byte $00                ; first byte has to be zero for BASIC program to work
    .byte $0c, $08           ; pointer to next BASIC line in memory, i.e. $080C
    .byte $0a, $00, $9e, $20 ; the code for: 10 SYS (includes trailing space)
    .byte $32, $30, $36, $32 ; ASCII version of SYS address, i.e. 2062
    .byte $00                ; line terminator
    .byte $00, $00           ; the pointer above points to this place in memory
                             ; as we have no other line, we leave both bytes zero
                             ; end of program

    ; memory location 2062 comes next, which our SYS command above calls

    ; (i.e. 2048 + 14 bytes for our BASIC program above)

start:
    ; your C64 assembly program goes here
    ; to demonstrate, this simple program just changes the screen color

    jsr $e544 ; clear the screen
    lda #$00
    sta $d020 ; border to black
    lda #$05
    sta $d021 ; background to green
    lda #$00  ; Black text
    sta $0286

    rts ; back to BASIC!


Saturday, 22 February 2020

The Dark Heart of Uukrul [RPG | DOS]


I've recently been playing this hugely underrated gem, and thought it worth a mention here.

The Dark Heart of Uukrul is a very old-skool RPG from a bygone era (way back when in the dark magical mists of 1989), that these days runs most effectively via DOSBox. No config is required, other than mounting the folder you unpack the files to as the C drive. It just works. (Pro Tip: the game files can very easily be found with a simple Google search.)

The game has no sound of any kind whatsoever, which on the plus side does at least mean no fiddling with IRQ and DMA settings to persuade it to run. Pick a solid track listing from Spotify and off you go!

After a short and lightly comical character creation sequence, you are dropped straight into the corridors of the ancient city under the mountain, in which your gaming session takes place.


The exploration view is reminiscent of Bards Tale era games, with some Dungeon Master-ness thrown in for good measure. Cursor (or ASDW) keys move you around the landscape, where you will encounter colorful descriptions of the rooms passed through, puzzles to stump even a veteran of RPGs of its - or any other - era; and monsters most foul - all comprising the elements of your quest to defeat the evil Uukrul of the title.

On the subject of monsters, whenever conflict arises, the game switches to an Ultima-style top-down 2D view for the duration of the battle, where turns are taken between your characters and the enemies.


Movement is a simple matter of choosing one of the eight available directions for each character, and weapon-based combat is also straightforward: just select which adjacent enemy to fight, and you're good to go (hit or miss).

Magic requires actual knowledge of the mystical words of power, so having a physical copy of the manual to hand as you play is a definite plus here (I chose to have the PDF version open in another window, and switch to it from DOSBox as required). It also requires your character to possess the appropriate magic rings of the correct element (e.g. Iron, Copper, etc) to trigger the spell or prayer.

Normal sorcery is just a matter of typing the name of your spell, and choosing a target (if applicable), and if you have the spell points, then that's it.

Priest spells on the other hand require the favour of the appropriate god to work, and more often than not, that favour is not forthcoming - meaning a missed turn (or even worse, a punishment from said deity for the irritation you have caused them).

I'm still fathoming all the details of this system, so I guarantee this will have more than enough surprises to entertain you as you journey into ever more perilous encounters.

In fact, I'm not all that far into the game as yet, but the premise and first rate design of the game is compelling me ever further into it. I'd quite like to get back to it right now, in fact...

If you've never heard of this game, and would like to probe the depths of the history of gaming (and RPGs), then you can certainly do a lot worse than this title. Apparently, it sold very poorly on its release, which in my opinion is a criminal injustice for such an extremely interesting and individual title.

Just one more thing...

It also occurred to me that my recent forays into the world of the C64 could perhaps benefit from consideration here. A game of this sort wouldn't be too difficult to craft on that machine (and I'm already thinking of algorithms for the two views, and how to store the data, dialogue and descriptions to fit in 64K).

I am not promising anything just yet, but I may well create a C64 homage to this title with a plot and world of my own devising... (Perhaps) watch this space?

UPDATE:

Had a very quick go on PetDraw (written by the 8-Bit Guy), and produced this:


This is on the C64 (in VICE) using just character mode and with no redefined characters (I would need some for the real thing, but this is just a proof of concept at this stage). With either careful use of a custom character set, and/or some sprites over the top, this could work very well I think!

Sunday, 16 February 2020

C64 Snake Game in under 1K


Here is very simple game of Snake, written in 100% 6502 assembly for the C64.

In total, it comes in well under 1K of memory in size (628 bytes to be exact). The only other memory it uses when running are the two 16-bit general purpose vectors in zero page memory, some of the SID voice 3 vectors (for a random number generator) and the video memory of the C64 itself.

In fact, if you discount the snake body pieces buffer (which once the code is loaded could in theory be placed anywhere in the C64's RAM), the code in fact comes at 458 bytes in size, and so could quite happily sit on the 512 byte boot block of an old-style floppy disk with room to spare.

It's certainly not the best version of Snake in the world - it lacks a score, any music and joystick support. (Keyboard controls are P - up, L - down, Z - left and X - right). But it works, uses the entire character area of the screen and has a certain degree of challenge.

Mainly, it was an exercise in properly learning the 65xx processor instruction set, while trying to come in under 1024 bytes in size as an extra personal challenge.

Anyway, copy-paste the code into a new text file renamed to 'snake1k.asm', and assemble it using:

    dasm snake1k.asm

then drag the resulting a.out file into VICE to try it out using:

    SYS 4096

from BASIC. I've also tested it on theC64 (or Maxi as some like to call it), where it also works just fine.

Short video of it running here:

https://www.youtube.com/watch?v=vOrLySWMXFY

Enjoy!

processor 6502
org $1000

NUMBER_OF_SNAKE_PARTS_TO_ADD = 4
FOOD_OUT_OF_RANGE_POS        = $FF

SNAKE_DIRECTION_LEFT = 0
SNAKE_DIRECTION_RIGHT = 1
SNAKE_DIRECTION_UP = 2
SNAKE_DIRECTION_DOWN = 3

_start:
; RND technique using SID from:
; https://www.atarimagazines.com/compute/issue72/random_numbers.php
LDA #$FF  ; maximum frequency value
STA $D40E ; voice 3 frequency low byte
STA $D40F ; voice 3 frequency high byte
LDA #$80  ; noise waveform, gate bit off
STA $D412 ; voice 3 control register

jsr $e544 ; clear the screen

; Initialize everything
ldy #0
init:
lda default_values,y
sta snake_head_x,y
iny
cpy #[body_directions - snake_head_x + 1]
            ; +1 to include first body byte
bne init

draw_snake_head:
ldx snake_head_x
ldy snake_head_y
jsr calculate_snake_screen_address
            ; exits with y == 0

lda #87
sta ($FD),y ; y should be zero by here

; save head address for use when erasing later
lda $FD
sta $FB
lda $FE
sta $FC

draw_snake_tail:
ldx snake_tail_x
ldy snake_tail_y
jsr calculate_snake_screen_address

lda #81
sta ($FD),y ; y should be zero by here

; delay wait to make each update playable :)
ldx #$20
wait:
ldy #$FF
wait_inner_loop:
dey
bne wait_inner_loop
dex
bne wait

; erase head
lda #81
sta ($FB),y ; y should be zero by here, ptr == head position

; erase tail
lda #$20
sta ($FD),y ; y should be zero by here, ptr == tail position

; move_head
lda body_directions
and #%11000000 ; keep only head direction
bne check_head_right
dec snake_head_x
check_head_right:
cmp #$40
bne check_head_up
inc snake_head_x
check_head_up:
cmp #$80
bne check_head_down
dec snake_head_y
check_head_down:
cmp #$C0
bne move_head_done
inc snake_head_y

move_head_done:
; Add a single snake part (if required) for this game loop
lda snake_parts_to_add
beq move_tail
inc snake_length
dec snake_parts_to_add
jmp skip_tail_move

move_tail:
; Get snake tail direction, move tail
ldx snake_length

; we now need to divide by 4 to get the byte position
txa
clc
ror
clc
ror
tay ; y is now buffer bytes offset

txa
and #$03
tax
        ; x == number of 2-bit shifts in byte to get tail direction

lda body_directions,y
; a == direction value for four possible body parts

direction_shift_loop:
dex
bmi tail_direction_found
rol
rol
jmp direction_shift_loop

tail_direction_found:
and #$C0 ; get just that one direction in top two bits

; a == tail direction in two high bits
and #%11000000 ; keep only tail direction
bne check_tail_right
dec snake_tail_x
check_tail_right:
cmp #$40
bne check_tail_up
inc snake_tail_x
check_tail_up:
cmp #$80
bne check_tail_down
dec snake_tail_y
check_tail_down:
cmp #$C0
bne skip_tail_move
inc snake_tail_y

skip_tail_move:
; Update all body directions as snake moves
lda body_directions
and #$C0
tay
jsr update_body_directions
jsr update_body_directions
lda #$3F
and body_directions
sta body_directions
tya
ora body_directions
sta body_directions

; check for all collisions, with edges and snake parts
ldx snake_head_x
cpx #$FF ; gone past zero, so hit screen edge
beq game_over

cpx #40
beq game_over

ldx snake_head_y
cpx #$FF
beq game_over

cpx #25
beq game_over

ldx snake_head_x
ldy snake_head_y
jsr calculate_snake_screen_address
lda ($FD),y ; y should be zero here
tax

        ; increase snake length, clear food
cpx #83 ; food?
bne check_for_obstacle
lda #NUMBER_OF_SNAKE_PARTS_TO_ADD
sta snake_parts_to_add
lda #FOOD_OUT_OF_RANGE_POS
sta food_x
sta food_y
bne collision_checks_done

check_for_obstacle:
cpx #$20
bne game_over

collision_checks_done:
jsr read_keys

; food never appears at FOOD_OUT_OF_RANGE_POS
lda #FOOD_OUT_OF_RANGE_POS
cmp food_x
bne draw_food
cmp food_y
bne draw_food

jsr get_rnd_pos
stx food_x
sty food_y

draw_food:
ldx food_x
ldy food_y
jsr calculate_snake_screen_address
lda #83
sta ($FD),y ; y should be zero after calculation jsr

jmp draw_snake_head

; Game Over - restart the game
game_over:
ldx #0
stx 198 ; clear key buffer
jmp _start

; Entry: none
; Exit: x == xcoord, y == ycoord, a corrupt
get_rnd_pos:
ldx $D41B ; get RND from SID
get_rnd_x_loop:
cpx #40
bcc get_rnd_y
txa
clc
sbc #40
tax
bne get_rnd_x_loop

get_rnd_y:
ldy $D41B ; get RND from SID
get_rnd_y_loop:
cpy #25
bcc get_rnd_done
tya
clc
sbc #25
tay
bne get_rnd_x_loop

get_rnd_done:
rts

update_body_directions:
ldx #0
update_body_loop:
rol ; use carry from A
            ; (first time through will be garbage but that's okay)
ror body_directions,x
ror ; temp store carry in A for next time round the loop (and next byte)
inx
cpx #170
bne update_body_loop
rts

; Read Keys and modify head direction accordingly
; Exit: a,x corrupt
read_keys:
clv
ldx 197 ; read key buffer
cpx #41 ; P
bne check_down_key
ldx #[SNAKE_DIRECTION_UP << 6]
bvc key_direction_update

check_down_key:
cpx #42 ; L
bne check_left_key
ldx #[SNAKE_DIRECTION_DOWN << 6]
bvc key_direction_update

check_left_key:
cpx #12 ; Z
bne check_right_key
ldx #[SNAKE_DIRECTION_LEFT << 6]
bvc key_direction_update

check_right_key:
cpx #23 ; X
bne check_keys_done
ldx #[SNAKE_DIRECTION_RIGHT << 6]

key_direction_update:
lda body_directions
and #$3F ; Keep all bits except top two (head direction)
sta body_directions
txa ; get new direction for head
ora body_directions
sta body_directions

check_keys_done:
rts

; Calculate Snake Screen Address
; Entry: x, y - screen coordinates
; Exit: y == 0, x,a corrupt
calculate_snake_screen_address:
; initialize character screen memory pointer
lda #0
sta $FD
lda #$04
sta $FE

; calculate actual address
row_address_calc:
cpy #0
clc
beq row_address_calc_done
lda #40
adc $FD
sta $FD
lda #0
adc $FE
sta $FE
dey
bvc row_address_calc ; 2nd adc never overflows, so safe
row_address_calc_done:
txa
adc $FD
sta $FD
tya ; y guaranteed to be zero here, saves a byte over lda #0
adc $FE
sta $FE
rts

default_values:
dc.b 19,12, 20,12, 1, 4, FOOD_OUT_OF_RANGE_POS, FOOD_OUT_OF_RANGE_POS, 0

snake_head_x:
dc.b 0
snake_head_y:
dc.b 0
snake_tail_x:
dc.b 0
snake_tail_y:
dc.b 0
snake_length:
dc.b 0
snake_parts_to_add:
dc.b 0
food_x:
dc.b FOOD_OUT_OF_RANGE_POS
food_y:
dc.b FOOD_OUT_OF_RANGE_POS
body_directions:
ds.b 170, 0 ; each byte has four body part directions in it,
    ; each direction two bits,
    ; = left, %01 = right,
    ; %10 = up,   %11 = down

_end:
; label only here to measure length of program

Saturday, 28 September 2013

C64 Coding - Part 3 - My First Program!

Right, now all the setting up is out of the way... what can we do with all this?

This part of the tutorial will be longer than most, because we will examine each component of our program until we understand every single element of it. It won't always be like this (I will attempt only to explain new concepts as they arise in future posts). But for this groundwork, it is essential that we look in detail at everything.

If you have done assembly language coding before, you may want to skim-read the code itself, and then move onto the next Part... Otherwise... take a deep breath!

Writing the code


Open up Notepad++ and type the following (note! line-beginning whitespace is important here - but you can use the spacebar or tab key for adding that whitespace)

<space>processor 6502
<space>org $1000

my_label:

Note the line of separation between the org and my_label? This is purely for layout purposes, so the code is easier to read. Use line spaces to separate logically distinct areas of code - when you come back to your code in six months time, you'll thank me for this!

NB: In future, I will not specify whitespace with <space> - just remember that all instructions expect a preceding space on their line, except for labels (e.g. my_label), and code relocation statements (see later).

So, keep an eye out for such formatting in all future code samples!

Save the file you have created in Notepad++ (File menu, Save) - when you are prompted for a filename, use the filter drop down to select ".asm" as the extension / file type. Then choose a name, e.g. "MyFirstPrg"

(Once you have performed the initial save, you can use the save toolbar button or Ctrl S to save your file to the same place without a folder browser, just like in any other Windows app).

Now add the following lines to the end of your .asm file. Don't worry about their meaning yet - we shall cover this shortly.

 lda #$08
 sta $0400
 lda #$05
 sta $0401
 lda #$0C
 sta $0402
 lda #$0C
 sta $0403
 lda #$0F
 sta $0404

 lda #$20
 sta $0405

 lda #$17
 sta $0406
 lda #$0F
 sta $0407
 lda #$12
 sta $0408
 lda #$0C
 sta $0409
 lda #$04
 sta $040A
 rts

Save the file.

Now, from the command prompt (ensuring you are in the E:\C64\src folder), type:

dasm MyFirstPrg.asm -oMyFirstPrg.prg

and press Enter.

If all has gone to plan, you should be returned to the command prompt with no errors. There will now be a "MyFirstPrg.prg" file in the src folder.

From the command prompt once more, type:

x64 MyFirstPrg.prg

This should launch the C64 emulator, VICE, with your newly created program.


Next, we need to execute the code we have loaded into the emulator. Type:

SYS 4096

into the running C64 and press Enter. You should see this:


Notice the text that has appeared on the first line of the screen!

Congratulations! You have just written your first Commodore 64 assembly language program :D

What does it all mean?

So, you would probably like to know how that all worked?

The starting two lines of our .asm file are fairly simple.

The first line tells 'dasm': "We are targetting the 6502 processor", which is what the C64 uses (actually, the C64 uses the 6510, but the assembly code is the same - so we choose this).

The second line says: "We are starting our code at memory location $1000".

The dollar sign tells the assembler that the number that follows is in Hexadecimal. If you are unsure what this means, take a look at this wikipedia page.

Hexadecimal (or Hex) numbers are handy for computer programming, because they concisely represent numbers in a form appropriate for machines that, at their lowest level, use binary. Binary is extremely long-winded to type out, but conveniently hex numbers are both shorter while also organising numbers into logical groups of 4-bits.

For this reason, most numbers in assembly language programs will be represented in Hex, rather than either binary (the machine's notation) or Decimal (our usual numbering system). It's basically a "best" of both worlds.

$1000 in decimal works out as "4096".

The C64's BASIC interpreter (what you start in when powering up a C64) uses decimal numbering to be human friendly. This is why we type "SYS 4096" to launch our code (SYS simply means "execute SYStem code at the following location").

NB: If any of this is confusing at this point, it would be a good idea to take a break from this tutorial and read up on number bases (specifcally the Hex and Binary representations, and their relation to our usual Decimal system) before proceeding. All that follows will assume familiarity with these number forms.

The Actual Code


Right, so memory code placement location and processor choice out of the way... What does the actual code do?

Our first line of code is:

 lda #$08

This translates as: "Load the Accumulator with the value #$08".

The accumulator is the 6502 processor's adding/subtraction register. It is the primary storage location for values during most calculations.

Shorthand for this register is the letter "a". Hence, "lda" is the same as saying "load a".

A register is a storage location within the CPU (the 6502 in this case). Because it is within the processor, it is extremely fast to access - unlike system memory (i.e. the storage cells in the RAM chips).

If you wish to perform calculations, you should prefer using registers over memory when the choice is available.

Now, we know from our "org" statement that $ means Hex, so $08 clearly means 8-in-Hex - which happens to be the same as 8 in Decimal (or 00001000 in binary).

But what about the # character?

CPUs have several different ways to address memory. If instead we had written:

 lda $08

what this would mean would be "Load the Accumulator with the value stored at memory location $08". That is to say, load a with the contents of memory location 8.

In a newly started system, a memory value could be anything (though it will most likely be either part of the built-in ROM code, or reset to zero by the operating system).

This is not what we want - we wish to choose not the location, but the value itself.

The # character says "the value" instead of "the value of memory location", turning our command into:

 lda #$08

or "load the accumulator with the value 8".

(NB: This form of CPU addressing is referred to as immediate mode, because the immediate value following the instruction is used, rather than the memory location or address).

Phew! If you have never touched assembly language before (or even programmed a computer before), all of this might seem a lot to take in - so relax, and ponder what you've read up until now before proceeding with the rest of this post.

***

So back with us? Good!

The next command is:

 sta $0400

This means "store the contents of the accumulator at memory location $0400".

As it happens, in a newly started C64, memory location (or address) $0400 is the start of the screen memory. The C64 starts off in "character mode", which means the mode used to draw letters to the screen.

Given our previous command, this in combination effectively means: "store the value 8 at location $0400".

The value 8 turns out to be the character code for the letter "H". So in human terms, we are actually saying: "store the letter H at the first location in character screen memory", which displays the letter H on the screen!

If I then tell you that the C64's character codes start at #$01 for A, #$02 for B, and so on - can you now guess what the rest of the (mostly similar) code is doing?

(Clue: value #$20 is a SPACE character...)

Hopefully, you can see now exactly what is happening here. Each line of code sets the next memory location with the character we require to make up the text "HELLO WORLD".

There is just one last thing to clear up: what does "rts" mean?

Well, when we call our code using the "SYS" command, under the hood this uses an instruction called "jsr" to jump into our code (in this case at 4096, or $1000).

"jsr" means "Jump into SubRoutine".

A sub-routine is a self-contained block of code that, prior to entry, remembers where it was launched from (we will cover this much later in the course, but for now, assume the previous location is stored somewhere by the computer, to be retrieved when needed).

"rts" means "Return from SubRoutine". Since our code was called from BASIC via the SYS command, "rts" tells the C64 to "Return to BASIC".

So all that instruction means is: finish our program now, and go back to where we came from!

What a lot of effort just to say Hello World!


Well... yes! It might look that way upfront. It is possible you have heard of assembly language being spoken of in hushed tones by experienced programmers, who insist that assembly language is "hard".

In fact, assembly language itself is very simple - in the sense that each instruction does a very small amount of work. It is in fact this that makes assembly language trickier than higher level languages such as BASIC or C/C++. Assembly language is, ironically, "hard" because it's "simple"!

You have to string together many smaller commands to make up the code for what you want to achieve. That is (possibly) the downside.

But the upside is that you have total control over the CPU in your machine. You are speaking the language of the machine itself, and that gives you unprecedented power over what you wish to achieve.

As with all things, with such power comes great responsibility. Use it wisely!

Which is what we shall now try to do in the following posts :D

C64 Coding - Part 2 - Setting Up

So, you have downloaded all components from part one. Perhaps you've also installed them... but if not, here is the way I did it:

  • Notepad++ - default installation. Easy!
  • dasm - installed to a location within a C64-related folder (see below)
  • VICE - same again
I have a second drive in my PC, used for data (and games). I have labelled this drive E:

The folder structure will reflect this, but if you only have one drive, or have a different drive letter arrangement, substituting it for E: should be good enough to replicate my steps below.

Note: all steps assume Windows 7 usage. (If enough people ask, I shall also detail how to do this on the Mac.)

I firstly opened a command prompt and created a C64 folder.
  1. Press the Windows key, to bring up the search box.
  2. Type "cmd" and press Enter. This should bring up a black DOS command prompt window.
  3. Type "E:" and press Enter (which should place you on the E: drive)
  4. Type "mkdir C64" and press enter. This should create your very own C64 working folder.
  5. Type "cd C64" to enter the folder.
Basic folder created!

Now, I prefer to separate my tools from my code, so I used the following command window steps to create separate folders for development.
  1. mkdir src
  2. mkdir dasm
  3. mkdir vice
Both dasm and VICE come as compressed zip (or equivalent) archives. I chose to expand these archives to the folders illustrated in steps 2 and 3, to keep them separated.

So that I could run both apps instantly every time I opened a command prompt window, I did the following:

  1. Click on the Start menu button.
  2. Right-click on "Computer"
  3. Select "Properties"
  4. Select "Advanced System Settings"
You should arrive at this window:



  1. Select "Environment Variables..."
  2. Under "System variables", locate and select the entry for "Path".
  3. Click the "Edit..." button
This will present you with a dialog for editing the system paths that the command prompt will check for existing commands.
  1. Click on the "Variable value" edit field.
  2. Press the End key to jump to the end of the field.
  3. Type ";" (semi colon)
  4. Add the full path to the binary directory in the dasm folder you created earlier, e.g. "E:\C64\dasm\dasm-2.20.11\bin" (look for the "bin" folder in what you expanded)
  5. Type ";"
  6. Add the full path to the VICE folder you extracted earlier, e.g. "E:\C64\vice\WinVICE-2.2-x64"
  7. Click the OK button on the variable dialog.
  8. Click the OK button on the Environment Variables dialog.
  9. Click the OK button on the System Preferences dialog.
If you have a command window open, close and reopen it. Then from the command prompt, type:

dasm.exe

and press Enter. If all is well, you should get a usage report from the dasm tool, no matter where you are located in the file system.

Do the same for:

x64.exe

which should also test the same thing for WinVICE.

If all is well, you are ready to go! Simply use the command prompt window to move to the "src" folder with:

E:
cd E:\C64\src

and you will be in the right place to make some C64 code!

C64 Coding - Part 1 - A Modern Day Coder's Prodding

One thing was certain from day one: no way was I going to code directly on a real (or emulated) Commodore 64.

The days of poking, peeking and hoping my tape/disk drive didn't just die on me are long since departed - and rightly so. Even the most basic PC operating system's tools often wipe the floor with anything that came with the old 8-bit computers.

I wanted a cross-assembler solution, just as I'd used for the ZX Spectrum some time before. What would I need for coding for a C64 on a modern PC?

Basic Requirements


There are some basic tools we will need to edit, assemble and run our C64 programs. I'd recommend:-
  • Notepad++ - Text Editor, has syntax highlighting for assembly files, free!
  • dasm - cross-assembler that supports 6502/6510 CPU instruction generation
  • VICE - C64 emulator
Naturally, you might have a preferred editor for source code, and by all means use it! However, for our purposes, Notepad++ will do just fine.

A 6502 Assembly Reference


Don't panic! You don't need to understand all of this immediately - but it will come in extremely handy later: a complete 6502 instruction reference.


Just keep it handy (i.e. bookmark it!) for when we need to discuss the details.

A Really Good C64 / VIC II Guide


I used this to learn the basics - and it rocks:


Also this:


So, in that case (you may be wondering) why blog about this at all?

Well...

Those are great links for anyone who ever dabbled in 8-bit machines in the past. But it occurred to me whilst reading much of the stuff that:

A lot of assumptions are made.


It makes sense, since those articles are aimed at enthusiasts. But I know at least one person who never tried this stuff before, but has an interest in playing about with it - perhaps a more comprehensive guide is required?

There is no cohesive "project" being built.


A great tactic when constructing a tutorial is to produce - over the course of all the units in said tutorial - a complete project, application or game, that pulls together all the ideas presented. Neither of these (still great!) introductions really do this.

Sometimes, clarity is lacking.


There were several moments when I read sections in those articles that I got lost. That is, I needed to constantly refer back to previous chapters, and read the passages again. This is not necessarily a bad thing in itself, but I've always found that learning coding techniques comes more naturally when you can simply refer to your own notes - or even better, code - to recap on what you have learned thus far.


So! I realised... perhaps I should record my own experience somewhere... Maybe... perhaps... in a blog?

Huzzah!

C64 Coding Adventure - An Introduction



Hello! Welcome to a new coding adventure, into the land of yesteryear...

Back in the early 80s, when home computers exploded upon us all, I became the proud owner of a Sinclair ZX Spectrum. That little beast was responsible for a hobby that ultimately grew into a career that blossoms to this day.

However, some of my classroom rivals naturally enough had the competing Commodore 64 (boooo!) - a machine that I insisted was nowhere near as fabulously awesome as my own Speccy. How could it be?

Well, fast-forward to the (more or less) here and now, where I found myself looking about for a new retro coding project to dive into, when it dawned on me: why not go back to that old playground competitor, and see what really made it tick?

I have never owned a C64. Until now, other than the odds and ends gleaned from a rabid C64 fanatic at school, I never learned how to code it in any way whatsoever. I've never coded on a 6502/6510, and wouldn't know a VIC vector if it smacked me in the face.

That is all about to change...

What I note here in the coming (likely sporadic) weeks and months is my own personal What If time-travelling excursion into an unknown world... and a traitorous crossing of territories.

Was the ZX Spectrum really the King Of The Home Computer Playground?

Let's find out!