Problems with MAC and EMAC macros in ColdFire V1+

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

Problems with MAC and EMAC macros in ColdFire V1+

Jump to solution
1,784 Views
javiercambra
Contributor II

Hello,

 

I am using the library CFLMOPM in order to implement some DSP functions in a ColdFire V1+ processor.

 

Software for the Library of Macros for Optimization Using eMAC and MAC Programmer's Manual

 

http://cache.freescale.com/files/32bit/doc/ref_manual/CFLMOPM.pdf?fsrch=1&sr=1

 

When using the CONV macro I get a CPU exception (illegal address). I am wondering if somebody has used this library for DSP in ColdFire V1+. I just using the simple example we can find in the documentation of this library.

 

Does anybody had this kind of problems?

 

I attached the project.

 

Thanks,

Javier

 

/* User includes (#include below this line is not maintained by Processor Expert) */

#include "emac_macro.h"

 

#define X_SIZE 20

#define H_SIZE 10

FRAC32 f32_y[X_SIZE+H_SIZE-1];

 

FRAC32 f32_x[X_SIZE] = {

D_TO_F32(0), D_TO_F32(0.309016994374947),

D_TO_F32(0.587785252292473), D_TO_F32(0.809016994374947),

D_TO_F32(0.951056516295154), D_TO_F32(0.99999),

D_TO_F32(0.951056516295154), D_TO_F32(0.809016994374947),

D_TO_F32(0.587785252292473), D_TO_F32(0.309016994374948),

D_TO_F32(1.22514845490862E-16), D_TO_F32(-0.309016994374948),

D_TO_F32(-0.587785252292473), D_TO_F32(-0.809016994374947),

D_TO_F32(-0.951056516295154), D_TO_F32(-1),

D_TO_F32(-0.951056516295154), D_TO_F32(-0.809016994374948),

D_TO_F32(-0.587785252292473), D_TO_F32(-0.309016994374948) };

 

FRAC32 f32_h[H_SIZE] = {

D_TO_F32(.1), D_TO_F32(.2), D_TO_F32(.3), D_TO_F32(.4),

D_TO_F32(.5), D_TO_F32(.6), D_TO_F32(.7), D_TO_F32(.8),

D_TO_F32(.9), D_TO_F32(.99) };

 

void main(void)

{

  /* Write your local variable definition here */

 

 

  /*** Processor Expert internal initialization. DON'T REMOVE THIS CODE!!! ***/

  PE_low_level_init();

  /*** End of Processor Expert internal initialization.                    ***/

 

  /* Write your code here */

  /* For example: for(;;) { } */

  CONV(f32_y, f32_x, f32_h, X_SIZE, H_SIZE);

  /*** Don't write any code pass this line, or it will be deleted during code generation. ***/

  /*** Processor Expert end of main routine. DON'T MODIFY THIS CODE!!! ***/

  for(;;){}

  /*** Processor Expert end of main routine. DON'T WRITE CODE BELOW!!! ***/

} /*** End of main routine. DO NOT MODIFY THIS TEXT!!! ***/

 

Original Attachment has been moved to: CONV_1.zip

Labels (1)
0 Kudos
1 Solution
1,067 Views
TomE
Specialist II

> I think the problem is in the instruction: move.l d7,(a4)+,

>...

> Step 5. move.l d7,(a4)+

> Step 6. subq.l #1,d1

>A4 0x1

That would certainly do it Step 5 is storing D7 to what A4 was pointing to before it was incremented (by 4).


Which was (1-4) or -3 or 0xfffffffd.


Register 4 has been loaded with a doubly-bad value. It is both ODD (which indicates a bug) and it isn't inside your memory space. It is also possible it was a good value a long time ago, but the loop counter was loaded with a huge value and it has been looping long enough to increment a4 up to that value (but it must have been odd to start with).


> This function code is written in conv.h file.

It would help if you said which one - there are two, one for "mac" and one for "emac". I'm going to have to pattern-match to work this out. It matches the emac one:

I'm now trying to paste the code from conv.h into here, but since this forum software is STILL BROKEN AFTER MONTHS AND MONTHS I can't paste a few lines in without it going crazy, so I have to manually past in one line at a time. Get cut-and-paste working guys!

#define CONV(y, x, h, xsize, hsize)

...

FRAC32 *yci = (y);

...

move.l  yci, a4

So register a4 is being loaded from "yci" and that is coming from "y", so what is "y" being passed in as?


Follow that path back. Remember "y" is meant to be a pointer. You may need to ask the compiler to run the preprocessor pass (that's "gcc -E" for me, don't know how to get CW to do this) and see what the macro is being turned into.


Tom


View solution in original post

0 Kudos
8 Replies
1,067 Views
TomE
Specialist II

It would help if you said which CPU you're using.

By "V1+" I assume you mean MCF51Jx as long as it isn't the JE or JM, so JF, JG or JU. Or one of the Q ones.

I note the CFLMOPM package is on the Product Page, so it should work on these chips:

MCF51Jx Product Summary Page

So it shouldn't be the problem of the Reference Manuals not mentioning that the CPU is missing instructions like DIV:

Re: no division instruction on V1's

Except that the MCF51JF128 Refence Manual says it has a V1 core and not a V1+ core.

I'd suggest you single-step the assembly and examine the instruction it is executing when it crahses and the register contents.

Read the Reference Manual description for an Address Error. It usually means a jump to an odd address, which is usually a subroutine return with a corrupted stack. There are also illegal assembly instruction formats, but they shouldn't be getting generated.

Tom

1,067 Views
javiercambra
Contributor II

Hi again,

You were right. The problem is in a jump instruction:

bne *-28

I don't understand this instruction, I have checked the ColdFire programmer Manual but I've not seen this nomenclature: branch not equal with "asterisk minus mumber"...

The CPU is throwing the exception Cpu_Vaccerr

Is this giving you an idea of what could be happening?

Thanks for your help

Javier

0 Kudos
1,067 Views
TomE
Specialist II

MCF51QM128 is listed as "V1 ColdFire core with EMAC and DIV", so you won't have that problem.

> MCF51QM device is not in the supported devices list.


That may be your problem. It may be something as simple as the library being configured for a different chip that has a different RAM size or something. The Library may be older than the chip (released before the chip was). I'd say you're on your own here and will have to understand EVERYTHING about the library and the chip if you're to get it working properly.


> bne *-28

I'm guessing that you're seeing this listed in a debugger of some sort. So it is that software's opinion of what it thinks the instruction is. The only way to REALLY be sure of what the instruction is is to decode the binary value of the instruction.

I'm guessing it is a PC-relative branch going back 28 bytes. That's legal, even and shouldn't be causing the problem, as long as it is still in the FLASH address space. What is the Program Counter? Get the compiler to give you a listing with assembly code (you need to find out how to get your compiler to do this as I'm using gcc here) and read the source and assembly and locate the instruction sequence from the program counter.

From CFPRM.pdf, "bcc" is "0110 <condition> <displacement> so I'd expect "0110 0110" and then the displacement, which being "-28" should be "ffe4" so the instruction should be "0x66FFe4" plus or minus 2.

> The CPU is throwing the exception Cpu_Vaccerr

Again that's the debugger's opinion. I read it as the ACCESS error and not the ADDRESS error as you said in your original post. Access is Vector 2. Address is Vector 3. Which one is it?

Examine the "Format/Vector Word" on the stack frame (CFPRM 11.1.2). The FS field should help explain what went wrong. Table 11.2 also lists the possible causes. The Vector field will say whether it is an ADDRESS or ACCESS error.

Note that Section 11.1 states "In some exception types, the program counter (PC) in the exception stack frame contains

the address of the faulting instruction (fault); in others, the PC contains the next instruction to be executed (next).". So it might be the instruction before the branch that caused the exception, but from the table it should be the faulted instruction - but the faulted address should be on the stack UNLESS the debugger is trying to help you and is showing you something else.

"11.3.3.2 Address Error Exception" in the Reference Manual warns the CPU will overwrite/clobber the faulting address in the case of an Address Error during an RTS, so that makes things hard if it happens.

"11.3.3.1 Access Error Exception" details what you're probably getting. In spite of Table 11-14 in the RM stating the PC is at the Fault address, this section says the exception is "imprecise" for writes so the PC may be of later instructions to the one that failed.

Have fun!

Tom

1,067 Views
javiercambra
Contributor II

Hi Tom,

Thank you for your detailed explanation, that help me to understand much better what is happening.


>I'm guessing it is a PC-relative branch going back 28 bytes. That's legal, even and shouldn't be causing the problem, as long as it is still in the FLASH address space. What is the Program Counter? Get the compiler to give you a listing with assembly code (you need to find out how to get your compiler to do this as I'm using gcc here) and read the source and assembly and locate the instruction sequence from the program counter

This function code is written in conv.h file. It's an assembler code inside a macro in C.

In the debugger dissasemby view the code appear as:

000009e8:   bne.s main+0x8 (0x9cc)        ; 0x000009cc

So It's a jump to 28 bytes before as you said.

>The CPU is throwing the exception Cpu_Vaccerr

>Again that's the debugger's opinion. I read it as the ACCESS error and not the ADDRESS error as you said in your original post. Access is Vector 2. Address is Vector 3. Which one is it?

It's an ACCESS error. In my first post i was seeing that register RCM_SRS0, bit [3:3] said illegal address, but after that I enabled the cpu interrupts and then I saw that was Cpu_Vaccerr.

>Examine the "Format/Vector Word" on the stack frame (CFPRM 11.1.2). The FS field should help explain what went wrong. Table 11.2 also lists the possible causes. The Vector field will say whether it is an ADDRESS or ACCESS error.

I have been seen everything you said me, but I am not identified the problem. When the exeption, the content of A7 is 0x80108C.

According to Figures 11.1 and 11.2,

FS= 0x0000 : Not an access or address error nor an interrupted debug service routine. So this is confusing me...

I think the problem is in the instruction: move.l d7,(a4)+,

I inserted several nops after this instruction, and seems that the exception happens in the 3rd pipeline stage.

Here you can find the sequence of instructions and the registers trace, maybe you can have an idea of what is happening. This are the instructions involved in the problem (arrow correspond to step 1):

000009d4:   adda.l d2,a3

000009d6:   move.l (a1)+,d4

000009d8:   move.l -(a3),d5

--> 000009da:   dc.w 0xaa04

000009dc:   btst #22914,d0

000009e0:   bne.s main+0x8 (0x9d6)        ; 0x000009d6

000009e2:   dc.w 0xa1c7

000009e4:   move.l d7,(a4)+

000009e6:   subq.l #1,d1

000009e8:   bne.s main+0x8 (0x9cc)        ; 0x000009cc

I write only the changing registers.

Step 1.  000009da:   dc.w 0xaa04

A3 0x0

A7 0x801094

PC 0x9da

SR 0x2000

Step 2. btst #22914,d0

PC 0x9de

Step 3. bne.s main+0x8 (0x9d6)        ; 0x000009d6

D2 0x0

PC 0x9e0

SR 0x2004

Step 4. dc.w 0xa1c7

PC 0x9e2

Step 5. move.l d7,(a4)+

PC 0x9e4

Step 6. subq.l #1,d1

A4 0x1

PC 0x9e6

SR 0x2000

Step 7 (Exception!) bne.s main+0x8 (0x9cc)        ; 0x000009cc

A7 0x80108C

PC 0x414

Thank you very much!

0 Kudos
1,068 Views
TomE
Specialist II

> I think the problem is in the instruction: move.l d7,(a4)+,

>...

> Step 5. move.l d7,(a4)+

> Step 6. subq.l #1,d1

>A4 0x1

That would certainly do it Step 5 is storing D7 to what A4 was pointing to before it was incremented (by 4).


Which was (1-4) or -3 or 0xfffffffd.


Register 4 has been loaded with a doubly-bad value. It is both ODD (which indicates a bug) and it isn't inside your memory space. It is also possible it was a good value a long time ago, but the loop counter was loaded with a huge value and it has been looping long enough to increment a4 up to that value (but it must have been odd to start with).


> This function code is written in conv.h file.

It would help if you said which one - there are two, one for "mac" and one for "emac". I'm going to have to pattern-match to work this out. It matches the emac one:

I'm now trying to paste the code from conv.h into here, but since this forum software is STILL BROKEN AFTER MONTHS AND MONTHS I can't paste a few lines in without it going crazy, so I have to manually past in one line at a time. Get cut-and-paste working guys!

#define CONV(y, x, h, xsize, hsize)

...

FRAC32 *yci = (y);

...

move.l  yci, a4

So register a4 is being loaded from "yci" and that is coming from "y", so what is "y" being passed in as?


Follow that path back. Remember "y" is meant to be a pointer. You may need to ask the compiler to run the preprocessor pass (that's "gcc -E" for me, don't know how to get CW to do this) and see what the macro is being turned into.


Tom


0 Kudos
1,067 Views
javiercambra
Contributor II

Hi Tom,

>Follow that path back. Remember "y" is meant to be a pointer. You may need to ask the compiler to run the preprocessor pass (that's "gcc -E" for me, don't know how to get CW to do this) and see what the macro is being turned into.

I already fixed the problems. It was an issue with the pointers and the configuration of the Compiler as you said.

A4 was pointing to a bad address: 0xFFFFFFFD

For some reason, the registers were storing bad values. Even after doing some changes, declaring new pointers in c and getting correct pointer values, in the execution of the first stack instructions the values were lost.


LEA -60(a7), a7

MOVEM.L D0-D7/A0-A5, (A7)


I Enabled the following options in the compiler.


CodeWarrior 10.2

C/C++ --> Build/Settings --> ColdFire Compiler --> Processor

Code Model: Far (32 bits)

A6 Stack Frames

Register Coloring

Instruction Sheduling

Peephole


You can find attached a library which implements a FIR filter using the eMAC. I hope would be usefull for someone. Is working with ColdFire V1+ MCF51QM128VLH.

Thanks Tom,

Javi






0 Kudos
1,067 Views
TomE
Specialist II

> For some reason, the registers were storing bad values.

The reason being one that gets a lot of people using CodeWarrior. I don't use it, but I think they changed the ABI in the middle of the CW7 series. That changed what parameters were pushed onto the stack during function calls, and that broke all previous assembly code that the users had written and that Freescale had written. They haven't updated their sample code, so most of the supplied code just won't work any more. Here;s one of may previous forum posts:

Coldfire register ABI documentation

Rather than changing compiler options you'd be better off with the right "declspecs" on the declarations of those assembly functions. Then the rest of your code will work with "new-style" assembly.

Tom

0 Kudos
1,067 Views
javiercambra
Contributor II

Hello Tom, thanks for your response.

I am using the MCF51QM128VLH. In the page product of MCF51Qx is available the library CFDSPLIB: rather than  CFLMOPM, but the MCF51QM device is not in the supported devices list.


I am wondering if this device is compatible or does not appear because the information in the web page is not actualized...

Javier

0 Kudos