Screen full of garbace, the C version

I perhaps did not mention, but I am using DASM for compiling assembler code and cc65 for C code. Below is the the C equivalent of the previous routine.


#include "stdio.h"
#include "stdlib.h"

#define SCREENMEM 0x0400
#define COLORMEM 0xD800
#define RASTER 0xD012
#define KEYBOARDMEM 0xDC01

#define POKE(addr,val) (*(addr) = (val))
#define PEEK(addr) (*(addr))

int main(void) {
    int loc = 0;
    char ch = 0;
    char col = 0;
    _randomize();
    while(1)
    {
        if(PEEK((char*)RASTER) == 0x80)
        {
            loc = rand() % 1024;
            ch = PEEK((char*)(SCREENMEM+loc));
            if(ch == 0x51)
                ch = 0x57;
            else if(ch == 0x57)
                ch = 0x20;
            else if(ch == 0x2A)
                ch = 0x51;
            else
                ch = 0x2A;
            col = rand() % 16;

            POKE((char *)(SCREENMEM + loc), ch);
            POKE((char *)(COLORMEM + loc), col);
        }
        if(PEEK((char*)KEYBOARDMEM) == 0xEF)
            break;
    }
    return EXIT_SUCCESS;
}

Adding some color to that mess

OK back to business. Here is a short addition to the previous “character stars” program that adds some random colors to it. The new file can be downloaded here. As before, the file suffix has been changed to fool WordPress. The file is plain ascii asm code.

So what has changed to the previous routine you ask anxiously. Not much actually. First we add some new hard-coded memory locations to the routine just like we did with the screen memory. This is the memory area that defines the color of a specific location on the screen. $D800 (55296) is the address where the color memory starts by default.


SCRMEM1 .byte $00, $04, $FF, $04, $FE, $05, $FF, $06 ; screen memory
COLMEM1 .byte $00, $D8, $FF, $D8, $FE, $D9, $FF, $DA ; color memory

Then we modify the TRANSFER routine so that we take up (to zero page addresses $BD & $BE) the screen color address for the same screen location we randomly chose to draw our character to:


TRANSFER1
    CLC
    ROL    ; get correct screen memory location
    TAY
    LDA    SCRMEM1,Y    ;first half of screen address
    STA    $BB
    LDA    COLMEM1,Y    ; first half of color address
    STA    $BD
    INY
    LDA    SCRMEM1,Y    ; second half of screen address
    STA    $BC
    LDA    COLMEM1,Y    ; second half of color address
    STA    $BE
    JSR    TAILPART

And finally we add some new lines to the DRAW routine that will eventually draw the character on the screen:


DRAW
    STA    ($BB),Y    ; print character
    JSR    RNDBYT
    AND    #$0F    ; scale to 0-15
    STA    ($BD),Y    ; store value to color memory
    RTS

What next?
I have been looking at cc65 a C-crosscompiler that can generate code for Commodore64. I am most likely to go on creating a simple game using sprites and character graphics either with C or assembly. I am also looking at how to generate high resolution (300×200 pixels) graphics in assembler, but that may take a while. I may also expand this blog to cover some of my beginner electronics projects such as this.

Screen full of garbage: random screen location in assembler

OK. Time to move on. In previous post I introduced few issues that one has to take into account when programming in Commodore 64 assembler and introduced the assembler version of that lame “starfield” routine. Which can be found here. It has “.doc” suffix because of WordPress file filters, but it is actually a plain ASCII file. In this post I will introduce the main routine as well as the routine to get the random screen location where to put the character.

The main routine

MAIN
          SEI
          JSR          RDINIT     ;init rnd number
WAIT
          LDA          RASTER     ;check for raster line
          CMP          #$80
          BNE          WAIT     ;wait if not #$80
          JSR          RNDBYT     ;get rnd number
          AND          #$03     ;scale it to range 0-3
          JSR          TRANSFER1
          LDA          $DC01     ;LOAD DATA PORT B / KEYBOARD
          CMP          #$EF     ;SPACE
          BNE          WAIT
          CLI
          RTS
          BRK

The main routine starts with SEI operation that will turn off the system interrupts (try to comment it out and see what happens) and then it will initialize the random number generator routine. Next we will check the raster line, that is, on which screen line the computer is drawing at the moment. We use this to slow down out routine to happen “only” 50 times a second.

Then we get a random number (0-255) and “AND” it with 3 that will zero all the other bits of the random number except the lowest two bits (giving us the range of 0-3). Finally we call the routine to select the random screen location.

Getting the random screen location
By now we have a routine for 8-bit random numbers (values 0-255), but the screen has 1024 locations starting with memory location 1024 ($0400) and ending in location 2047 ($07FF). So I split the screen into four 256 byte chunks and stored the start addresses to memory:

SCRMEM1 .byte $00, $04, $FF, $04, $FE, $05, $FF, $06

Note that the address bytes are wrapped around so $0400 becomes $00, $04. You can actually change the screen memory location, but we’ll look at that later on.

TRANSFER1
          CLC
          ROL          ; get correct screen memory location
          TAY
          LDA           SCRMEM1,Y          ;first half of screen address
          STA          $BB
          INY
          LDA          SCRMEM1,Y ; second half of screen address
          STA          $BC
          JSR          TAILPART
          RTS

So the accumulator contains the previous random number (0-3) fetched in the WAIT routine. We clear the carry flag and rotate the number left one bit (I later realized that using the the normal shift operation, ASL). Now we have a even number between 0 and 6 inclusive. We use this value to select the proper chunk of 255 bits of screen memory.

First, we store that value to the Y register so that we can use it to access memory location and then we get the first (low!) byte of the screen address and place it in zero page to location $BB. Then we increase the Y value and get the next byte (the high byte of the memory location) and place it in $BC. Now we have the starting address of one of four screen location chunks in the $BB-$BC memory location. Next we call the “TAILPART” routine.

Select and print out a character in given location

TAILPART ; check and print the character
          JSR          RNDBYT
          TAY
          LDA          ($BB),Y ; load curren character at $BB+1
          CMP          #$51 ; if it is ball
          BEQ          STEP2
          CMP          #$57 ; if it is donut
          BEQ          STEP0
          CMP          #$2A ; if it is asterisk
          BEQ          STEP1
          LDA          #$2A ; else
DRAW
          STA            ($BB),Y ; print character
          RTS
STEP0
          LDA          #$20 ; space
          JMP          DRAW
STEP1
          LDA            #$51 ; ball
          JMP          DRAW
STEP2
          LDA          #$57 ; donut
          JMP          DRAW

First we get yet another random number. This one defines the actual screen location which we use to store our character, but before that we will read the contents (character) of the same memory location:

  • If the character is ball we will replace it with donut.
  • If it is donut we will replace it with a space
  • If it is asterisk we will replace it with ball
  • Otherwise we will insert asterisk in the screen location.

And then in the DRAW routine we will put the selected character to the selected screen location (we take the address stored in address $BB-$BC, add Y to it and store the accumulator in that memory location).

Finally we return (RTS) back to the TRANSFER1 routine and again return back to the WAIT routine where we will check if space key has been pressed. If not, we do the thing all over again. If space has been pressed we will enable interrupts and exit our program.

That’s about it. Next time we will add some colors to this routine.

Screen full of garbage, enter confusion

So I started to learn 6502 assembly language. It is not my first assembler to dabble with: I’ve been doing some small exercises in Mips assembler (largest program  was a merge sort algorithm). But – oh boy – was I about to face some serious issues.

Data size

8-bit computers surprisingly deal with data in bytes. The registers are byte sized along with the other stuff. So what does it mean? Basically you can freely do stuff with numbers between 0-255, but after that it gets a bit more complicated. Now, 255 is awfully small number if you are about to, for example, multiply a number with another (not to mention the floating point numbers or the BCD format of which I may dabble with later). Even more so if you have been used to use variables like 32 bit integers without thinking it much. Which brings us to the

Instruction set

Oh dear, the instruction set is very small and lacks such novelty things like multiplication. And there is (to my knowledge) no available kernel routine for that (perhaps one could use the Basic multiplication routine?).  So it pretty much looks like one has to do all the boring things first. Maybe my coworker is kind enough to let me to put his “print number” and multiplication routines in this blog at some point.

Registers

You have three of them: accumulator, X and Y and thats about it. Be prepared to swap things around quite a bit. There is also the program stack of which we will have closer look after this set of blogs.

Memory

Where the processor and registers work in 8 bit chunks, the memory address is a 16 bit number. Actually, a wrapped around one so if you want to point to the location $0c00 then you put the low byte first: $oo $0c. With all the other things this just nicely adds up to the initial confusion.
It is also quite hard to start programming a system that relies in the use of various memory locations (or routines residing in certain memory addresses) while you only know a handful of the system addresses.

Something good too!

But in the end I have to admire the simplicity, elegance and openness of the system. No wonder it has been the favorite of many modders and DIY dudes all around the world. And even though the first steps has been as comfortable as sitting on the ant’s nest with no pants on, I have some unexplained need to continue with learning and trying out various silly things with the assembler.

Anyway, here is the full source code of the assembler routine: sfoc2. It is a plain text file, the “doc” suffix is because of the file filter of WordPress. I’ll (try to) dissect the code in the following posts.

The random number generator

Lets start with random numbers instead of doing my own “linear congruential random number” generation routine I just copied one I found from the Compute’s book “Machine language routines for Commodore 64/128 “. The name of the routine is RNDDBYT:


RDINIT                    ; init rnd from the sound chip
            LDA    #$FF
            STA    FREHI3
            LDA    #%10000000
            STA    VCREG3
            STA    SIGVOL
            RTS
RNDBYT
            LDA    RANDOM        ; get random number
            RTS

The RDINIT routine is called just once to set up the random number generator.

  • First the number 255 is put to the accumulator and then stored to FREHI3 ($D40F, 54287) which is the high byte of frequency control for voice 3 in SID changing the voice’s wave frequency to very high.
  • Then the number 128 (8th bit) is loaded to accumulator and it is used to set the voice 3 waveform type to noise (VCREG3, see for example the Commodore 64 user’s guide for more information).
  • And finally the same 128 is used to set up the volume of voice 3 making it inaudible. The maximum volume is 15 so I guess making the number go over the limit will turn volume off?

The RNDBYT routine just copies the value from the “third oscillator’s waveform” whatever that means (probably it is the current value of the voice 3 waveform and since it is rabidly changing noise it will work as random number generator).

Funnily enough the routine RDBYRG in the same book gets the random number in given range (0-255) by reading the oscillator waveform until it gets the number within the given range!! This is almost as good as Bogosort.

Next time we will be back, the blog will talk about getting a random location from screen.

Screen full of garbage, basic version

Introduction
Some weeks ago I got together with a coworker and we got interested in modding my poor old Commodore 64 computer. We are currently building an interface between the C64 and PC so that the computers can communicate via the cassette port. In fact, C64 does think that it is loading a program from a tape instead of another computer. This way there is no need to make modifications to the Commodore 64.

This has also brought up the interest to learn the Commodore 64 assembly language, a skill I never learned as a kid. All those LDAs and STAs were too much for me at the time and I played games and coded in Basic instead.

So few weeks ago I started to look at programming the good old Commodore 64 and found out that my Basic skills had pretty much dried away. I remember being rather good with Basic, but after reading the manuals I started to wonder how much of my Basic coding was just dumb copy-paste instead of really understanding the inner workings of the language and system.

After fiddling for a while I decided to start learning the assembly language. I decided to use Dasm cross-assembler so that I can write the code in some adequate editor and then cross-compile the code to be run either in emulator or inĀ  real C64. I decided to start with a lousy “star-field” program that just fills the screen with some characters. In this post I will do an autopsy to the Basic version of the program and then move on to the assembler version in the future posts.

 "Stars"

"Fancy" star effect aka. screen full of ...

The Basic version

10 print chr$(147)
20 x = (rnd(0)*1023)+1024
30 x = (rnd(x)*1023)+1024
40 y = 32
50 ch = peek(x)
60 if ch=42 then y=81
70 if ch=81 then y=87
80 if ch=32 then y=42
90 poke x,y
100 get i$
110 if i$<>”" then stop
120 goto 30

Line 10 clears the screen.

Line 20 gets a random number between 1024 and 2047 using the internal clock (or some such) as the seed.

Line 30 does the same, but uses the previous random number as the seed. If I would comment out this line, the characters would come up in steady columns like in Matrix (not really, but you get the idea). Such a good random number generator.

Why 1024-2047? As it happens the screen resides in memory locations 1024-2047 and we use this random number to display a character in certain location. For example “POKE 1024,81″ would display a “ball” in the upper left corner of the screen.

Line 40 puts value 32 (space) to variable “y” which we use later on to display stuff on screen.

Line 50 looks at the current character in given location (where our random number points to).

lines 60 to 80 just compare the read value so that if it is

  • asterisk (42), then put 81 (ball) to variable “y”
  • a ball (81), then put “a donut” (87) to variable “y”
  • a space (32), then put an asterisk (42) to variable “y”
  • otherwise retain the old value of 32 in variable “y”

Line 90 does all the work and puts the character in variable “y” to the random screen location “x”.

Line 100 reads user input (one keypress).

Line 110 checks it any key was pressed, if so then stop the program execution.

Otherwise in line 120 jump back to the line 30 and start over again (without clearing the screen, of course).

Looks pretty easy, right?

Follow

Get every new post delivered to your Inbox.