Subroutine parameters

Programming the 6502 microprocessor and its relatives in assembly and other languages.
User avatar
Arlet
Posts: 2353
Joined: 16 Nov 2010
Location: Gouda, The Netherlands
Contact:

Re: Subroutine parameters

Post by Arlet »

Downside of mixing code and data is that branches get out of range quicker. For big chunks of data, you could place them somewhere else, and then just use a pointer word after the JSR to get to it.
User avatar
Druzyek
Posts: 367
Joined: 12 May 2014
Contact:

Re: Subroutine parameters

Post by Druzyek »

Could you use a macro to declare all the strings inline for readability but put their actual declaration somewhere else like a compiler does? Something like this:

Code: Select all

Print   .macro msg
        ???
        .endm
        
        Print "Hello!"
        Print "Test"
After expansion:

Code: Select all

        LDA #<str1
        LDX #>str1
        JSR print_sub
        LDA #<str2
        LDX #>str2
        JSR print_sub
        ...
str1:   .DB "Hello!"
str2:   .DB "Test"
User avatar
drogon
Posts: 1671
Joined: 14 Feb 2018
Location: Scotland
Contact:

Re: Subroutine parameters

Post by drogon »

Druzyek wrote:
Could you use a macro to declare all the strings inline for readability but put their actual declaration somewhere else like a compiler does? Something like this:

Code: Select all

Print   .macro msg
        ???
        .endm
        
        Print "Hello!"
        Print "Test"
After expansion:

Code: Select all

        LDA #<str1
        LDX #>str1
        JSR print_sub
        LDA #<str2
        LDX #>str2
        JSR print_sub
        ...
str1:   .DB "Hello!"
str2:   .DB "Test"
Not 100% sure about doing it via a macro, however if using ca65 then you can use separate data and code segments, however it will require writing a suitable config file for it and arranging the loader (or eprom burner) to work out where to put the sections.. So:

Code: Select all

.code
  ldx #>msg1
  ldy #<msg1
  jsr strout

.data 
msg1: .byte "Hello, world",13,10,0
.code ; Back to the code segment
  ... more 6502 program code here
This is almost exactly what happens behind the scenes when using cc65 (and other C compilers on operating systems such as Unix/Linux, etc.) It then becomes the linkers problem to work out how to create a file that the loader can recognise and put the sections into the right place in RAM or ROM.

I've had a look at the macro features of ca65 and I'm not sure it can do that though - however if you were clever with something like m4 (that runs under Unix/Linux, etc.) then it's possible - you effectively divert the generated output (ie. the string data) into a temporary file as part of your PRINT macro, then you need an ending macro that pulls the diverted text into the main document at the end. It should be possible to write a macro that uses the segments though - let me check... I don't think so.

It looks like you can change segments - that's fine, but can't change segments inside a macro - at least not with ca65

This is my test file:

Code: Select all

	strout	= $F000 ; Faking it
.org $1000

;
;	.macro	print string
;	.code
;	ldx	#>:+
;	ldy	#<:+
;	jsr	strout
;	.data
;:
;	.asciiz	string
;	.code
;	.endmacro
;
;
;	print	"Hello, world"
;	print	"Another test"
;
;
	.code
	ldx	#>:+
	ldy	#<:+
	jsr	strout
	.data
:
	.asciiz	"Hello World"

	.code
	ldx	#>:+
	ldy	#<:+
	jsr	strout
	.data
:
	.asciiz	"Another Test"
And the assemble & link commands if you want to test it:

Code: Select all

ca65 -g --cpu 65c02 -l test2.lst test2.s
ld65 -t none -S 0x1000 -vm -m test2.map -o test2 test2.o
the one using the macros gets the output file in the right order, but has the wrong addresses for the ldx & ldy instructions. This may well be a bug in ca65 though.

So have a look at the .lst and .map files and comment out the bottom and un-comment the top to experiment.

.... but before I hit submit, I did a few more tests and it looks like you CAN use the macros, however only if you keep it all relocatable until the link state, so no .ORG in the source file, but keep that -S 0x1000 (or whatever) in the link command.

So using the macros, assembling, linking to $1000 (the data segment follows on), the hex output file looks like:

Code: Select all

000000 a2 10 a0 0e 20 00 f0 a2 10 a0 1b 20 00 f0 48 65  >.... ...... ..He<
000010 6c 6c 6f 2c 20 77 6f 72 6c 64 00 41 6e 6f 74 68  >llo, world.Anoth<
000020 65 72 20 74 65 73 74 00                          >er test.<
Which has the offset for the first string at $100e which looks correct... the map file is somewhat confusing, but the relevant lines are:

Code: Select all

Name                   Start     End    Size  Align
CODE                  001000  00100D  00000E  00001
DATA                  00100E  001027  00001A  00001
Now all you need do is create the right config file for cc65 and a loader that can read the .map file and you're there :-)

Cheers,

-Gordon
--
Gordon Henderson.
See my Ruby 6502 and 65816 SBC projects here: https://projects.drogon.net/ruby/
whartung
Posts: 1004
Joined: 13 Dec 2003

Re: Subroutine parameters

Post by whartung »

Arlet wrote:
Downside of mixing code and data is that branches get out of range quicker. For big chunks of data, you could place them somewhere else, and then just use a pointer word after the JSR to get to it.
Well, depending on the data, the inline method may be a touch more compact as there never needs to be actual code referencing the data, much less loading it in to registers.

Consider:

Code: Select all

    JSR add
    db $1234
    db $4567
in contrast to:

Code: Select all

    LDA #<data
    LDX #>data
    JSR add
    ...
data:
    db $1234
    db $4567
In the first effort, the routine implicitly "knows" where the data is, whereas in the second you need 4 bytes to load up registers and whatnot.
Now, obviously the routine is going to chew up some memory to pull the parameters apart, etc.

But given enough calls, there could be a notable decrease in code size at the cost of some performance (as always...).
White Flame
Posts: 704
Joined: 24 Jul 2012

Re: Subroutine parameters

Post by White Flame »

ca65 macros can absolutely generate segment-hopping output, using .pushseg, .segment "foo", .popseg. I use that heavily in AcheronVM and some older projects to generate data tables and even documentation.
User avatar
drogon
Posts: 1671
Joined: 14 Feb 2018
Location: Scotland
Contact:

Re: Subroutine parameters

Post by drogon »

White Flame wrote:
ca65 macros can absolutely generate segment-hopping output, using .pushseg, .segment "foo", .popseg. I use that heavily in AcheronVM and some older projects to generate data tables and even documentation.
One of those cases where you don't know what you don't know... and despite using ca65 for some time now, completely missed pushseg!

However the one thing I found when playing with the stuff above is that it didn't seem to work when you'd specified a .org in the source file and I'm not sure if this is a bug/feature of ca65 or by design.

But now this is opening up some ideas for me...

Cheers,

-Gordon
--
Gordon Henderson.
See my Ruby 6502 and 65816 SBC projects here: https://projects.drogon.net/ruby/
Post Reply