Yet another question (PIC18 MPLAB port)

el_es wrote on Thursday, August 14, 2008:

Starting a new thread, because this is generally about the PIC18F MPLAB port.

I admit, my assembly language understanding (of PIC assembler that is) is less than satisfactory - but here is what I spotted :

in FreeRTOS\Source\portable\MPLAB\PIC18F\port.c

in portRESTORE_CONTEXT() macro :

----- line 273
    /* How many return addresses are there on the hardware stack?  Discard   
        the first byte as we are pointing to the next free space. */           
        MOVFF    POSTDEC1, FSR0L                                                   
        MOVFF    POSTDEC1, FSR0L                                                   
    _endasm                                                                       
                                                                               
    /* Fill the hardware stack from our software stack. */                       
    STKPTR = 0;                                                                   
                                                                               
    while( STKPTR < FSR0L )            <<<<< this                                           
    {                                                                           
        _asm               
------- line 284

I understand that the STKPTR is just a counter that can be 0…31.
Whereas the FSR0{L,H} are the lower and higher byte of the pointer.

I suppose the line marked  <<<<< this

should rather read

     while(STKPTR < INDF0)

to have the STKPTR compared with the count of addresses that were saved on stack, and NOT the address it is saved at ?

Am I right or should I learn more PIC18 assembler ? :slight_smile:

rtel wrote on Friday, August 15, 2008:

I think - again from memory - that FSR0L contains the number of items that need pushing onto the hardware stack.

portSAVE_CONTEXT() moves the hardware stack onto the task stack - the number of items that were on the hardware stack is variable so portSAVE_CONTEXT() also pushes the number of items that the hardware stack contained onto the task stack.  When portRESTORE_CONTEXT is called it loads this number from the task stack into FSR0L - then uses this number as a loop counter as it moves the items back from the task stack into the hardware stack - ensuring that the right number of items are restored.

A bit ugly, but this is constrained by how the PIC18 and the C18 compiler both work.

Regards.

el_es wrote on Friday, August 15, 2008:

(Yay, The Author Himself spoke to me :slight_smile: )

So it actually does, you’re right - it is even written in the commentary :slight_smile:

I’m just concerned about the point of using FSR0L to hold the simple counter value.
Any rationale behind this ? Why not simply use the WREG here ? Or some other memory field (not to search too far - the code that pops the task context back:

— line 273
/* How many return addresses are there on the hardware stack?  Discard   
        the first byte as we are pointing to the next free space. */           
+/* Use WREG to hold this value */
-            MOVFF    POSTDEC1, FSR0L                                                   
+              MOVF POSTDEC1                  /* this is one cycle less and one program word less also */

-        MOVFF    POSTDEC1, FSR0L   
+              MOVF POSTDEC1                  /* we have the stack level in the WREG now */

  
   
    _endasm                                                                       
                                                                               
    /* Fill the hardware stack from our software stack. */                       
    STKPTR = 0;                                                                   
                                                                               
-    while( STKPTR < FSR0L )                                                       
+      while(STKPTR < WREG)      /* no idea how would this compile ?*/
+/* might actually need to be asm-coded - but could it have a point being shorter->faster? */

    {
— line 283

rtel wrote on Friday, August 15, 2008:

Provided the value of that register is restored from that task stack after it is used as the counter (if it were before then its value would get clobbered) then I don’t see why not :o)

Regards.

el_es wrote on Friday, August 15, 2008:

Yes,

—  port.c, line 353
        _asm                                                                    
            MOVFF    POSTDEC1, STATUS                                           
            MOVFF    POSTDEC1, WREG                                               
            /* Return without effecting interrupts.  The context may have       
            been saved from a critical region. */                               
            RETURN    0                                                           
        _endasm           
— port.c, line 359

this is the very last register restored in context restore.

So this actually could work :slight_smile: provided, that C18 doesn’t f* up the WREG compiling the while() loop…

(I’m just analyzing the code till now - didn’t try to compile&see yet - if somebody verified that works I’d be glad)

If it does, bad luck then… we’ll need to code the stack restoration in asm fully.
(but hey, this is port code anyway, and port*CONTEXT are macros)

paul_piak wrote on Thursday, October 02, 2008:

The thing is that the restore code inside the while loop is:
            MOVF    POSTDEC1, 0, 0                                               
            MOVWF    TOSU, 0                                                       
            MOVF    POSTDEC1, 0, 0                                               
            MOVWF    TOSH, 0                                                       
            MOVF    POSTDEC1, 0, 0                                               
            MOVWF    TOSL, 0                                                       
thus WREG is compromised by the restore instructions themselves. Therefore "while(STKPTR < WREG)"
will not work.

You might want to suggest to use the following code instead (just like the stack-save code, not using WREG)
            MOVFF    POSTDEC1,TOSU                                               
            MOVFF    POSTDEC1,TOSH                                               
            MOVFF    POSTDEC1,TOSL                                               
but this  is illegal:
Error - file ‘./SERIAL.o’, section ‘.code_SERIAL.o’, TOSU cannot be used as the destination of a MOVFF or MOVSF instruction.

Paul