To make machine language programs more friendly it is nice to add a basic stub which contains a line with a SYS
statement to start the code. This is easy to do on the Vic-20 and the process gives you an insight into how Basic programs are stored in memory. I'll show you how to do this and how to extend the programs to meet your needs.
A Basic program consists of a series of Basic lines followed by two 00
octets to signify the end of the program. Each Basic line starts with a 16-bit next line link to the next Basic line in memory. Then there is a 16-bit Basic line number. The following bytes represents the statements on the Basic line and is terminated by a 00
octet.
To create the following Basic program:
2013 SYS 4110
We could use this simple Basic stub for an unexpanded Vic in xa65 assembler:
* = $1001
.word basicEnd ; Next Line link, here end of Basic program
.word 2013 ; The line number for the SYS statement
.byt $9e ; SYS token
.asc " "
.asc "4110" ; Start of machine language
.byt 0 ; End of Basic line
basicEnd .word 0 ; End of Basic program
The location 4110
is the next memory address after the end of the Basic program. The Basic program starts at memory location $1001
which is 4097
in decimal, and the Basic stub is 13
bytes long, so 4097 + 13 = 4110
.
Using Vicmon to Explore a Basic Program
To see how the Vic-20 stores a BASIC program in memory we can use the Vicmon Cartridge, introduced previously. First power cycle your Vic and enter the following program:
2013 SYS 4110
On an unexpanded Vic-20 the User Basic Area is at $1000 and a Basic program begins at $1001. If we enter the monitor and look at the program:
.M 1001 100F
We'll see
1001 0C 10 DD 07 9E
1006 20 34 31 31 30
100B 00 00 00 00 00
The first two bytes 0C 10
is an address, $100C
, representing the next line of Basic in memory, in this case it points to 00 00
which signifies the end of the program.
The second two bytes DD 07
is the number $07DD
which when converted to decimal is 2013
. So this is the line number of the first line.
We now have the actual contents of the Basic line. It starts with 9E
which is the token for SYS
, followed by 20
which is a space character. Then come four bytes 34 31 31 30
, which are the ASCII characters 4110
. The line is terminated by the octet 00
.
Finally the end of the program is marked by 00 00
.
Hiding the SYS Statement With a Message
When you load many programs and do a LIST
, all you see is a message such as:
(C) 2013 LORRY WOODMAN
This is done by following the SYS
statement with a REM
containing backspace characters, which would look like:
* = $1001
.word basicEnd ; Next Line link, here end of BASIC program
.word 1 ; The line number for the SYS statement
.byt $9e ; SYS token
.asc " "
.asc "4150" ; Start of machine language
.byt $3a ; colon symbol token
.byt $8f ; REM token
.asc " "
.dsb 15,$14 ; Backspace characters to make line invisible
.asc "(C) 2013 LORRY WOODMAN"
.byt 0 ; End of Basic line
basicEnd .word 0 ; End of Basic program
To calculate the start of machine language add the number of bytes in the message to 4128
. In the example above the message is 22
bytes long, hence the start of the machine language code is at 4150
.
More Complex Basic Stubs
For more complex Basic stubs, rather than working out each byte of the stub by hand, I would recommend creating the Basic program that you want, and then examining it with a machine language monitor. This way you can easily see what is happening and then just copy the memory dump when you are happy with the program.
Some values will be unknown to you when you write the Basic program, so just put in a dummy value with the right number of characters and use the monitor to work out what the correct value should be. A good example of this is working out where a SYS
statement should point to. I would enter 8888
, then look in the monitor for 38 38 38 38
and change those values to the next memory location after the end of the Basic program as indicated in the monitor.
Other Memory Configurations
There are three main memory configurations that you have to be aware of with the Vic: unexpanded, 3Kb memory expansion and 8Kb or more memory expansion. The following table translates the main values used above to the correct value for each configuration:
Unexpanded | 3Kb | 8Kb+ |
---|---|---|
4097 / $1001 | 1025 / $401 | 4609 / $1201 |
4110 | 1038 | 4622 |
4128 | 1056 | 4640 |
4150 | 1078 | 4662 |
So the first Basic stub would look like the following for a 3Kb configuration:
; 2013 SYS 1038
* = $401
.word basicEnd ; Next Line link, here end of Basic program
.word 2013 ; The line number for the SYS statement
.byt $9e ; SYS token
.asc " "
.asc "1038" ; Start of machine language
.byt 0 ; End of Basic line
basicEnd .word 0 ; End of Basic program
And for an 8Kb+ configuration:
; 2013 SYS 4622
* = $1201
.word basicEnd ; Next Line link, here end of Basic program
.word 2013 ; The line number for the SYS statement
.byt $9e ; SYS token
.asc " "
.asc "4622" ; Start of machine language
.byt 0 ; End of Basic line
basicEnd .word 0 ; End of Basic program
Putting it All Together
To finish, here is a complete program including a Basic stub, which has been added to the "Hello, World!" example from: Beginning Assembly Programming on the Commodore Vic-20.
CHROUT = $ffd2
* = $1001
.word basicEnd ; Next Line link, here end of Basic program
.word 2013 ; The line number for the SYS statement
.byt $9e ; SYS token
.asc " "
.asc "4110" ; Start of machine language
.byt 0 ; End of Basic line
basicEnd .word 0 ; End of Basic program
ldx #$00
loop lda message, x
beq finished
jsr CHROUT
inx
bne loop
finished rts
message .asc "HELLO, WORLD!" : .byt 0