Displaying text/characters & their colours on screens
is all about displaying text/characters on to the screen. Well,
before we move on to the next part of putting text/characters from
screen data memory on to the screen RAM, we shall do a simple little
HELLO WORLD program in C64Studio. Alright, so this is nothing special, but it will
introduce you to a command, often used in turbo assembler called .TEXT.
This is useful for those of you who want to write text, without
designing a screen using any specific hardware or software, i.e. Action
Replay cartridge, Screen Editor, etc. We are using default BANK #3, to
display our screen characters. So the character store range will be
from $0400-$07E7. Where $0400 will be the very first char on screen,
and $07E7 will be the last char on screen.
An example of the HELLO WORLD program.
HELLO WORLD - ASSEMBLY VERSION
* = $0810 ;SYS 2064 to start
JSR $E544 ;QUICK SCREEN
LDA #$02 ;RED BORDER
LDX #$00 ;BLACK
LDY #$14 ;DEFAULT
;DISPLAY HELLO WORLD! AT $0400
DISPHELLO LDA HELLOTXT,X
SPACEKEY LDA $DC01 ;WAIT FOR SPACEBAR
JMP $FCE2;(SOFT RESET C64)
HELLOTXT !TEXT "HELLO WORLD!"
is not a good result, as the displayer uses the second set of
characters (SHIFT+whatever key used), so what we will want to do is
convert the chars by checking what they are. This can easily be done by
adding some extra code into the loop which calls the text display.
Change the code under ;DISPLAY HELLO WORLD to:
;DISPLAY HELLO WORLD! AT $0400
DISPHELLO LDA HELLOTXT,X
CMP #$40 ;IS TEXT CHAR
;ELSE DON'T CHANGE
SBC #$40 ;TO CORRECT CHARS.
CHAROKAY STA $0400,X
is a way to bypass this problem
without needing to change this code, if you are using C64 Studio as it
uses a special screen command which is !CT SCR before !TEXT. So if you
are using C64Studio, just place !CT SCR one line before placing
!TEXT for your message. Otherwise, use this
method if your are using a Turbo Assembler compatible cross assembler
or TURBO ASSEMBLER itself. Another method would be to automatically use
Action Replay cartridge machine code monitor to update the text. Test
the result. Okay, now where SPACEKEY is, insert a INC $D020 but keep
the LDA $DC01 prompt.
Now that's a bit of fun for you eh?. ;)
BACK TO TOP
Data to Screen RAM
can we display text
or characters on the screen? Easy, we use loops, but we need to use
RAM, which is located in different memory banks. We shall stick to the
normal C64 display bank ($0400 - $07E7), so that then we can display
For a start
try and something, which is located at $4000 and then pastes it through
the whole of the screen area. Remember, this is only an experiment.
are different methods, but we'll use a simple method on displaying a
that is located at $4000.
TEXT AT BANK
* = $0900 ;SYS2304
FROM SCREENLOC1 'X' TIMES
;PASTE TO SCREENPOS1 'X' TIMES
LDA SCREENLOC2,X ;READ
FROM SCREENLOC2 'X' TIMES
;PASTE TO SCREENPOS2 'X' TIMES
LDA SCREENLOC3,X ;READ
FROM SCREENLOC3 'X' TIMES
;PASTE TO SCREENPOS3 'X' TIMES
LDA SCREENLOC4,X ;READ
FROM SCREENLOC4 'X' TIMES
;PASTE TO SCREENPOS4 'X' TIMES
; X=X+1 UNTIL X = $FF (256)
;IF X <> $FF THEN GOTO DISPLAY
this routine is smaller and more compact to display text.
Now that you
to display the screens, we want to display colours for the text. And
is how we can do this:
The colour RAM
between $D800 and $DBE7. Therefore, variables can be created for the
So create some new variables, which are as follows:
(underneath STA SCREENPOS4,X) enter the following:
You don't just
screen displaying only text, but you get the text to display painted in
Why not play
the colours. Here is a small table on which colour does what job :o)
DISPLAYING EXPORTED CHARPAD FILES (CHARSET, 1x1 SCREEN (MAP) AND ATTRIBUTES)
you are using a cross assembler, such as ACME, C64STUDIO or any other
particular program. You are using charpad, and would like to display
your own single screens using the CHARPAD? Well, simply create your
very own project. Draw your own graphics screen. For this example, I
have picked up the graphics from one of my cancelled game projects,
Sen2itive (Sensitive 2), as it didn't quite work out for me. I never
even done any levels for the game, after starting the code in 2016.
Here is what you need to do:
Draw a single screen (40 chars
width, 25 chars height) using Charpad V2.0. Colours must be based on
character colour. You may use tiles if you want to, as a start,
compress chars, etc. Then disable the tile mode, so 1x1 chars are used
instead. Save the project. Then export as separate files. They are:
- CHARSET (Basically the charset for your game / demo screen)
- ATTRIBUTES (Colour data of the charset for your game / demo / intro screen)
- MAP (The actual MAP of the game/demo/intro screen)
select some positions to place each raw binary (after extracted)
(Unless you have used a version of charpad that exports single char
screens to .PRG format that is). Now what you want to do is DISPLAY the
background image, multicolour, etc.
This example is based on TURBO ASSEMBLER, in 64ASM;Display custom char screen to BANK 3 screen RAM;by Richard/TND!TO "DISPLAYCHARPADBINARIES.PRG,CBM
*=$0810 ;SYS2064 to runSEILDA #$37STA $01LDA #$18STA $D016 ;Screen Multicolour mode enabled STA $D018 ;Charset mode set to display custom char $2000-$2800LDA #$00 ;Set colour blackSTA $D020 ;to borderSTA $D021 ;and background
STA $D022 ;Char Multicolour 1
STA $D023 ;Char Multicolour 2
;Draw main screen from matrix -
;NOTE max 256 chars per location ($0400-$04FF, $0500-$05ff,
LDX #$00DRAWSCRNLDA MATRIX,X ;Get data from screen data file SCREEN.BINSTA $0400,X ;Put data into SCREEN RAMLDA MATRIX+$100,X ;Fetch the next 256 bytes of data from binarySTA $0500,X ;Store the next 256 bytes to screenLDA MATRIX+$200,X ;... and so onSTA $0600,XLDA MATRIX+$2E8,XSTA $06E8,XINX ;Increment accumulator until 256 bytes readBNE DRAWSCRN ;;Draw attributes from 256 bytes attribs table and place these to SCREEN RAMLDX #$00PAINTCOLSLDY $0400,X ;Read screen positionLDA ATTRIBS,Y ;Read attributes tableSTA $D800,X ;Store to COLOUR RAMLDY $0500,X ;Read next 256 screen positionsLDA ATTRIBS,Y ;Store to COLOUR RAM + $100STA $D900,X ;... and so onLDY $0600,XLDA ATTRIBS,YSTA $DA00,XLDY $06E8,XLDA ATTRIBS,YSTA $DAE8,XINX ;Increment accumulator until 256 bytes readBNE PAINTCOLS
JMP * ;Infinite loop
;If using a cross assembler use CORRECT pseudo command, offset for importing binary data*=$2000 !BINARY "CHARSET.BIN"
RESULT:BACK TO TOP
Moving text horizontally
well as display text, graphics or whatever you like. It is also
possible to move text horizontally or vertically. You many have noticed
intros / demos in the past that allowed to scroll a message across the
screen. Most scroll text tends to be smooth scrolling. Smooth scrolling
is controlled by a raster split, which is featured in the next chapter.
For now, I am going to give you a small example on scrolling a message,
without IRQs and Raster interrupts. This is not an actual program, just
a simple subroutine. If you want to. Create a simple program like;Horizontal scrolling message subroutine
SBC #$02 ;Set speed of scroll (Can be altered)
AND #$07 ;Control max HPOS as $07.
LDA $07C1,X ;Pick row 25, and copy 39 characters from column 1
STA $07C0,X ;Place all characters one column back
LDA #7 ;Just for fun, make yellow text.
CPX #$28 ;Repeat 40 characters, until full scroll of the screen
LDA MESSAGE ;Self-mod address for message position
CMP #$00 ;CHECK FOR @ COMMAND
LDA #<MESSAGE ;RESET MESSAGE
STA SCRREAD+1 ;SELFMOD STORE LOW BYTE OF MESSAGE
STA SCRREAD+2 ;SELFMOD STORE HI BYTE OF MESSAGE
STA $07E7 ;Last char of the screen
INC SCRREAD+1 ;Increment lowbyte position of the message
INC SCRREAD+2 ;Increment hibyte position of the message
XPOS !BYTE 0
;MAIN TEXT MESSAGE
!TEXT "this is a horizontal scrolling message ... "
!TEXT "it can either be long or short ... "
!BYTE 0 ;SETS @
then, how does it work? Well, a loop is called to pull a set of 39
characters from one column forward inside a loop. Then it pulls the 39
characters back one column. A self-modifying setup SCRREAD + 1 or 2, is
used for displaying a single character from the message to the very
last character on the screen. SCRREAD reads the low (SCRREAD+1) +hi
byte (SCRREAD+2) of the scrolling message. The current low/byte address
selected in SCRREAD will place one last character at the end of the
screen. To move on to the next character from the message we want the
computer to display. SCRREAD's low or hi byte self-modifying address
changes. The subroutine will simply increment the low byte of a
message, until value $00 is found. Then it increments the hi-byte.
Every self-mod increment works the same kind of way. Every time you run
a program with a scroll text. It is very important to initialise the
text of the scroll. Simply by calling out:
showed you how to display a 1x1 character. Later on in Assemble It,
there are examples on how to display a 1x2 character to screen. This is
simply called by fetching a screen row above, and changing the
character mode using an EOR or CLC ADC value code. This really depends
on where the next character set value lies to form your own character
set. There's more on this later.
BACK TO TOP
Moving text vertically
text vertically is also possible, but it can eat quite a lot of raster
time. The best way is usually to generate a few loops. The basic idea
of moving a text is simply to pull each row from the top to the bottom
(or vice-versa) inside a loop. Then update a message or similar. A
small example (Using 8 rows and 40 columns):
;Upward Scroller by Richard/TND
LDA YDELAY ;Set out a delay for the upscroll
CMP #$08 ;Delayed enough? because upscroll is FASTER
BEQ YDELAYOK ;compared to side scroll.
INC YDELAY ;Increment delay by 1 byte until 8
LDA #$00 ;Reset delay
LDA YPOS ;Set Y-Position for upwards scroll
BPL DOSCROLL ;If scroll value is UNDER $10 ... Call DOSCROLL
subtract value by 1
STA YPOS ;for smooth scroll.
LDA #$17 ;Reset value of Y POS for scroll
;Move screen data upwards, one row after another
LDA $0400+1*40,X ;Take 40 chars from last row
STA $0400,X ;Position to row above ...
LDA $0400+2*40,X ;Repeat with the next row
STA $0400+1*40,X ;place to previous row ...
LDA $0400+3*40,X ;and so on ...
LDA MESSAGE,X ;Self modifying message ...
CMP #$00 ;@ SPOTTED?
LDA #<MESSAGE ;Reset message now @ is spotted.
SKIPRESET ;Standard message found, skip reset!
CPX #$28 ;Read 40 chars per row
LDA SCRREAD+1 ;Move on to the next row of upscroll
Stored in MESSAGE
YDELAY !BYTE 0
YPOS !BYTE $17 ;Always init with $17 for scroller
!CT SCR ;Convert text to PETSCII screen codes ...
MESSAGE !TEXT "----------------------------------------"
!TEXT "this is an upwards scrolling text, which"
!TEXT "can be as long or short as you want it "
!TEXT "please also note that upwards scrolling "
!TEXT "text can actually take up more space, "
!TEXT "in memory, compared to a horizontal "
!TEXT "scrolling message. still, it works! "
is also possible to reverse scroll a vertical scroller. An example of
this is featured in the game section of this tutorial (Chapter 6).
BACK TO TOPDisplaying Multicolour Bitmap Graphics
multicolour bitmap graphics (i.e. pictures, etc) can be quite a
challenge for newcomers. However it isn't all that hard. All you need
to do is know the charset and bitmap and screen area for where a bitmap
lies. It is also possible to split picture data and place it into
another memory. You can either load in a default picture image, and
split it into 3 files (Colour RAM Data, Video RAM (Screen) Data and
Bitmap). Then install the 3 sets of picture data in to C64Studio as PRG
format (Add !bin "filename.prg",,2). The question is HOW DO I KNOW
WHERE TO PUT THE BITMAP?
Well, the answer is that you can place
the BITMAP into one of the 4 different banks. However the SAME address
of the memory bank must be used. You would also need to change the CHAR
RAM, to be able to read the screen memory position. Here is HOW to
display a bitmap picture. (This is a default Koala Paint default
source below).;Koala paint displayer (Default position)
SCRDAT = $7F40COLDAT = $8328
BACKGROUNDCOLOUR = $00 ;Black selected.
;Draw full colour + screen RAM to
LDA COLDAT,X ;Read colour RAM data at $7f40 (After the bitmap)
STA $D800,X ;Store to C64's Colour RAM
LDA COLDAT+$100,X ;Read the next 256 bytes of colour RAM data, at $8040
STA $D900,X ;Store to C64's colour RAN + 256 bytes
LDA COLDAT+$200,X ;... and so on!
LDA SCRDAT,X ;Read screen/video DATA at $8328
STA $4000,X ;Store to C64's video RAM set at BANK #$02
LDA SCRDAT+$100,X ;Read the next 256 bytes of colour RAM data, at $8428
STA $4100,X ;Store to C64's video RAM + 256 bytes at BANK #$02
;READ 256 Bytes before finished drawing chars
;Set screen BANK to BANK 2, Set char display to #$18
;and allow multicolour mode to be set on to the screen
lda #$02 ;Screen BANK #$02
;Charset mode/Bitmap mode to use $4000 in BANK #$02
lda #$18 ;Screen multicolour on
lda #$3b ;Bitmap mode ON
jmp * ;Jump to itself
;Import the standard KOALAPaint picture into the C64's memory.
*=$6000 ;Default address for koalapaint picture
!bin "goldfish.koa.prg",,2 ;Always use the ,,2 prompt for PRG files
Splitting a picture manually:
split a picture manually, you can use two different methods. The best
method is by using a PC tool that can load Koala paint pictures (or
bitmap pictures of any other format), and split out the data. GANGED is a good example for doing exactly that. It can also convert PC bitmap images into C64 graphics formats. PixCen can probably do the same job, but is more for artistic talent
To split a picture manually on a native C64. You can do it in different ways. The easiest way would be to use Picture Splitter
by Brix. Or alternatively, if you know what type of format your picture
has been saved as. Use a manual save. The manual save here is for
KoalaPaint pictures, being split and saved to a new load address, using
Action Replay/Retro Replay machine code monitor. It might be possible
to do the same with other monitors:
Saving a bitmap data from $6000-$7f40 and setting load address to $2000
Saving a video RAM from $7F40-$8328 and setting load address to $4000
Saving a colour RAM from $8328-$8710 and setting load address to $4400
if you want to display your picture at these addresses?. Well, of
course you would need to link all 3 files to one program (Simply by
loading each binary/prg separately). Here isa C64Studio example which
will do EXACTLY that.
;Displaying a moved picture data to default
;C64 BANK memory
COLDATA = $4400
VIDDATA = $4000
BACKGROUNDCOLOUR = $00
;Draw the bitmap colour + screen data to
;standard screen area at BANK #$03 (Default BANK)
STA $DD00 ;Screen BANK #$03
LDA #$3B ;Bitmap mode
STA $D018 ;Charset /screen mode for displaying screen $0400-$07E8
STA $D016 ;Multicolour mode
;Import binary files (Bitmap, Video RAM and Colour RAM) to memory
all for screen programming part in this tutorial. The next part is
going to be slightly more fun. Where we take a look at raster splits,
interrupts, and create some amazingly fun oldschool effects using
rasters and interrupts. Also we will attempt to make an oldschool
PETSCII intro and a few other things slammed together from previous