Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Document RGBLINK's support for SDAS object files #1665

Open
Rangi42 opened this issue Feb 24, 2025 · 9 comments
Open

Document RGBLINK's support for SDAS object files #1665

Rangi42 opened this issue Feb 24, 2025 · 9 comments
Labels
docs This affects the documentation (web-specific issues go to rgbds-www) rgblink This affects RGBLINK
Milestone

Comments

@Rangi42
Copy link
Contributor

Rangi42 commented Feb 24, 2025

RGBDS 0.4.1 added "GBDK support" (aka RGBLINK support for objects output by SDAS) in July 2020, but we've neglected to document it. Update rgblink.1 to not only mention "RGB objects".

Note that #1008 mentions other bullet points for ostensibly complete "C toolchain" usability. I don't know how essential/blocking any of those are to actually using RGBASM+RGBLINK as part of a C+asm multilanguage project.

@Rangi42 Rangi42 added docs This affects the documentation (web-specific issues go to rgbds-www) rgblink This affects RGBLINK labels Feb 24, 2025
@Rangi42 Rangi42 added this to the 0.9.2 milestone Feb 24, 2025
@Rangi42
Copy link
Contributor Author

Rangi42 commented Feb 24, 2025

Give a brief example like this:

# Create a RGB object file with RGBASM
rgbasm -o foo.o foo.asm
# Create a SDAS object file with SDCC
sdcc -c -msm83 -o bar.rel bar.c
# Link both objects together into a ROM with RGBLINK
rgblink -o rom.gb foo.o bar.rel

@SelvinPL
Copy link

SelvinPL commented Feb 24, 2025

examples __sdcccall(1) (which is default in SDCC version > 4.1)

in: 8-bit (a)
return: 8-bit (a)
bar.h

uint_8 increment(uint8_t i);
//{
//	return ++i;
//}

rgbds.asm

_increment:
	inc a
	ret

in: 16-bit (de)
return: 16-bit (bc)
bar.h

uint_16 increment(uint16_t i);
//{
//	return ++i;
//}

foo.asm

_increment:
	inc de
	ld b, d
	ld c, e
	ret

in: 16-bit (de), 8-bit (a)
return: 16-bit (bc)
bar.h

uint_16 add(uint16_t a, int8_t b);
//{
//	return a+b;
//}

foo.asm

_add:
	add a, e
	ld c, a
	ld a, d
	adc a, 0
	ld b, a
	ret

@SelvinPL
Copy link

excerpt from SDCC documentation (4.3.5):


This calling convention can be chosen per function via __sdcccall(1).
8-bit return values are passed in a, 16-bit values in bc, 32-bit values in debc. Larger return values (as well as
struct and union independent of their size) are passed in memory in a location specified by the caller through a
hidden pointer argument.
For functions that have variable arguments: All parameters are passed on the stack. The stack is not adjusted
for the parameters by the callee (thus the caller has to do this instead).

Image

For Functions that do not have variable arguments: the first parameter is passed in a if it has 8 bits. If it has 16
bits it is passed in de. If it has 32 bits, it is passed in debc. If the first parameter is in a, and the second has 8 bits, it
is passed in e; if the first is in bc or debc, and the second has 8 bits, it is passed in a; if the first is passed in a, and
the second has 16 bits, it is passed in bc; if the first is passed in de, and the second has 16 bits, it is passed in bc; all
other parameters are passed on the stack, right-to-left. Independent of their size, struct / union parameters and all
following parameters are always passed on the stack. The stack is adjusted by the callee (thus explicitly specifying
__z88dk_callee does not make a difference), unless the functionhas variable arguments.


@Rangi42
Copy link
Contributor Author

Rangi42 commented Feb 24, 2025

Thanks a lot! Some questions:

  • Do the declarations not need extern?
  • What's the difference between uint_8/uint_16 and uint8_t/uint16_t?

(I should probably get sdcc set up on my machine and try these out before adding them in docs.)

@SelvinPL
Copy link

SelvinPL commented Feb 24, 2025

also for better sdcc code you may add __preserves_regs() directive:

so for our example: uint_8 increment(uint8_t i);

uint_8 increment(uint8_t i)  __preserves_regs(b, c, d, e, h, l);

so caller will not generate push on those register if it may need after return from function call

@SelvinPL
Copy link

SelvinPL commented Feb 24, 2025

  • Do the declarations not need extern?

AFAIK C doesn't require extern for function

  • What's the difference between uint_8/uint_16 and uint8_t/uint16_t?

I think typo is the difference :D

@SelvinPL
Copy link

SelvinPL commented Feb 24, 2025

variable defined in asm

bar.c (https://godbolt.org/z/481n9sqnd)

extern uint8_t counter;
void main(void)
{
  counter++;
}

foo.asm

section "counters", WRAM0
_counter::
  ds 1

variable in HRAM

bar.c (https://godbolt.org/z/njnvff7Mq)

extern __sfr counter;
void main(void)
{
  counter++;
}

foo.asm

section "HRAM counters", HRAM
_counter::
  ds 1

@Rangi42
Copy link
Contributor Author

Rangi42 commented Feb 24, 2025

Very cool. I think rgblink(1) should have one basic/minimal "yes this works" example, and these can go elsewhere. Maybe a gbdev.io page. Maybe a new rgbsdcc(5) man page. Maybe an example GitHub repo (but then something ought to link to it).

@avivace
Copy link
Member

avivace commented Feb 26, 2025

@Rangi42 I'd say this should stay in the rgbds.gbdev.io man pages? I like the rgbsdcc(5) man page option

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
docs This affects the documentation (web-specific issues go to rgbds-www) rgblink This affects RGBLINK
Projects
None yet
Development

No branches or pull requests

3 participants