Easy banking with SDCC / Newlib

ZX80, ZX 81, ZX Spectrum, TS2068 and other clones
Post Reply
User avatar
jorgegv
Member
Posts: 70
Joined: Wed Nov 18, 2020 5:08 pm

Easy banking with SDCC / Newlib

Post by jorgegv »

Hi guys,

I have been trying the banking support with ZX target, with the following source files:

main.c:

Code: Select all

// zcc +zx -vn --list -s -m --c-code-in-asm -lndos main.c bank6.c -create-app -o banked.bin

#include <stdio.h>

extern int banked_function( void ) __banked;

void main( void ) {
    printf( "Hello world from main bank!\n" );
    printf( "** Value from bank 6: 0x%04x\n", banked_function() );
    while ( 1 ) ;
}
bank6.c:

Code: Select all

#pragma bank 6

int banked_function( void ) __banked {
    return 0x1972;
}
When compiling with the above command line (which selects ZCCZ80 and Classic clib), everything works out of the box, which is great.

But when I try any of the following CFLAGS, it does not work:

Code: Select all

# sccz80, classic - this works
#CFLAGS = --list -s -m --c-code-in-asm -lndos -create-app -o banked.bin

# sccz80, newlib
#CFLAGS = --list -s -m -clib=new --c-code-in-asm -create-app -o banked.bin
# error: Warning: Non-empty UNASSIGNED section ignored -
#  this indicates that some code/data is not part of the memory map

# sdcc, classic
#CFLAGS = --list -s -m -compiler=sdcc --c-code-in-asm -lndos -create-app -o banked.bin
# error: Error: Section  overlaps section CODE by 3751 bytes
# zx: Aborting... one or more binaries overlap
# Building application code failed

# sdcc, newlib - this is the one I'm most interested in
#CFLAGS = --list -s -m -compiler=sdcc -clib=new --c-code-in-asm -create-app -o banked.bin
# (it does not parse stdio.h and gives lots of errors)
So my question: what's the status of no-fuss banking support with SDCC and/or newlib? I'd prefer to use SDCC+newlib for optimization reasons, but the fact that banking is sooooo easy with sccz80 and classic may compel me to migrate to that combination if the other is not available.

Thanks in advance :-)
User avatar
dom
Well known member
Posts: 1554
Joined: Sun Jul 15, 2007 10:01 pm

Re: Easy banking with SDCC / Newlib

Post by dom »

Banked support has only been added to classic, for me it's a much more interesting idea when there's potentially lots of targets to support.

It should however, work with both sccz80 and sdcc in classic: I've just tried examples/banked by changing the CFLAGS_zx_bank line so that it has this:

Code: Select all

CFLAGS_zx_bank = -lndos -compiler=sdcc --legacy-banking
And the banked example appears to work.

Having said that, there's really not much that's needed to add support for it, the classic implementation is here: https://github.com/z88dk/z88dk/blob/mas ... d_call.asm - if you get the names of the sections correct you should just be able to add it to your project: If it does work, let me know and I can add it into the newlib library.

Onto your problems:

Code: Select all

# error: Error: Section  overlaps section CODE by 3751 bytes
# zx: Aborting... one or more binaries overlap
# Building application code failed
I see this a lot when I forget to clear out the residual files from previous compilations - the a_XXXX.bin files - maybe that's happened to you?

Code: Select all

# sdcc, newlib - this is the one I'm most interested in
#CFLAGS = --list -s -m -compiler=sdcc -clib=new --c-code-in-asm -create-app -o banked.bin
# (it does not parse stdio.h and gives lots of errors)
Your options (-compiler=sdcc -clib=new) are using SDCC with the newlib SCCZ80 library - just use -clib=sdcc_ix or -clib=sdcc_iy to switch to using sdcc.
User avatar
jorgegv
Member
Posts: 70
Joined: Wed Nov 18, 2020 5:08 pm

Re: Easy banking with SDCC / Newlib

Post by jorgegv »

dom wrote: Mon Jan 10, 2022 7:54 pm Banked support has only been added to classic, for me it's a much more interesting idea when there's potentially lots of targets to support.

It should however, work with both sccz80 and sdcc in classic: I've just tried examples/banked by changing the CFLAGS_zx_bank line so that it has this:

Code: Select all

CFLAGS_zx_bank = -lndos -compiler=sdcc --legacy-banking
And the banked example appears to work.
It works for me also without the --legacy-banking switch, what's it supposed to do?
dom wrote: Mon Jan 10, 2022 7:54 pm Having said that, there's really not much that's needed to add support for it, the classic implementation is here: https://github.com/z88dk/z88dk/blob/mas ... d_call.asm - if you get the names of the sections correct you should just be able to add it to your project: If it does work, let me know and I can add it into the newlib library.
I'll keep you posted. I have already studied that implementation and know how it works, so I'll try to do it.
dom wrote: Mon Jan 10, 2022 7:54 pm
Onto your problems:

Code: Select all

# error: Error: Section  overlaps section CODE by 3751 bytes
# zx: Aborting... one or more binaries overlap
# Building application code failed
I see this a lot when I forget to clear out the residual files from previous compilations - the a_XXXX.bin files - maybe that's happened to you?
This was it. "make clean" and then compiled fine.
dom wrote: Mon Jan 10, 2022 7:54 pm

Code: Select all

# sdcc, newlib - this is the one I'm most interested in
#CFLAGS = --list -s -m -compiler=sdcc -clib=new --c-code-in-asm -create-app -o banked.bin
# (it does not parse stdio.h and gives lots of errors)
Your options (-compiler=sdcc -clib=new) are using SDCC with the newlib SCCZ80 library - just use -clib=sdcc_ix or -clib=sdcc_iy to switch to using sdcc.
Fine, thanks for the reminder, and also thanks for all your quick help.

Cheers
J.
User avatar
dom
Well known member
Posts: 1554
Joined: Sun Jul 15, 2007 10:01 pm

Re: Easy banking with SDCC / Newlib

Post by dom »

jorgegv wrote: Mon Jan 10, 2022 9:28 pmIt works for me also without the --legacy-banking switch, what's it supposed to do?
SDCC changed the default banking mechanism a while bank so that the function to call is specified in ehl rather than in memory. --legacy-banking switches it back: maybe you've got an older version of sdcc.
User avatar
jorgegv
Member
Posts: 70
Joined: Wed Nov 18, 2020 5:08 pm

Re: Easy banking with SDCC / Newlib

Post by jorgegv »

dom wrote: Tue Jan 11, 2022 6:59 pm
jorgegv wrote: Mon Jan 10, 2022 9:28 pmIt works for me also without the --legacy-banking switch, what's it supposed to do?
SDCC changed the default banking mechanism a while bank so that the function to call is specified in ehl rather than in memory. --legacy-banking switches it back: maybe you've got an older version of sdcc.
Mmmm I have examined the ASM output and indeed it is generating the old "call banked_call" + "defq _my_banked_function" dance. But I usually use some Z88DK version near the nightly (last commit in my Z88DK installation is from october 13th 2021)...

Has this convention changed after that date or before?
User avatar
dom
Well known member
Posts: 1554
Joined: Sun Jul 15, 2007 10:01 pm

Re: Easy banking with SDCC / Newlib

Post by dom »

I get the new calling convention in for example: zcc +zx -a bank1.c -compiler=sdcc -a - the call without parameters uses it. This is using r12555
User avatar
jorgegv
Member
Posts: 70
Joined: Wed Nov 18, 2020 5:08 pm

Re: Easy banking with SDCC / Newlib

Post by jorgegv »

Strange. I just cloned the repo now and rebuilt Z88DK, and I still get the old convention by default. This is my compile line for SDCC + classic (sources are the ones above):

Code: Select all

zcc +zx -vn --list -s -m -compiler=sdcc --c-code-in-asm -lndos -create-app -o banked.bin main.c bank6.c
And examining main.c.lis, I see this:

Code: Select all

   445                          ;main.c:7: void main( void ) {
   446                          ;       ---------------------------------
   447                          ; Function main
   448                          ; ---------------------------------
   449                          _main:
   450                          ;main.c:8: printf( "Hello world from main bank!\n" );
   451   000000 210000                  ld      hl,___str_1
   452   000003 e5                      push    hl
   453   000004 cd0000                  call    _puts
   454   000007 f1                      pop     af
   455                          ;main.c:9: printf( "** Value from bank 6: 0x%04x\n", banked_function() );
   456   000008 cd0000                  call    banked_call
   457   00000b 00000000                defq    _banked_function
   458   00000f 010000                  ld      bc,___str_2+0
   459   000012 e5                      push    hl
   460   000013 c5                      push    bc
   461   000014 cd0000                  call    _printf
   462   000017 f1                      pop     af
   463   000018 f1                      pop     af
   464                          ;main.c:10: while ( 1 ) ;
   465                          l_main_00102:
   466                          ;main.c:11: }
   467   000019 1800                    jr      l_main_00102
...which I believe is the old banking scheme, right?

Last commit in my cloned repo is from today at about 18:30, so it seems I'm pretty much up to date :-)

Edit: If I add "-a" to my compile line, the generated ASM file also has the old convention:

Code: Select all

; Function main
; ---------------------------------
_main:
;main.c:8: printf( "Hello world from main bank!\n" );
        ld      hl,___str_1
        push    hl
        call    _puts
        pop     af
;main.c:9: printf( "** Value from bank 6: 0x%04x\n", banked_function() );
        call    banked_call
        defq    _banked_function
        ld      bc,___str_2+0
        push    hl
        push    bc
        call    _printf
        pop     af
        pop     af
;main.c:10: while ( 1 ) ;
l_main_00102:
;main.c:11: }
        jr      l_main_00102
User avatar
jorgegv
Member
Posts: 70
Joined: Wed Nov 18, 2020 5:08 pm

Re: Easy banking with SDCC / Newlib

Post by jorgegv »

Just a thought: maybe the SDCC version which is downloaded when building Z88DK is not the trunk version? According to this: https://github.com/z88dk/z88dk/issues/1 ... -664559581 the --legacy-banking option was added to SDCC trunk, and the comment date is July 2020...

Maybe you are using a newer SDCC version instead of the Z88DK downloaded one?
User avatar
jorgegv
Member
Posts: 70
Joined: Wed Nov 18, 2020 5:08 pm

Re: Easy banking with SDCC / Newlib

Post by jorgegv »

Also a curiosity: when I run z88dk-zsdcc -h, it shows the --legacy-banking option as available...

What's going on here?
User avatar
jorgegv
Member
Posts: 70
Joined: Wed Nov 18, 2020 5:08 pm

Re: Easy banking with SDCC / Newlib

Post by jorgegv »

More info: I have just downloaded stock SDCC (yesterday's nightly), which appears to be r12871, and compiled main.c to asm with:

Code: Select all

sdcc -mz80 --asm=z80asm -S main.c
The generated assembler output is:

Code: Select all

._main
;main.c:9: printf( "Hello world from main bank!\n" );
	ld	hl, ___str_1
	call	_puts
;main.c:10: printf( "** Value from bank 6: 0x%04x\n", banked_function() );
	ld	e, BANK(_banked_function)
	ld	hl, _banked_function
	call	___sdcc_bcall_ehl
	push	de
	ld	hl, ___str_2
	push	hl
	call	_printf
	pop	af
	pop	af
;main.c:11: while ( 1 ) ;

.l_main00102
	jp	l_main00102
...which indeed uses the new EHL convention.
User avatar
jorgegv
Member
Posts: 70
Joined: Wed Nov 18, 2020 5:08 pm

Re: Easy banking with SDCC / Newlib

Post by jorgegv »

More info: I have patched the Z88DK Makefile to download SDCC r12871 (from yesterday), rebuilt Z88DK with the new SDCC version (patch applied without issues) and rerun my banking test, and surprise, it is generating code using the old convention, but without using --legacy-banking switch.

So it seems something in Z88DK is forcing SDCC to generate old banking code regardless of the --legacy-banking switch being used or not, but the stock SDCC indeed obeys the switch if used.

Any ideas from the experts?
User avatar
dom
Well known member
Posts: 1554
Joined: Sun Jul 15, 2007 10:01 pm

Re: Easy banking with SDCC / Newlib

Post by dom »

I believe I added in some rewrite rules when it looked like there wasn't going to be a compatibility flag: https://github.com/z88dk/z88dk/blob/mas ... opt.1#L598

It captures most of the cases, but unfortunately I didn't catch the tail call. case, so you end up with some horrible Frankenstein code in certain cases:

Code: Select all

extern int func_bank1() __banked;
extern int func_bank3(int value) __banked;

int main() {
        func_bank3(100);
        return func_bank1();
}

% zcc +test -a -compiler=sdcc eg.c

...
_main:
	ld	hl,0x0064
	push	hl
	call	banked_call
	defq	_func_bank3
	pop	af
	ld	e,b_func_bank1
	ld	hl,_func_bank1
	jp  ___sdcc_bcall_ehl
User avatar
jorgegv
Member
Posts: 70
Joined: Wed Nov 18, 2020 5:08 pm

Re: Easy banking with SDCC / Newlib

Post by jorgegv »

Besides not catching the tail call case (easy to fix :-) ), it also looks like you wanted to replace the new banking code with the old one no matter the case: with that rule you always replace the EHL call with the DEFQ one.

Also the target/zx/driver/banking/zx_banked_call.asm implementation seems to be in line with this, since this routine is not prepared for receiving args in EHL, and only works with the DEFQ convention.

So it looks that only legacy banking is supported in Z88DK, right?
User avatar
dom
Well known member
Posts: 1554
Joined: Sun Jul 15, 2007 10:01 pm

Re: Easy banking with SDCC / Newlib

Post by dom »

Yes, I think support for one banked call technique is enough. So with those rules, the flag is no longer needed which is where we started from.

Trampolining for a banked call is never going to be speedy so at the moment I can't see the advantage of the "new way" of doing things, apart from removing the possibility of supporting __z88dk_fastcall __banked functions.
User avatar
jorgegv
Member
Posts: 70
Joined: Wed Nov 18, 2020 5:08 pm

Re: Easy banking with SDCC / Newlib

Post by jorgegv »

Mmm I have taken a look at the SDCC implementation of the trampolines, and the EHL one seems to be quicker, at the very least because of the reduced number of instructions compared to the Z88DK one.

But indeed one implementation seems enough, yes. Thanks for the support, Dom.
Post Reply