Where will my program be loaded? How can I control that?

Basic and Machine Language

Moderator: Moderators

charles92027
Vic 20 Newbie
Posts: 8
Joined: Tue Jun 14, 2022 12:57 pm
Location: California
Occupation: software engineer

Where will my program be loaded? How can I control that?

Post 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

User avatar
bjonte
Vic 20 Hobbyist
Posts: 110
Joined: Sun Jan 22, 2017 5:47 am
Location: Gothenburg

Re: Where will my program be loaded? How can I control that?

Post 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.
User avatar
bjonte
Vic 20 Hobbyist
Posts: 110
Joined: Sun Jan 22, 2017 5:47 am
Location: Gothenburg

Re: Where will my program be loaded? How can I control that?

Post 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.
User avatar
bjonte
Vic 20 Hobbyist
Posts: 110
Joined: Sun Jan 22, 2017 5:47 am
Location: Gothenburg

Re: Where will my program be loaded? How can I control that?

Post 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...>
charles92027
Vic 20 Newbie
Posts: 8
Joined: Tue Jun 14, 2022 12:57 pm
Location: California
Occupation: software engineer

Re: Where will my program be loaded? How can I control that?

Post 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?
charles92027
Vic 20 Newbie
Posts: 8
Joined: Tue Jun 14, 2022 12:57 pm
Location: California
Occupation: software engineer

Re: Where will my program be loaded? How can I control that?

Post 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!
charles92027
Vic 20 Newbie
Posts: 8
Joined: Tue Jun 14, 2022 12:57 pm
Location: California
Occupation: software engineer

Re: Where will my program be loaded? How can I control that?

Post 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.
User avatar
chysn
Vic 20 Scientist
Posts: 1205
Joined: Tue Oct 22, 2019 12:36 pm
Website: http://www.beigemaze.com
Location: Michigan, USA
Occupation: Software Dev Manager

Re: Where will my program be loaded? How can I control that?

Post 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.
VIC-20 Projects: wAx Assembler, TRBo: Turtle RescueBot, Helix Colony, Sub Med, Trolley Problem, Dungeon of Dance, ZEPTOPOLIS, MIDI KERNAL, The Archivist, Ed for Prophet-5

WIP: MIDIcast BASIC extension

he/him/his
charles92027
Vic 20 Newbie
Posts: 8
Joined: Tue Jun 14, 2022 12:57 pm
Location: California
Occupation: software engineer

Re: Where will my program be loaded? How can I control that?

Post 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!
User avatar
Mike
Herr VC
Posts: 4841
Joined: Wed Dec 01, 2004 1:57 pm
Location: Munich, Germany
Occupation: electrical engineer

Re: Where will my program be loaded? How can I control that?

Post 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.
User avatar
bjonte
Vic 20 Hobbyist
Posts: 110
Joined: Sun Jan 22, 2017 5:47 am
Location: Gothenburg

Re: Where will my program be loaded? How can I control that?

Post 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. :)
User avatar
Mike
Herr VC
Posts: 4841
Joined: Wed Dec 01, 2004 1:57 pm
Location: Munich, Germany
Occupation: electrical engineer

Re: Where will my program be loaded? How can I control that?

Post 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.
User avatar
bjonte
Vic 20 Hobbyist
Posts: 110
Joined: Sun Jan 22, 2017 5:47 am
Location: Gothenburg

Re: Where will my program be loaded? How can I control that?

Post 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).
groepaz
Vic 20 Scientist
Posts: 1187
Joined: Wed Aug 25, 2010 5:30 pm

Re: Where will my program be loaded? How can I control that?

Post 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)
I'm just a Software Guy who has no Idea how the Hardware works. Don't listen to me.
User avatar
bjonte
Vic 20 Hobbyist
Posts: 110
Joined: Sun Jan 22, 2017 5:47 am
Location: Gothenburg

Re: Where will my program be loaded? How can I control that?

Post 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).
Post Reply