Hi Eric!

Thanks, I'll give this a whirl - it may wind up being what I do, but for giggles, I persisted a bit with the idea I outlined in the earlier post, and hit a road bump, which was a bit of a bummer. It's not insurmountable, but it's rather less pretty than the nearly-pure-c it looked like it would be;

In summary, I found that if I declared the structure as const, the compiler would generate a nice block of data, to be loaded at the correct address, and it looked like the solution would be something like this:

struct usb_vectable_entry
{
        uint8_t jmp_insn;
        void (*fn_addr)(void);
        uint8_t zero;
};

#define USBINT_IRQ 8

void sudav_isr(void) __interrupt
{
            P0 = 0x0;
            while(1); // debug LED off and halt
}

void func_2(void) __interrupt
{
}

#define NULL (0)

#define LJMP_OP 0x02
#define NOP_OP 0x00

#define USB_VEC(a) { LJMP_OP, (a), NOP_OP }

__code static struct usb_vectable_entry __at(0x0d00) usb_vectable[32] =
{
        USB_VEC(sudav_isr),
        USB_VEC(func_2),
        ...

}

static const struct usb_vectable_entry __at(0x0043) usb_vector = USB_VEC((void (*)(void))usb_vectable);

which actually works *perfectly* but for one detail.

The function pointers all are stored little-endian, and the CPU's LJMP instructions require a big-endian address. Unfortunately, as the function addresses are not available at compile time, the C preprocessor cannot perform the byteswap, and obviously the linker has no idea that this is desired, so...

Looking closely, it seems like 8051 is a total mess on this topic - some regs are LE, the LJMP encoding is BE, and some regs have the high and low byte separated with other regs in the middle...

I suppose I could have a small 'fixup' function that iterates the array of structs and byteswaps all the pointers (and the usb vector itself), which actually wouldn't be so horrible, and would keep the implementation "pure" C (but for the __at() directive, which could probably be replaced with linker magic at this point, but of course, this still takes up a smidge more space in code space than your solution.

I may give it a try anyway, just because, well, y'know...

It would be really nice if there were a directive (like __xdata et. al.) that caused the compiler to store a particular object in a big-endian format - this would allow my idea to work without any fixup function run prior to enabling interrupts. Perhaps it might look something like this:

struct usb_vectable_entry
{
        uint8_t jmp_insn;
        __be_ptr void (*fn_addr)(void);
        uint8_t zero;
};

Would this be something that a patch to sdcc might be welcome for?

or perhaps a --bigendian-pointers command line option (perhaps this would be too far reaching?). It strikes me that the CPU is essentially 8 bit, so does it really matter what order pointers are stored in RAM? or is this important to some implementations? perhaps they have actual 16 bit LE registers?

What do people think? It'd be really lovely if we could write C code that can fill in the two autovector tables on the cypress FX2 without having to do dirty tricks or resort to assembler...

*muses* I suppose I could write a script to swizzle the bytes in the assembler output from sdcc *slap* :-D

-Ian

On 29/06/2026 11:44, [email protected] wrote:
Hi Ian,

How about:

#include <stdint.h>

extern void USBINT_AUTOVECTORS(void) __interrupt(8) __naked;

int main(void)
{
__asm
   .area HOME (CODE)
   .bndry 256
_USBINT_AUTOVECTORS::
   ljmp _USBINT_SUDAV
   .ds 1
   ljmp _USBINT_SOF
   .ds 1
   ljmp _USBINT_SUTOK
   .ds 1
   ljmp _USBINT_SUSPEND
   .ds 1

   // And so on...

   .area CSEG (CODE)
__endasm;

   while (1)
   {
   }
}

static volatile uint8_t i = 0;

void USBINT_SUDAV(void) __interrupt
{
   i = 0;
}

void USBINT_SOF(void) __interrupt
{
   i = 1;
}

void USBINT_SUTOK(void) __interrupt
{
   i = 2;
}

void USBINT_SUSPEND(void) __interrupt
{
   i = 3;
}

As compiled and linked with SDCC 4.6.0, this seems to give the desired layout 
in code space.

  Eric





________________________________________
From: Ian Molton via Sdcc-user <[email protected]>
Sent: Monday, June 29, 2026 03:21
To: [email protected] <[email protected]>
Cc: Ian Molton <[email protected]>
Subject: Re: [Sdcc-user] Cypress FX2 USB vector "table"


So, I may be either answering my own question, or looking dumb by

missing the obvious "correct" way, but...



This appears to generate correct assembly for the jumptable, at the

desired address. The idea is to construct the LJMP instructions that

should exist for each entry point, as 0x02 is the correct opcode (each

entry is 4 bytes, so the remaining one is left as a 0. Using the __at()

directive an array of structs can be created at a specific (aligned)

location.



I haven't yet tried to generate an interrupt handler - I expect the

compiler to refuse to generate an interrupt function for the USB vector

to occupy the same address as the array - but it should be trivial to

generate the correct LJMP 0x0d00 instruction and copy it to 0x0043.



The documentation for the EZUSB is contradictory on this point - it is

unclear if only the byte at 0x0045 is replaced by the low byte of the

USB autovector function pointer, or if instead the entire 4 bytes of the

autovector are used.





I'll try this out soon - in the meantime, this is my code:





struct usb_vectable_entry

{

          uint8_t jmp_insn;

          void (*fn_ptr)(void);

          uint8_t zero;

};



void func_1(void)

{

}



void func_2(void)

{

}



#define NULL (0)



static struct usb_vectable_entry __at(0x0d00) usb_vectable[32] =

{

          {02, func_1, 00},

          {02, func_2, 00},

          {NULL},



         ...



};





The assembler output by sdcc as part of the .globals setup generates a

table that looks valid at 0xd00 -



          mov     dptr,#_usb_vectable

          mov     a,#0x02

          movx    @dptr,a

          mov     dptr,#(_usb_vectable + 0x0001)

          mov     a,#_func_1

          movx    @dptr,a

          mov     a,#(_func_1 >> 8)

          inc     dptr

          movx    @dptr,a

          mov     dptr,#(_usb_vectable + 0x0003)

          clr     a

          movx    @dptr,a

          mov     dptr,#(_usb_vectable + 0x0004)

          mov     a,#0x02

          movx    @dptr,a

          mov     dptr,#(_usb_vectable + 0x0005)

          mov     a,#_func_2

          movx    @dptr,a

          mov     a,#(_func_2 >> 8)

          inc     dptr

          movx    @dptr,a

          mov     dptr,#(_usb_vectable + 0x0007)

          clr     a

          movx    @dptr,a

          mov     dptr,#(_usb_vectable + 0x0008)

          movx    @dptr,a

      ...





I'm unsure why the compiler has emitted this rather than copying .data

from somewhere else - I assume I'm missing an option on the sdcc

commandline, as this looks quite space inefficient.



Fun and games...



-Ian





On 28/06/2026 19:29, Ian Molton via Sdcc-user wrote:

Hi all,
I've looked through the docs and searched online, but I can't find an
answer to this.
Normal ISRs work just fine for the FX2, but I want to use the USB
autovector functionality. I can't just use a bunch of function
pointers, as the table uses actual jump instructions which the CPU
"reinterprets" to get the destination of the jump.
I've seen several people produce solutions to this that each have
their own problems. The SDCC documentation hints that there is a
solution, but gives no information.
Is there actually a solution, like using __interrupt(), or some nice
way to generate a compatible jump table that can be located in a fixed
position in memory by the linker? I don't like the idea of using an
assembler stub that inherently has to define pretty much every ISR, if
only as a dummy function.
If not, would patches to sdcc be welcome?
-Ian
_______________________________________________
Sdcc-user mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/sdcc-user




_______________________________________________

Sdcc-user mailing list

[email protected]

https://lists.sourceforge.net/lists/listinfo/sdcc-user



_______________________________________________
Sdcc-user mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/sdcc-user

Reply via email to