'call' with page 0 is currently dangerous; how change default call page?

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

'call' with page 0 is currently dangerous; how change default call page?

Jump to solution
1,732 Views
isionous
Contributor III

I am developing for the MC9S12XDT512 and I noticed some call/ppage behavior that seems to be dangerous in some cases.

 

I am using a banked memory model, so almost all functions are called using the 'call' instruction.  Unfortunately, it seems if the 'call' is to a function outside of the banked flash window (0x8000..0xbfff), then codewarrior generates 0x00 as the page operand of the 'call' instruction.  There is no flash page 0x00.  0xe0 is the lowest flash page.  So, if you call a subroutine in unbanked flash, you dangerously have ppage set to 0x00 and the banked flash window is invalid.

 

This is usually not a problem, but if your execution of code gets close to the banked flash window while ppage is 0x00, the PC register changes to a weird address, which means your program is broken.  I have done experiments that confirmed that the problem only occurs when ppage is set to an invalid value and when you are executing code within a few bytes of the flashed bank window.

 

How can I change the behavior of code generation for 'call' instructions so that ppage is never set to 0x00?

 

Thanks.

Labels (1)
Tags (1)
0 Kudos
1 Solution
1,291 Views
kef
Specialist I

You get call's to nonbanked memory because you added nonbanked segments to DEFAULT_ROM. These should be added at the end of DEFAULT_ROM placement list to make linker using nonbanked segments, when there's no space in banked memory. Nonbanked memory should be used first of all for constants and strings, it doesn't make sense to prioritise banked code placement to nonbanked memory.

View solution in original post

0 Kudos
11 Replies
1,291 Views
kef
Specialist I

Any code to demostrate the problem? It is OK to call routine with any PPAGE value, provided routine is allocated in nonbanked memory and routine exits with RTC instruction. I don't know what does mean "code gets close to the banked flash window". Do you mean you have RTC instruction at 0x7FFF, or 0x7FFE, and code breaks approaching to bottom of page window (0x8000)?

0 Kudos
1,291 Views
isionous
Contributor III
#define TRICKY_SPOT 0x7ffc
#define CALL_PAGE   0x00

const unsigned char RTCInstruction @TRICKY_SPOT = 0x0A;

int main() {
    __asm call TRICKY_SPOT,CALL_PAGE
}

 

The PC changes to a weird value if I step the 'call' instruction if TRICKY_SPOT is anywhere from 0x7ffc to 0x7fff (I imagine that 0x8000 would also be problematic) and CALL_PAGE is 0x00.  If CALL_PAGE is 0xFE or TRICKY_SPOT is 0x7ffb (or smaller), I can successfully step the 'call' and 'rtc' instructions.

 

Also, if I preface the 'rtc' instruction with some NOPs, the 'call' can be stepped into fine, but the PC goes whacky when executing NOPs just before 0x8000.

 

Even though execution might never get to 0x8000, I imagine that pipelining or other things happen such that the processor tries to read a bit ahead of the PC.

0 Kudos
1,291 Views
kef
Specialist I

Thanks for sharing these details, it's interesting.

I didn't verify it my self, but I guess that illegal address reset may happen when instruction queue is refilled from nonexisting flash page. The fix should be easy, just edit PRM file to exclude 0x7FFC-0x7FFF from the memory map.

0 Kudos
1,291 Views
leroy_o
Contributor III

Hi,

I have one question, since this issue also happened to me with ROM_4000 non banked flash segment.

I intend, for memory resource reasons, to put code also into ROM_D000 non banked flash segment.

Is the same fix applicable, i.e.: exclude 0xFEFC to 0xFEFF memory region, does anyone know why the last 4 bytes can cause the non existing PPAGE problem? Or is it by experience that those last 4 bytes were determined (and for ROM_D000 it maybe another number of bytes if any)?

Thanks in advance.

0 Kudos
1,291 Views
RadekS
NXP Employee
NXP Employee

No, this “issue” is related only to PPAGE=0x00 and code at address 0x7FFC~0x7FFF.

Why?: S12 CPU using three 16-bit stages in the instruction queue (instruction buffer). If we call function at address 0x7FFC and PPAGE=0x00, CPU will read automatically next 6 bytes (0x7FFC-0x8001). Unfortunately 0x008001 is illegal address and therefore we get illegal address reset.

For details please check chapter 4 Instruction Queue at CPU12/CPU12X Reference Manual:

http://www.freescale.com/files/microcontrollers/doc/ref_manual/S12XCPUV2.pdf

Workarounds:

1. CALL and RTC execute correctly in the normal 64KB address space, however since extra execution cycles are required, routinely substituting CALL/RTC for JSR/RTS is not recommended. For non banked area should be used JSR/BSR functions.

Note: If we want use 0x4000-0x7FFF area, we should disable JSR to BSR optimization by compiler option: “-Onb=b”

2. Remove 0x7FFC ~ 0x7FFF area from valid code memory range. In prm file, for example:

ROM_4000      = READ_ONLY   0x4000 TO   0x7FF0;.

3. Just idea: change default PPAGE by compiler option, for example:”-DefaultPpage0xFE”. Default value of this parameter is 0.


0 Kudos
1,291 Views
isionous
Contributor III

Thank you for the suggested fix.  Do you think the danger of page-zero calls is worthy of a bug report?  As of right now, Codewarrior can produce code that is buggy and can be fixed if they did calls to unpaged flash with a page of 0xFF rather than 0x00.

0 Kudos
1,288 Views
kef
Specialist I

I verified it myself. Yes, it's illegal address access reset. The same hapens if you JSR routine at 0x7FFC, when PPAGE is set to nonexisting  flash page number. ILAF flag becoms set.

 

CALL's to routines in nonbanked flash should not happen normally. Did you do something like that with ISR:

 

#pragma CODE_SEG __NEAR_SEG  NON_BANKED

#pragma TRAP_PROC

void myinterruptroutine(void)

{

}

#pragma CODE_SEG DEFAULT  // <--- did you forget to add this after nonbanked ISR?

 

void myfoo(void) // CALL-RTC function that is allocated in NON_BANKED 

{                              // in the case above pragma is missing

}

 

 

 

If this is not the case, then maybe you edited DEFAULT_ROM placement to include nonbanked flash segment?

 

I don't know what else could cause banked routine to be allocated in nonbanked flash. Maybe memory banker, but I'm not familiar with it. Yes, submit service request for this.

0 Kudos
1,288 Views
isionous
Contributor III

I did not forget to do any "#pragma CODE_SEG DEFAULT" lines. In fact, even with the code below, I get 'call' instructions:

 

#pragma CODE_SEG DEFAULTvoid SomeFunction(void) {    return;}void main(void) {    // compiles to 'CALL SomeFunction,PAGE(SomeFunction)'    SomeFunction();}

 I do have DEFAULT_ROM placement to include banked and nonbanked flash in my Project.prm file:

 

DEFAULT_ROM       INTO  ROM_APP_4000, ROM_APP_C000,                        PAGE_FE, PAGE_FC, PAGE_FB, PAGE_FA, PAGE_F9,                        PAGE_F8, PAGE_F7, PAGE_F6, PAGE_F5, PAGE_F4,                        PAGE_F3, PAGE_F2, PAGE_F1, PAGE_F0, PAGE_EF,                        PAGE_EE, PAGE_ED, PAGE_EC, PAGE_EB, PAGE_EA,                        PAGE_E9, PAGE_E8, PAGE_E7, PAGE_E6, PAGE_E5,                        PAGE_E4, PAGE_E3, PAGE_E2, PAGE_E1, PAGE_E0;

 

0 Kudos
1,292 Views
kef
Specialist I

You get call's to nonbanked memory because you added nonbanked segments to DEFAULT_ROM. These should be added at the end of DEFAULT_ROM placement list to make linker using nonbanked segments, when there's no space in banked memory. Nonbanked memory should be used first of all for constants and strings, it doesn't make sense to prioritise banked code placement to nonbanked memory.

0 Kudos
1,290 Views
isionous
Contributor III

I have now put the unpaged flash regions at the end of the DEFAULT_ROM placement list.  Thank you very much for your help.  As far as I can tell, with my new prm\Project.prm file, the dangerous call behavior will now only happen once all of the paged flash is used for code, which is unlikely.

0 Kudos
1,290 Views
rlw
Contributor I

I would recommend that your DEFAULT_ROM only be placed in  in banked pages, and only put code that needs to be non-banked into non-banked pages:

 

DEFAULT_ROM     INTO    PAGE_FC, PAGE_FB, PAGE_FA, PAGE_F9, PAGE_F8;STARTUP,NON_BANKED,ROM_VAR,COPY                 INTO    PAGE_FD;
0 Kudos