Strange compilation error with SDCC

ZX80, ZX 81, ZX Spectrum, TS2068 and other clones
Post Reply
Stefan123
Member
Posts: 85
Joined: Fri Oct 21, 2016 7:57 am

Strange compilation error with SDCC

Post by Stefan123 »

I'm confused by the following compilation error when compiling the test program below with SDCC (it compiles fine with SCCZ80):

"Error at file 'test.c' line 607: integer '162' out of range"

There is no line 607 and no integer with value 162...

Code: Select all

// zcc +zxn -vn -SO3 -startup=31 -clib=sdcc_iy -m --max-allocs-per-node200000 test.c -o test -create-app

#include <stdint.h>
#include <arch/zxn.h>

static void write_mmu(uint8_t mmu, uint8_t page)
{
    switch (mmu)
    {
        case 0:
            ZXN_WRITE_MMU0(page);
            break;
        case 1:
            ZXN_WRITE_MMU1(page);
            break;
        case 2:
            ZXN_WRITE_MMU2(page);
            break;
        case 3:
            ZXN_WRITE_MMU3(page);
            break;
        case 4:
            ZXN_WRITE_MMU4(page);
            break;
        case 5:
            ZXN_WRITE_MMU5(page);
            break;
        case 6:
            ZXN_WRITE_MMU6(page);
            break;
        case 7:
            ZXN_WRITE_MMU7(page);
            break;
        default:
            break;
    }
}

int main(void)
{
    write_mmu(3, 20);

    return 0;
}
User avatar
dom
Well known member
Posts: 1319
Joined: Sun Jul 15, 2007 10:01 pm

Post by dom »

The error is from the assembler I think. I suspect that sdcc has inserted a relative jump, but the macro substitution for ZXN_WRITE_MMU that happens is making the jump too long - a look at the assembler output should prove it.
alvin
Well known member
Posts: 1872
Joined: Mon Jul 16, 2007 7:39 pm

Post by alvin »

Yes dom has it.

There was a recent-ish change to error reporting that adds information about c lines for debuggers in the asm output of the compilers. Only sccz80 has been modified to output this information so right now we have z80asm reporting line numbers corresponding to the asm translation for zsdcc compiles when an error happens in the assembler.

If you translate your .c to asm:
zcc +zxn -vn -a -SO3 -startup=31 -clib=sdcc_iy test.c

You'll see line 607 contains this:

Code: Select all

;; line 607
        jr        C,l_write_mmu_00111
        ld        c,(ix+4)
        ld        b,0x00
        ld        hl,l_write_mmu_00117
        add        hl, bc
        add        hl, bc
        add        hl, bc
        jp        (hl)
l_write_mmu_00117:
        jp        l_write_mmu_00101
        jp        l_write_mmu_00102
        jp        l_write_mmu_00103
        jp        l_write_mmu_00104
        jp        l_write_mmu_00105
        jp        l_write_mmu_00106
        jp        l_write_mmu_00107
        jp        l_write_mmu_00108
l_write_mmu_00101:
        ld        l,(ix+5)
        ld        a,l
        ld        bc,0x243b
        ld        l,0x50+0
        out        (c),l
        inc        b
        out        (c),a
        jr        l_write_mmu_00111
l_write_mmu_00102:
It's a relative jump that has been pushed out of range.

The reason is that these "ZXN_WRITE_MMU0(page);" are being inlined into the code like this:

Code: Select all

        ld        bc,0x243b
        ld        l,0x50+0
        out        (c),l
        inc        b
        out        (c),a
So what was a 3-byte call generated by the compiler has been turned into 8 bytes in post-process inlining.
The inlining is done by copt using this file: https://github.com/z88dk/z88dk/blob/mas ... xn_rules.2

Right now the order of processing is:

zsdcc c->asm translation (here ZXN_WRITE_MMUn() is a "call _ZXN_WRITE_MMUn()")
zsdcc peephole does a JP -> JR substitution when labels are in range.
copt does the post-process inlining which in this case is inserting more code and increasing the jr distance past the max 127 bytes.

At one time there was going to be a special mmu instruction that took 3 bytes so this was safe to do. But now there is no special instruction so we have to move this inlining into zsdcc's peepholer instead.

I'll add an issue for this so it's not forgotten.
alvin
Well known member
Posts: 1872
Joined: Mon Jul 16, 2007 7:39 pm

Post by alvin »

Stefan123
Member
Posts: 85
Joined: Fri Oct 21, 2016 7:57 am

Post by Stefan123 »

First I thought that using, for example, ZXN_WRITE_REG(REG_MMU7, page) instead of ZXN_WRITE_MMU7(page) would be a good workaround in SDCC. However, now I have encountered cases when ZXN_WRITE_REG() exhibits the same compilation issue as ZXN_WRITE_MMU<num>().

The only safe workaround for me right now is to go back and use the good old z80_outp() again.
alvin
Well known member
Posts: 1872
Joined: Mon Jul 16, 2007 7:39 pm

Post by alvin »

Stefan123 wrote:First I thought that using, for example, ZXN_WRITE_REG(REG_MMU7, page) instead of ZXN_WRITE_MMU7(page) would be a good workaround in SDCC. However, now I have encountered cases when ZXN_WRITE_REG() exhibits the same compilation issue as ZXN_WRITE_MMU<num>().
It's all inlined code. The situation will improve a bit when nextreg is allowed but we haven't allowed that yet because it's not yet working 100%.
The only safe workaround for me right now is to go back and use the good old z80_outp() again.
z80_outp() involves a function call. If you want speed you can inline io with port assignments instead.
Post Reply