Coldfire V1+ Inline Assembly (MCF51QM) for EMAC in Codewarrior V10.4

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Coldfire V1+ Inline Assembly (MCF51QM) for EMAC in Codewarrior V10.4

1,366 Views
chbecker
Contributor II

Hi everyone,

 

I´m trying to implement a assembly function which uses the EMAC Unit to multply over 2 32-bit Fields. I`ve started with a marcro described in CFLMOPM (EMAC / MAC Library) but it didnt work out of the box.

So I rewrite this macro to a Statement-level inline assembly according to 34.1.1.4.2 Statement-level in MCU_Coldfire_Compiler.pdf.

 

Unfortunately after calling the function the cpu traps in ISR(Cpu_ivViinstr).

 

My question is: Do I  maybe have to save and restore registers I`ve used in this inline assembly function? And if yes, how can I do this?

 

The original source was:

/* Save registers */\

        lea -60(a7),a7          

       movem.l d0-d7/a0-a5,(a7) 

 

and at the end

 

/* Restore registers */  \

     movem.l (a7),d0-d7/a0-a5 

     lea 60(a7),a7    

 

But I guess this won`t work anymore becaus of the register abi calling convention?!

 

Ive also tried different settings in coldfire compiler - processor -properties but it didnt help

     

 

 

Another question: Do I need the "rts" statement at the end?

 

 

 

Here`s my source code

 

 

void emac_mul (unsigned long * d,    unsigned long * s2,    unsigned long *s1, unsigned long n)

    {

     asm {

         

              /* Initialize MACSR register for unsigned operations */

            move.l #0x40,d0            ;

            move.l d0,MACSR            ;

            moveq.l %16,d0            ;

            /* Load function variables */

            move.l d,a0            ;

            move.l s1,a1            ;

            move.l s2,a2            ;

            move.l n,d1            ;

            /* Load counter */

            move.l d1,d2            ;

            /* Load in d1 number of 4 operations */

            asr.l %2,d1            ;

            beq *+72            ;

            /* Initialize eMAC accumulators */

            move.l #0,ACC0            ;

            move.l #0,ACC1            ;

            move.l #0,ACC2            ;

            move.l #0,ACC3            ;

            /* Perform 4 by 4 operations as MUL */

            movem.l (a1),d7/a3-a5        ;

            add.l d0,a1            ;

            movem.l (a2),d3-d6        ;

            macl.l d7,d3,(a1)+,d7,ACC0    ;

            macl.l a3,d4,(a1)+,a3,ACC1    ;

            macl.l a4,d5,(a1)+,a4,ACC2    ;

            macl.l a5,d6,(a1)+,a5,ACC3    ;

            /* Store results and clear accumulators */

            movclr.l ACC0,d3        ;

            movclr.l ACC1,d4        ;

            movclr.l ACC2,d5        ;

            movclr.l ACC3,d6        ;

            movem.l d3-d6,(a0)        ;

            add.l d0,a2            ;

            add.l d0,a0            ;

            subq.l %1,d1            ;

            bne *-38            ;

            /* Load in d2 number of operations Left */

            and.l %3,d2            ;

            beq *+16            ;

            sub.l d0,a1            ;

            /* Perform last operations as MUL */

            move.l (a6)+,d3            ;

            mulu.l (a1)+,d3            ;

            move.l d3,(a0)+            ;

            subq.l %1,d2            ;

            bne *-10            ;

            rts            ;

          }

    }

 

 

Maybe anyone has an idea or there`s a little hint to get this working.

 

Thanks for help

 

Christian

Labels (1)
0 Kudos
4 Replies

622 Views
JimDon
Senior Contributor III

This for sure works on the MCF51JM

/* Save registers */\

        lea -60(a7),a7         

       movem.l d0-d7/a0-a5,(a7)

and at the end

/* Restore registers */  \

     movem.l (a7),d0-d7/a0-a5

     lea 60(a7),a7 

Regardless of the ABI argument passing. Also, I am seeing the first 3 argument in D0,D1 and D2.

0 Kudos

622 Views
TomE
Specialist II

The original source was:

/* Save registers */\

        lea -60(a7),a7          

       movem.l d0-d7/a0-a5,(a7) 

But I guess this won`t work anymore becaus of the register abi calling convention?!

The "register calling convention" just means that parameters are passed in registers to the function instead of on the stack. Everything else remains the same.


The code you quoted drops the stack pointer by 60 bytes and then saves 14 registers, 56 bytes worth.


The code I'm used to looking at (using gcc) does the following:

static eI2cStatus_t I2cWait(uint32_t a_nDelayUs, volatile uint8_t *a_pReg,

                                                        uint8_t a_nMask, bool a_bSet)

{

40004e50:       4e56 ffe4       linkw %fp,#-28

40004e54:       48d7 0c7c       moveml %d2-%d6/%a2-%a3,%sp@

40004e58:       4282            clrl %d2

40004e5a:       142e 0017       moveb %fp@(23),%d2

The use of the "link" instruction generates chained frame-pointers which is used to access the parameters and local variables, as well as reserving room for saving the registers.

I'd suggest you write a "dummy" function that has some real arithmetic inside it, maybe even a C version of the function you're trying to write. Then disassemble it and see what the compiler generated for the function prologue and epilogue. Then use that as a guide for your assembly.

I think you'd be better off writing "real assembly code" rather than trying to embed it in a C function.

Your real problem is that Freescale don't seem provide a working library CFLMOPM war written and tested with versions 4 and 5 of their compiler, and hasn't been updated to work with the current compilers. The compiler used to support Stack and Register ABIs, but from my reading this isn't possible any more. Are you sure there's no way to get CodeWarrior to support code written for the "Stack ABI"?

Converting the library is a job for an expert ColdFire Assembly programmer. Do you really want to have to learn that to get the job done? You may be better off choosing a chip that comes with the working code you need to get the job done.

Tom

0 Kudos

622 Views
TomE
Specialist II

Someone had a similar problem using that same library with the same chip back in June.

Use the "Search" box in the upper right of this page and search for "EMAC". Follow the links including this one:

https://community.freescale.com/message/335758#335758

I can see your current problem by looking at your code. Yes, you have to save and restore SOME of the registers. You should try to find where CodeWarrior documents their ABI, specifically the Function Calling Convention:

http://en.wikipedia.org/wiki/Application_binary_interface

Calling convention - Wikipedia, the free encyclopedia

Your function is using nearly ALL of the registers without saving any of them. The ABI will document which registers:

1 - Are NOT preserved across function calls and are thus free for use within the function,

2 - ARE preserved across function calls, and thus the function has to save and restore before use,

3 - How parameters are passed into the function (which parameters in which registers and/or on the stack).

4 - How (which register, usually D0) results are returned from the function in.

Note CodeWarrior changed (3) a few years ago, meaning there's a lot of code written "the old way" that won't work on the current system.

> Do I need the "rts" statement at the end?

No, the fact that you're inside a C function means that it will do that for you.

> Unfortunately after calling the function the cpu traps in ISR(Cpu_ivViinstr).

that's not a problem. That's an opportunity. If the debugger is set up properly it should show you what instruction it failed on, and where it was. The fault code on the stack should say more about what went wrong. If it doesn't do that you should be able to simply single-step the code to see where it fails or where it goes off the rails. From there it is usually pretty easy to work out WHY it went off the rails.

Tom

0 Kudos

622 Views
JimDon
Senior Contributor III

You for sure do not need to save and restore D0, as that is the return value. Other register are used to pass in arguments, but that could changed based on settings.

Other than that I would, save and restore all the rest, also MACSR .

     

0 Kudos