exam if method called from ISR context (S12X)

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

exam if method called from ISR context (S12X)

Jump to solution
1,404 Views
grzegorzK
Contributor III

Hi

 

I have such problem:

I would like to write method (for S12X) what will be exam if is called from ISR or task. let me show example:

 

/**

* Metod return TRUE if called from ISR or FALSE if called from task

*/

extern bool S12X_ISR_context(void);

 

and use:

 

===========

 

void CAN_ISR(void)

{

     bool context = S12X_ISR_context(); //return TRUE due called from ISR!

}

 

===========

void main(void)

{

     bool context = S12X_ISR_context(); //return FALSE due called from main

}

 

===========

 

 

Am I clear enough?

1. Is it possible to implement testing IPL bits in CCR register?

 

I found in datasheet such picture (attached below), but:

2. I do not know details of S12X core so please someone check it if I am going right way..

3. How to read to stack located variable IPL bits?

3081_3081.pngpastedImage_9.png

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

Grzegorz Konopko wrote:

uint8_t S12X_ISR_context(void)

{

  uint8_t volatile CCRW_H;

  __asm(pshcw);

  __asm(movb 1, SP+,CCRW_H);    

  __asm(ins);

  return CCRW_H;

}

CCRW_H is allocated on the stack and compiler probably is unable to track all stack manipulations done in inline asm. Either make CCRW_H static or adjust stack before CCRW_H access, like this:

uint8_t S12X_ISR_context(void)

{

  uint8_t CCRW_H;

 

  __asm(pshcw);

  __asm(movb 2, SP+,CCRW_H);    

  return CCRW_H;

}

Left side MOVB argument is a byte at 0,SP, which is exactly CCRH. It is OK to 2,SP+ to remove both CCRH and CCRL from the stack.

But TFR CCRH,A still is better:

uint8_t S12X_ISR_context(void)

{

  uint8_t CCRW_H;

 

  __asm(TFR CCRH,A);

  __asm(STAA CCRW_H);

  return CCRW_H;

}

View solution in original post

0 Kudos
8 Replies
1,032 Views
RadekS
NXP Employee
NXP Employee

I will start from question 2: Details about S12X core (include instruction set) you can find in S12XCPU reference manual:

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

Ad question 3:

There are few useful assembler instructions:

asm PSHCW;                            //store CCR to stack (include CCRH)

asm PULCW;                            //restore CCR from stack (Include CCRH)

asm EXG CCRH,A;                   // Exchange Register Contents (CCRH<==>A)

asm LDAA #1;                          //load 1 to accumulator A

asm LDAA 0,SP;                      //load last byte from SP to accumulator A

In attachment you can find simple example code for interrupt nesting at S12XE include manipulation with IPL value.

Ad question 1:

Yes, you can...

You can use for example:

asm PSHCW;                            //store CCR to stack (include CCRH)

asm LDAA 0,SP;                      //load last byte from SP to accumulator A

...

Note: Do not forget release SP after using of this code (you can use for example command asm PULCW; or asm LEAS 2,SP;)

I hope that help you.


1,032 Views
kef
Specialist I

You can save few cycles restoring SP like this

   PSHCW

   LDAA   2,SP+

But it is much better to not use stack and transfer CCRH dirtectly using one of these instructions

   TFR CCRH,A

   TFR CCRW,D

   TFR CCRW,X

   TFR CCRW,Y

1,032 Views
grzegorzK
Contributor III

Thank you Edward and Radek. FreeScale support newer fails :smileyhappy:  (like always)

I understand everything, now my only problem is mix Ansi C with assembler of S12X.

Yours example based on manipulation pure assembly and manipulation registers, but I need mix it with Ansi C code.

I did method (quoted below), but it is not working due I manipulate SP without understand.

/**

* Method exam if is called from task context or ISR context

* @return  0 if called from task context

* @return  level of IPL in CCR register, always !0 value what means is ISR

*          context

*/


uint8_t S12X_ISR_context(void)

{

  uint8_t volatile CCRW_H;

 

  __asm(pshcw);

  __asm(movb 1, SP+,CCRW_H);    

  __asm(ins);

  return CCRW_H;

}


Problem is method do not return popped value from stack but value in memory next to. I know problem, but I do not know how to overcome due lack of knowledge.


May someone help me? (Probably better is use movw, CPU reference manual is not easy to fast understand without examples, I was looking examples on forum but without success).

Regards

/Greg


0 Kudos
1,033 Views
kef
Specialist I

Grzegorz Konopko wrote:

uint8_t S12X_ISR_context(void)

{

  uint8_t volatile CCRW_H;

  __asm(pshcw);

  __asm(movb 1, SP+,CCRW_H);    

  __asm(ins);

  return CCRW_H;

}

CCRW_H is allocated on the stack and compiler probably is unable to track all stack manipulations done in inline asm. Either make CCRW_H static or adjust stack before CCRW_H access, like this:

uint8_t S12X_ISR_context(void)

{

  uint8_t CCRW_H;

 

  __asm(pshcw);

  __asm(movb 2, SP+,CCRW_H);    

  return CCRW_H;

}

Left side MOVB argument is a byte at 0,SP, which is exactly CCRH. It is OK to 2,SP+ to remove both CCRH and CCRL from the stack.

But TFR CCRH,A still is better:

uint8_t S12X_ISR_context(void)

{

  uint8_t CCRW_H;

 

  __asm(TFR CCRH,A);

  __asm(STAA CCRW_H);

  return CCRW_H;

}

0 Kudos
1,032 Views
grzegorzK
Contributor III

Thanks all for effort. 3 propositions works great!!!

But I have on question:

Why you prefer operation on register "A" (Accumulator?, whatever) over operation on stack when mixing C and assembly?

From my understand (I was assembly guy long time ago) when do such mixing after assembly instruction we should left all context (all registers, SP etc.) unattached, because C compiler

a) is in charge of all context,

b) do not see assembly modification of registers and assembly insertion should left all registers as before assembly code.

In ours (working) examples:

I.

  __asm(TFR CCRH,A);

  __asm(STAA CCRW_H);


II.


  __asm(tfr ccrh,a); /*copy CCH to A*/

  __asm(anda #0x07); /*mask IPL bits*/

  __asm(staa CCRW_H); /*store A in CCRW_H*/


in both examples above we disturb CPU context due operations on A register.


III.

__asm(pshcw);

  __asm(movb 2, SP+,CCRW_H);  


In example III. context is absolutely unattached, SP back to it's original state.


So that's why I have doubts. Please clear up if possible :smileyhappy:



REGARDS

/Greg

0 Kudos
1,032 Views
kef
Specialist I

Well, it makes sense to keep inline asm preserving all CPU registers, as this should work for every compiler. But I know no C compiler for S12(X), which would assume and expect that uint_8 foo(void) won't touch A register. S12(X) has very few registers, it is not logical to try to keep them all untouched. A,B and concatenated D register are the most used.

For static functions, which are not accessible from other C and asm modules, very smart compiler could analyze static function and detect some not sued register, which would allow compiler to use that free register to keep some data over function call. But your routine is not declared static, and only calling convention defines what registers should be not touched and what registers are used to pass data to and from function. If you look at CW docs, you'll find no requirement to keep any register preserved (except SP of course). So I prefer to use faster version with TFR instruction.

0 Kudos
1,032 Views
grzegorzK
Contributor III

Thank you. Clear.

0 Kudos
1,032 Views
MJW
NXP Employee
NXP Employee

Hello,

Your assembly code plays with SP. This confuses the compiler (CCRW_H is allocated on the stack and

the compiler assumes the address based on the SP before the asm code).

Instead, you can try this:

  __asm(tfr ccrh,a); /*copy CCH to A*/

  __asm(anda #0x07); /*mask IPL bits*/

  __asm(staa CCRW_H); /*store A in CCRW_H*/

Best Regards,

MJW

0 Kudos