Page 1 of 2
Where will my program be loaded? How can I control that?
Posted: Tue Jun 14, 2022 4:28 pm
by charles92027
I've the program below. It's my first assembly program for the Vic-20
I'm trying to make it work with all memory configurations. It reads the screen page and saves it to zero page for indirect index addressing. I know it's still using a hard-coded color address, but I haven't worked that out yet.
It has a basic program in the beginning that I'm sure is recognizable. It runs the machine language starting at $100D.
The problem is, depending on the memory configuration, the program loads at different addresses, and doesn't run correctly unless basic memory starts at $1001
Is there any way to compensate for this?
Code: Select all
SCREEN_START = $1E00
COLOR_START = $9600
CHARACTER_ROM = $8000
CHARACTER_RAM = $1C00
SCREEN_PAGE = $288
SCREEN_ADDRESS = $FD
COLOR_ADDRESS = $FB
.org $1001
; BASIC program to boot the machine language code
.byte $0B, $10, $0a, $00, $9e, $34, $31, $30, $39, $00, $00, $00
; store the screen address in zero page, for indirect-indexed addressing
LDA #$00
STA SCREEN_ADDRESS
LDA SCREEN_PAGE
STA SCREEN_ADDRESS + 1
; lower the top of basic programming
LDA #$1C
STA $34
STA $38
;copy 512 bytes from 32768 $8000 to 7168 $1C00
ldx #$00
copyChracters:
LDA CHARACTER_ROM, X
STA CHARACTER_RAM, X
LDA CHARACTER_ROM + 256, X
STA CHARACTER_RAM + 256, X
INX
BNE copyChracters ; incrementing past FF will set it back to zero
LDX #$07
makeSmiley:
LDA smiley, X
STA CHARACTER_RAM, X
DEX
BPL makeSmiley
switchToRamSet;
LDA #$FF
STA $9005
LDY #$3F
writeCharacters:
TYA
STA (SCREEN_ADDRESS), Y
LDA #$00
STA COLOR_START, Y
DEY
BPL writeCharacters
done:
RTS
smiley:
.byte %00111100
.byte %01000010
.byte %10100101
.byte %10000001
.byte %10100101
.byte %10011001
.byte %01000010
.byte %00111100
Re: Where will my program be loaded? How can I control that?
Posted: Tue Jun 14, 2022 10:25 pm
by bjonte
You can make your BASIC line SYS address relative to the BASIC start vector and ensure you have location independent boot code that copies the real program to the correct location before jumping there. This requires some thinking to write location independent code.
You can also make a separate boot file that simply loads the main program to the location it was made to run at and jump there. This is easier and what I would recommend because you can also check for required memory expansions and put user friendly messages on the screen outside the main program.
Re: Where will my program be loaded? How can I control that?
Posted: Tue Jun 14, 2022 10:30 pm
by bjonte
Your program seems to be location independent already so another alternative for now is just to modify the BASIC line to SYS the basic start vector contents plus an offset into your code.
Re: Where will my program be loaded? How can I control that?
Posted: Tue Jun 14, 2022 11:09 pm
by bjonte
I use this macro in my assembler to construct the BASIC line:
Code: Select all
// This basic line works for relocatable BASIC programs.
// The .sys_addr will be called relative to the start of the BASIC program.
macro basic_line_20(.line_number, .sys_addr)
{
.start:
define word = .line2
define word = .line_number
define byte[] = {
// syspeek(43)+256*peek(44)+OFFSET
$9e, $c2, $28, $34, $33, $29, $aa, $32, $35, $36,
$ac, $c2, $28, $34, $34, $29, $aa, string(.sys_addr - .start), $00
}
define word .line2 = 0
}
So I can begin the program like this:
Code: Select all
basic_line_20(2022, start)
start:
<my program...>
Re: Where will my program be loaded? How can I control that?
Posted: Wed Jun 15, 2022 8:07 am
by charles92027
Thank you all for you input.
When you talk about writing a loader, I assume it will pull a binary file from the disk and write it to a specific memory address.
Is this done in a BASIC program, or ML? How do you build this on a disk?
Re: Where will my program be loaded? How can I control that?
Posted: Wed Jun 15, 2022 1:58 pm
by charles92027
I think I have it worked out using the kernel functions to load binary files.
So, build a loader in assembly, with the basic boot strap to start.
Then, that loader will load files into specific memory addresses, into program, graphics and sounds.
I’ll post my findings soon!
Re: Where will my program be loaded? How can I control that?
Posted: Wed Jun 15, 2022 4:30 pm
by charles92027
Until I load a program to a specific place in memory, I still lack a valid pointer to my reserved data. For instance, if I want to load a file, I need to have the filename to load.
I declared the filename following the bootstrap, so I just need to add the filename length to the bootstrap jump, and then I can discover the address of the filename by adding the length of the bootstrap to the start of basic.
The screen writing code is a bit convoluted because I'm trying to address the screen and the filename using the Y index. I won't need to do this for a loader, I'll just need to get the pointer to the filename.
Code: Select all
SCREEN_START = $1E00
COLOR_START = $9600
CHARACTER_ROM = $8000
CHARACTER_RAM = $1C00
SCREEN_PAGE = $288
SCREEN_ADDRESS = $FD
COLOR_ADDRESS = $FB
START_OF_BASIC = $2B
FILENAME_Y = $1C ; 29 bytes past the start of basic
.org $1001
bootstrap:
; BASIC program to bootstrap the machine language code
; 10 sys peek(43) * 256 * peek(44) + 40
.byte $1A, $04, $0A, $00, $9E, $20, $C2, $28
.byte $34, $33, $29, $AC, $32, $35, $36, $AC
.byte $C2, $28, $34, $34, $29, $AA, $34, $30 ; $34, $30 ==> skip 40 bytes, 29 bytes for the bootstrap + 11 bytes for the filename
.byte $00, $00, $00, $00
; declare some data space here.
; This address can be found by adding start of basic, stored at $2B $2C, and adding 29 bytes, the length of the boot strap
filename:
; H E L L O W O R L D
.byte $08, $05, $0C, $0C, $0F, $17, $0F, $12, $0C, $04, $00 ; 11 bytes
start:
; store the screen address in zero page, for indirect-indexed addressing
LDA #$00
STA SCREEN_ADDRESS
STA COLOR_ADDRESS
LDA SCREEN_PAGE
STA SCREEN_ADDRESS + 1
; convert screen address to color address
AND #$03
ORA #$94
STA COLOR_ADDRESS + 1
; prepare to write the filename to screen by getting the first character and preparing the stack
LDY #FILENAME_Y ; Set filename index
TYA
PHA ; Push filename index on stack
LDA (START_OF_BASIC), Y ; Load first character into A
TAX ; Save it in X
LDY #$00 ; Set screen index
TYA
PHA ; Push screen index on stack
writeCharacters:
PLA
TAY ; Pull screen index off stack
TXA ; Put the character back into A
STA (SCREEN_ADDRESS), Y ; write the character to the screen
LDA #$00
STA (COLOR_ADDRESS), Y ; change character to black
INY ; increment the screen index
TYA
TAX ; Save it in X
PLA
TAY ; Pull the filename index off the stack
INY ; increment the filename index Y
TYA
PHA ; Push filename index on stack
TXA
PHA ; Push Screen index on Stack
LDA (START_OF_BASIC), Y ; Load next character
TAX ; Save it in X
BNE writeCharacters ; if it's zero, we're done
PLA
PLA ; clean the stack
done:
RTS
I still need to do some testing, but I think this will work with all the various memory expansion options.
Re: Where will my program be loaded? How can I control that?
Posted: Thu Jun 16, 2022 7:51 am
by chysn
It seems to me that you're working too damn hard.
VIC-20 software is traditionally written for a specific level of expansion (unexpanded, +3K, +8K, etc.), and users add or remove expansion based on program requirements. VIC-20 memory is constrained enough without having to add code to handle more than one configuration; not only screen and color memory, but also foregoing JMP in favor of messier constructs.
I get it as a programming exercise, but in real-world software there's no reason to put yourself through all that.
Re: Where will my program be loaded? How can I control that?
Posted: Thu Jun 16, 2022 12:31 pm
by charles92027
That's a valid point.
When I was a kid all I had was an unexpanded Vic-20, all these options make my head spin!
Re: Where will my program be loaded? How can I control that?
Posted: Sat Jun 18, 2022 10:59 am
by Mike
The peculiarities of the VIC-20's memory organisation set aside, there is a definitive answer to the question in the OP: PRG files consist of a
load address (low-endian, two bytes) followed by the
payload. The payload either gets loaded:
- to that original load address (with a secondary address not equal zero - this is also called 'absolute load'), or
- to another address specified by the application (with a secondary address equal to zero) - with the LOAD command of BASIC, this is the start of BASIC RAM. This is also called 'relative' or 'relocating' load.
Actually, for tape operation it is possible to force a load to the original address, regardless what secondary address was specified. You find more details in the sticky thread '
ROM calls and other tricks'.
...
As nice as bjonte's universal BASIC stub looks on first sight, it does not completely solve the issue: the standard autostart behaviour of VICE does an absolute load - which loads the stub to the load address specified in the file, but not necessarily to the BASIC start as given by the current RAM configuration! Which simply means, the payload is loaded somewhere - but chances are, it does not end up where we want.
Quite some time ago, I had already extended upon this idea of an universal BASIC stub and arrived at an implementation that - with absolute load - loads into OS workspace. In doing so, it:
- diverts an OS vector which then
- forces an autostart of a small machine code routine that in turn
- enforces the unexpanded RAM configuration,
- loads another program intended to run in unexpanded RAM config, and finally
- starts that program.
If this universal BASIC stub is instead loaded by a 'normal', relocating/relative LOAD, it does not autostart, but presents a BASIC stub which is started by RUN. Again, memory is constricted to unexpanded RAM and that next program is chained to. You see this boot loader in action in my
Unexpanded Games Collection. As the name implies, all the games are supposed to run with unexpanded RAM. The boot loader though disables any RAM expansion while chaining to the game menu, so
the user does not need to remove any plugged in RAM cartridge beforehand.
This is the most probable scenario where one would want to handle different RAM configurations. There is no likely reason to load an oversized program executable into an unexpanded VIC-20.
Re: Where will my program be loaded? How can I control that?
Posted: Sat Jun 18, 2022 11:37 pm
by bjonte
It’s a nice feature to support both loading using 0 and 1 as secondary address!
I dislike VICE’s choice to load with secondary address 1 by default. It makes it difficult to make a generic loader for multiplatform programs. Data files that isn’t intended to be loaded to BASIC should have had it’s own type to solve this issue instead of secondary address. But a bit late to change now.

Re: Where will my program be loaded? How can I control that?
Posted: Mon Jun 20, 2022 1:16 pm
by Mike
bjonte wrote:I dislike VICE's choice to load with secondary address 1 by default.
It is a two-sided sword. For one, it eases the load of machine code programs, especially cartridge images (in BLK5). The thing inconsistent about this - one normally never would start that kind of programs with RUN, yet VICE follows up the autostart with "RUN" or "RUN:" + [RETURN]. On the VIC-20, that only gives the expected result and starts the BASIC program, when the RAM configuration has been correctly set before.
MG picture files naturally have a load address of $10F1 (because they are saved from there) but loaded with ",8" and at least +8K RAM, they present a BASIC stub so the picture can be shown with RUN without having to load MINIGRAFIK. Unfortunately, the standard autostart behaviour of VICE thwarts this.
It makes it difficult to make a generic loader for multiplatform programs. Data files that [are not] intended to be loaded to BASIC should have had [their] own type to solve this issue instead of secondary address. [...]
With the boot loader, that issue can be solved right away: you extend the boot sequence with an intermediate program that runs in unexpanded RAM configuration (which it gets guaranteed by the boot loader!), that then checks the presence of the RAM required by the target program. If RAM is there, re-expand the RAM configuration and boot through. If the necessary RAM is not there, say "sorry" and stop.
It just needs one to drop the requirement to have each and everything onefiled. If anyone is concerned about that, a *.d64 disk image with those three files (and BOOT as first one!) still gives a package that serves this purpose of being a single file.
Re: Where will my program be loaded? How can I control that?
Posted: Wed Jun 22, 2022 10:02 am
by bjonte
I agree a small bootloader can solve the problem for all VIC20 configurations. I meant that the problem is still there when the boot loader should be working on PET, C16, +4, C64 or C128 as well. It would have been nice if that was possible, but the ,8,1 thing breaks that. I attempted that and settled for the requirement to load using ,8 (or other device of course).
Re: Where will my program be loaded? How can I control that?
Posted: Wed Jun 22, 2022 11:14 am
by groepaz
dislike VICE’s choice to load with secondary address 1 by default.
It doesnt do that anymore for quite a while now (on VIC20 and PET)
Re: Where will my program be loaded? How can I control that?
Posted: Wed Jun 22, 2022 11:53 pm
by bjonte
groepaz wrote: ↑Wed Jun 22, 2022 11:14 am
dislike VICE’s choice to load with secondary address 1 by default.
It doesnt do that anymore for quite a while now (on VIC20 and PET)
That’s nice! I didn’t notice the VIC20 change because outside development I use the package manager’s default old version. The problems I had most recently was with the Plus/4 (when the loading address was $0801).