PrintAT and Colour
I have been debating with myself regarding how to handle support in relation to these articles. In the past I have given support to anyone that wrote to me via email, contacted me via FB or via Reddit, asked for help on one of the websites where these articles are published and so on. This was too hard to manage since the queries were coming from too many different places and sometimes, I lost track.
Therefore, I decided to change this a little bit. It is taking too much of my time as is. I decided that from article 11 onwards, the only way you can get support is if you join the Phaze101 Facebook group and comment under the article. This should give me visibility of all issues, queries or comments in one place.
Also, for sake of updates that I do from time to time on the previous articles, all updates will be done on the PDF documents only. These are found on the Phaze101 FB group under the files section and on the RetroProgramming Italia (RPI) FB group under the files section. The Phaze101 FB group will hold the English Version of the articles and their updates. Likewise, the RetroProgramming Italia (RPI) FB group will hold both the English and the Italian version and their respective updates. I will not be updating anything else except these.
To keep track of updates, I have updated the PDF article template to include a version number.
Like this, things should be easier to manage since everything is in one place, or at least, two places.
The future of these articles
I like to keep things simple and I hope I have managed to achieve this so far. I also like to use simple English because I think of the many non-native English speaking out there that might be reading these articles. Also, but not least, I like to write in a way that feels like I am talking to you directly.
Having said that, these articles or future ones will always be free, and I won’t be going on Patreon asking for your support. I simply love doing this and I would like to help those that really want to learn. This is something that I really didn’t have when I was younger, and I had to learn everything the hard way.
When my love for these types of articles die, that’s when you won’t have more of these. Till then the articles will continue to flow and hopefully we will cover more advanced topics in the future.
It’s hard right now to release these articles more frequently, however as stated may times, Saturday afternoon is when they will be released, just can’t tell which Saturday 😊
OK Let’s Start.
PrintAT – Example 1
In the last article our PrintAT routine displayed a string in the middle of the screen. The maximum string length is 256 characters. However, what if we wanted to print multiple strings?
Here is the first solution
Not much changed except we added two subroutines. The first one is called DisplayScreen. This routine is called from the Main subroutine of the program.
The second one is called ClearBuffers.
Also, you will notice that at the end of our program we have more strings of text to display on our screen.
We have a total of 5 strings to display. This code is a bit repetitive, but it achieves what we want to do.
This is a call to ClearBuffers which I will explain further down.
Lines 184 – 186
This is our SetCurs Routine, as explained in Article 9. Nothing changed here. We pass the y and x values, and we calculate the offset of where on the screen we should start writing our text.
Line 188 – 190
This is the same as in Article 9 and we print our first text string as usual. Also, nothing has changed here.
The rest is a repetition of the above. We calculate the offset again and print the next string of text on the screen.
The same code is repeated 5 times as per our number of strings.
The only thing that is new is ClearBuffers.
This is a simple routine that clears the 4 bytes where we calculate and store the offset. If we do not do this, we will be adding to the previous offset value. Try it out to see what happens.
The above means that the 16-bit values at memory locations Buf2 and Buf3 are reset to a zero value.
If you run the code with the usual SYS49152 you should see the following screen
It is time we cover another programming topic for the Commodore 64 hardware.
So far, we have set the colour of the border and the colour of the text background, but we have not set the text colour. This colour has always been the light blue that is the default when you switch on your Commodore 64 or start your emulator.
Just as there are 1000 bytes for screen character memory, there are another 1000 bytes for colour memory. There are a number of colour modes, but to keep it simple, we will start with the mode where each character on our screen can have a colour value from 0 to 15. The Commodore 64 colour values are shown below
This table was taken from the CBM Prg Studio Tools à Options à Palette (C64). For a more detailed table you can check the C64 Wiki. It shows more info as per the table below.
Here is the link to the C64 Wiki Colour table
Colour Memory or Colour Ram (pick your choice here) starts at memory location 55296 (\$D800) for the top-left character and ends at 56595 (\$DBEF) for the bottom-right character.
All we need to do is store a value from 0 to 15 into the memory location corresponding to where our character is, and we will change the colour of our character.
What this means is that if we change the value of memory location 55296 (\$D800) our character at memory location 1024 (\$400) with change its colour.
Imagine Colour Memory superimposed on top of our Screen Memory and each character stored on screen memory has a corresponding value in Colour Memory to indicate its colour. The offset value from where the character is stored in screen memory starting at \$400 is the same offset value from where colour memory starts at \$D800.
One final note about colour memory: the values that you can store in colour memory are from 0 to 15 and hence it uses only the 4 lower bits or nibble. Storing or poking the value of 16 is same as storing the value 0, which is black. In other words, the higher 4 bits or nibble is ignored.
PrintAT – Example 2
In this example we will include writing to colour memory and print some text in a different colour other than the default light blue colour, that is colour 14 (\$0E).
Here is the link to the code in Pastebin:
Let’s go through the code and examine the differences that are introduced in the code from the previous example, starting from top. I will skip the routines that were discussed before that haven’t changed.
Lines 24 – 21
This is the area where we define our constants. You will notice that besides the constant for screen memory, I defined a constant for colour memory called ColMem.
We also defined a zero page temp storage space to hold some value.
We need to choose these memory locations in the Zero Page carefully since almost all are used by the system Kernal or Basic. I do not know how many times I used the wrong one and when I return back to Basic the C64 did not respond anymore because I would have corrupted its Basic somehow 😊.
Lines 33 – 58
This is our main loop. At first it might look very different, but in practice, not so much.
We start by setting the Background and the Border. The routine SetBgBorder is still the same.
Next comes the routine ScrFill. This looks new, but in reality, it replaces the routine that we used to call ClearScreen . It does basically the same thing, but it has a new parameter. The new parameter is for the text colour. When clearing the screen, we will be setting the screen text colour using this parameter.
We call the DisplayScreen routine which I have completely changed from the previous one but kept the same name. We will go through this in detail at a later stage.
Once the screen is displayed, we wait for the user to press the spacebar. This is the usual WaitForSpace routine from earlier articles.
The following parts are new but nothing special.
After the spacebar has been pressed, we restore the border and background to the same default colours of the Commodore 64 when switched on.
We also clear the screen and set the text colour to the usual light blue colour 14 or \$0E
Now let’s go through the Subroutines that have changed: you will notice that now I have updated the header comments for each routine by specifying the parameters that each one takes and for what it is used. This will help us remember things better in the future when we will reuse the subroutines.
The ScrFill Subroutine
As stated earlier, this routine is an enhancement of ClearScreen. It takes two parameters: the fill character that needs to be stored in the A register and the Character Colour value that needs to be stored in the Y register.
Lines 83 – 84
We store the values of the A register in a temporary Zero Page memory address. Then we initialise X to zero.
Lines 87 – 91
Basically, this is the same as the ClearScreen routine. We fill the screen with the character specified in the Accumulator.
Lines 93 – 97
First, we transfer the colour parameter stored in Y to the A register. The rest is identical to the above with the exception that instead of using ScrBase we use ColMem. This writes the colour to our colour memory locations.
The rest is still the same. We compare for 250 (\$FA) and if not equal we continue to loop till we have written to all the memory locations.
This routine is a lot shorter than the previous example. We are in fact only passing the beginning of a series of multiple strings. All this is possible thanks to the way we are storing our strings.
Let’s have a look at our series of multiple strings at the end of the code.
Line 295 – 296
In the memory location labelled NoStrs we are storing the number of strings we are passing to the DisplayScreen subroutine. In this case we are saying that we are passing 6 strings.
We could have passed this as a parameter to the routine however I prefer to store it as close as possible to the strings.
Line 229 – 300
The first 2 bytes where our first string is stored at memory location labelled Strings, are the x and y position for the first string. In the previous article, these were parameters to the SetCurs routine, but now they are used here. Our string still ends with a zero byte value but it starts right after the 2 values that are the x and y coordinates where it has to go on the screen.
In doing the above we have solved a big repetitive task. In example one of this article, you may recall that for each string, we had to repeat the same code: we had to set where the string is located on the screen and then display it. The new PrintAT routine is more intelligent and is able to know how many strings it needs to print and also where each string has to go on the screen.
The next 5 strings follow the same pattern – a pair of coordinates and a zero-byte terminated string.
The Enhanced Print AT Routine
Lines 188 – 190
This is still the same as the old version. We store the source address of where our multiple strings start.
Line 192 – 193
Here we store the number of strings in a Temporary memory location for future reference.
Lines 197 – 205
We just make sure that the buffer memory locations used by our SerCurs routine are all initialised to zero.
We then read the first two bytes of the string pointed to by the source memory address in the Zero Page. We store these in the X and Y register and call the usual subroutine SetCurs to set the position of where we will be writing on the screen.
Lines 207 – 214
This is a simple addition to add 2 to our 16bit source address so that we point to the actual character string that we want to print.
Line 216 – 220
This is the same as in the old print routine. We basically set the destination address where we will be writing the string to the screen.
Lines 222 – 230
This is also the same as the old print routine covered in article 9 and in the first example of this article. We simply print the string one character at a time from the source address to the destination address until we hit the zero byte of the null terminated string. We then skip to the next step.
Recap Lines 196 – 230
All these lines basically set the position on the screen and print a string. Previously, we had the SetCurs sub routine being a separate sub routine and we called it before the PrintAT. Now, SerCurs is part of PrintAT and it is the PrintAT routine that calls it. PrintAT still needs to format the parameters that SetCurs needs before it is called.
Lines 233 – 241
Remember that in TempMem we stored the number of Strings we need to print. Since we printed our first string, we decrement the value in TempMem and if this is a zero we know that there are no more strings to print and so we exit by jumping to PrintExit.
If there are more string to print, we do the next part.
Lines 243 – 256
We increment the Y register to point to the beginning of the next formatted string. We add the Y register value to the source 16-bit address. This will point the source address to the first 2 bytes of the next formatted string which are the X and Y Coordinates of where the next string is going to be printed on the screen.
Since we know there is a string to be printed and the source address of the print routine is pointing to it already, we jump to SetPos and start all over again by first setting the position of where the string is going to be printed and then we print the string.
That is basically it. There are no more routines that have changed.
If you type the usual SYS49152 you should see the following screen.
As you can see, besides setting the Border and Background colours, this time we also set the foreground colour or the text colour to black.
That is all for now. We have come to the end.
PrintAT is a very powerful routine. In the next article I will finish off the PrintAT series of articles but it will end with a big surprise that will illustrate the true power of this routine.
As always, if you have any questions please message me on either the Phaze101 Facebook group or the Retroprogramming Italia FB group. May the coding force be with you.
Coding is Fun 😊
Thanks Go To
English proofreading: Colin Vella
Translation to Italian: Davide Aldegheri
Italian proofreading: David La Monaca
Coding Check: Daniele Verzotto
And Retro Programming Italia