News:

PROTON pic BASIC Compilers for PIC, PIC24, dsPIC33

Main Menu

PROCEDURE: How to Return an error variable

Started by AlbertoFS, Jun 30, 2023, 02:04 PM

Previous topic - Next topic

AlbertoFS

Several times I have had to perform a special Procedure whose return variable does not change when there is an error within the Procedure. As an example we could choose the "LooKUp & LookDown" commands of the Positron Compiler. See the manual.

Normally the variable Result = 0 (or another value) is defined as the initial value within the procedure. But this value could be a valid response of the procedure. In this case it could take a few hours before encountering this error.

A better system would be that the return variable does not change when there is an error inside the procedure, notifying it with a special command "ExitProcNull" (for example).

Compiler output of a normal Procedure:
    Lfsr 0,TableNumbers
    Movff Index,PRODL
    Rcall LookUpRAM1
    Movff PRODH,LookUpDownReturn
It is seen that the return variable is always modified, with and without error within the Procedure.

With an error as a response, I'd like to get the following to make it very efficient.
    Lfsr 0,TableNumbers
    Movff Index,PRODL
    Rcall LookUpRAM1
With no error as a response, the response would be the usual.
    Lfsr 0,TableNumbers
    Movff Index,PRODL
    Rcall LookUpRAM1
    Movff PRODH,LookUpDownReturn
At the moment the Procedure does not allow this function.
But there is a trick that allows you to perform a reentry of the return variable. And it works great but the exit code is written 2 times. It is less efficient.
    Lfsr 0,TableNumbers
    Movff Index,PRODL
    Movff LookUpDownReturn,PRODH
    Rcall LookUpRAM1
    Movff PRODH,LookUpDownReturn
Making a Macro assembler, you can get something the closest to the ideal. A flag is placed that allows the annoying line to be skipped!
    Lfsr 0,TableNumbers
    Movff Index,PRODL
    Rcall mLookUpRAM2_Sub
    Btfsc _B__VR1,0
    Movff INDF1,Return_Var
Next, we will see how these functions are performed.

EXAMPLE 1:
Perform a Procedure that might give a response similar to the "LookUp" command for RAM. The procedure will be called: LookUpRAM1().
This Procedure performs a search for a value within an array with an input value (Index).
    Dim TableNumbers[11] As Byte = 10,20,30,40,50,60,70,80,90,100,0

    LookUpDownReturn = LookUpRAM1(TableNumbers,Index,LookUpDownReturn)
Then it is checked externally if the return value has been changed. A value that is not in the array is chosen as control value (255).
    Index = 9
    LookUpDownReturn = 255                  '/ Load a value to control the Procedure.

    HRSOut "Index : ",Dec Index,CR 

    LookUpDownReturn = LookUpRAM1(TableNumbers,Index,LookUpDownReturn)

    HRSOut "Result: ",Dec LookUpDownReturn,CR
    If LookUpDownReturn = 255 Then
        HRSOut "ERROR: Variable Index out of range! ",CR
    EndIf
This Procedure gives compiled code like this:
    Lfsr 0,TableNumbers
    Movff Index,PRODL
    Movff LookUpDownReturn,PRODH
    Rcall LookUpRAM1
    Movff PRODH,LookUpDownReturn
EXAMPLE 2:

Make a Macro Assembler that could give a similar response to the "LookUp" command for RAM. The procedure will be called: LookUpRAM2().
This Macro performs a search for a value within an array with an input value (Index).
    Dim TableNumbers[11] As Byte = 10,20,30,40,50,60,70,80,90,100,0

    LookUpDownReturn = LookUpRAM2(TableNumbers,Index)
This Macro internally performs the copy of the return variable, so it is not necessary to write it in the macro (a little more efficient).

This Macro gives compiled code like this:
    Lfsr 0,TableNumbers
    Movff Index,PRODL
    Rcall mLookUpRAM2_Sub
    Btfsc _B__VR1,0
    Movff INDF1,Return_Var
This macro has been made up to look like a Procedure. You can't see the difference (except in color).


Description of the Procedures:
LookUpDownReturn = LookUpRAM1(TableNumbers,Index,LookUpDownReturn)


    Dim xxFSR0 As FSR0L.Word
    Dim xxFSR1 As FSR1L.Word

Proc LookUpRAM1(ByRef pArrayIn As xxFSR0, pIndex As PRODL, pResult As PRODH),pResult
    #ifdef watchdog_req
    Clrwdt
    #endif
    xxFSR1 = xxFSR0 + PRODL
    '/--------------------------------------------------------------------------
    Do
        If POSTINC0 = 0 Then Break  '/ Check array until final 0.
    Loop   
    xxFSR0 = xxFSR0 - 2
    '/--------------------------------------------------------------------------
    If xxFSR1 > xxFSR0 Then         '/ If index is not correct then exit
        ExitProc                    '/ Error pIndex is out of range.
    EndIf
    PRODH = INDF1
EndProc

    LookUpDownReturn = LookDownRAM1(TableNumbers,Index,LookUpDownReturn)


Proc LookDownRAM1(ByRef pArrayIn As xxFSR0, pIndex As Byte,pResult As PRODL), pResult
    #ifdef watchdog_req
    Clrwdt
    #endif

    PRODH = 0
    Do
        If INDF0 = 0 Then               '/ Check array until final 0.
            ExitProc                    '/ Return an Error. pIndex is out of range.
        EndIf
        If INDF0 = pIndex Then Break  
        Inc PRODH                       '/ Retrieve the result of the search.
        Inc xxFSR0
    Loop   
    PRODL = PRODH
EndProc

Macro Description:
    LookUpDownReturn = LookUpRAM2(TableNumbers,Index)

    Dim xxResult As Byte System
    Dim xxReturnByte As Byte System
    Dim xxEnableReturn As Bit

$define LookUpRAM2(pArrayIn,pIndex) mLookUpRAM2 pArrayIn,pIndex


mLookUpRAM2 Macro- pArrayIn,pIndex
    #if (Prm_Count != 2)        
        #error "Incorrect amount of parameters for mLookUpRAM2 macro. 2 Parameters required!"   
        Exitm
    #else
        #if (Prm_1 != Byte_Array_Ptr) && (Prm_1 != String)
            #error "LookUpRAM2 Macro - (Param1) Should be a BYTE array or a String!"
            Exitm
        #else
            #if (Prm_1 == Byte_Array_Ptr) || (Prm_1 == String)
                Num_FSR0 pArrayIn
            #endif
        #endif     
        #if (Prm_2 != Byte) && (Prm_2 != Num8)
            #error "LookUpRAM2 Macro - Input Value(Param1) Should be a Byte Variable or a Num8"
            Exitm
        #else   
            #if (Prm_2 == Byte)
                Byte_Byte pIndex, PRODL
                            #endif
            #if (Prm_2 == Num8)
                Num_Byte pIndex, PRODL
            #endif           
        #endif
        #if (mLookUpRAM2_RETURN == 1)
'            #if (Return_Type != Byte)
'                #error "LookUpRAM2 Macro - Return variable should be a Byte variable"
'                Exitm
'            #else
'                Byte_Byte Return_Var, xxReturnByte
'            #endif
        #endif
    #endif
    GoSub mLookUpRAM2_Sub
    #if (mLookUpRAM2_RETURN == 1)
        #if (Return_Type != Byte)
            #error "LookUpRAM Macro - Return variable should be a Byte variable"
            Exitm
        #else
            'Set_Bank xxEnableReturn
            Btfsc xxEnableReturn
            Byte_Byte INDF1, Return_Var
        #endif
    #endif
Endm

#ifMacro- mLookUpRAM2      
mLookUpRAM2_Sub:
    #ifdef watchdog_req
    Clrwdt
    #endif
    xxFSR1 = xxFSR0 + PRODL
    '/--------------------------------------------------------------------------
    Do
        If POSTINC0 = 0 Then Break  '/ Check array until final 0.
    Loop   
    xxFSR0 = xxFSR0 - 2
    '/--------------------------------------------------------------------------
    If xxFSR1 > xxFSR0 Then         '/ If index is incorrect then exit
        'INDF1 = xxReturnByte        '/ Return same value of Return_Var
        xxEnableReturn = 0
        Return                     
    EndIf
    '/--------------------------------------------------------------------------
    xxEnableReturn = 1
    Return
#endIfMacro-
This Macro is prepared to support the 2 systems.

    LookUpDownReturn = LookDownRAM2(TableNumbers,Index)

$define LookDownRAM2(pArrayIn,pIndex) mLookDownRAM2 pArrayIn,pIndex

mLookDownRAM2 Macro- pArrayIn,pIndex '\Byte
    #if (Prm_Count != 2)        
        #error "Incorrect amount of parameters for LookDownRAM macro. 2 Parameters required!"   
        Exitm
    #else
        #if (Prm_Count < 2)
            #error "mLookDownRAM2 - Too few parameters"
            Exitm
        #else
            #if (Prm_1 != Byte_Array_Ptr) && (Prm_1 != String)
                #error "mLookDownRAM2 Macro - (Param1) Should be a BYTE array or a String!"
                Exitm
            #else
                #if (Prm_1 == Byte_Array_Ptr) || (Prm_1 == String)
                    Num_FSR0 pArrayIn
                #endif
            #endif     
            #if (Prm_2 != Byte) && (Prm_2 != Num8)
                #error "mLookDownRAM2 Macro - (Param2) Should be a Byte Variable or a Num8"
                Exitm
            #else   
                #if (Prm_2 == Byte)
                    Byte_Byte pIndex, PRODL
                #endif
                #if (Prm_2 == Num8)
                    Num_Byte pIndex, PRODL
                #endif           
            #endif
'            #if (mLookDownRAM2_RETURN == 1)
'                #if (Return_Type != Byte)
'                    #error "mLookDownRAM2 Macro - Return variable should be a Byte variable"
'                    Exitm
'                #else
'                    Byte_Byte Return_Var, xxReturnByte
'                #endif
'            #endif
        #endif
    #endif
    GoSub mLookDownRAM2_Sub
    #if (mLookDownRAM2_RETURN == 1)
        #if (Return_Type != Byte)
            #error "LookUpRAM Macro - Return variable should be a Byte variable"
            Exitm
        #else
            'Set_Bank xxEnableReturn
            Btfsc xxEnableReturn
            Byte_Byte PRODH, Return_Var
        #endif
    #endif
Endm

#ifMacro- mLookDownRAM2      
mLookDownRAM2_Sub:
    #ifdef watchdog_req
    Clrwdt
    #endif
    PRODH = 0
    Do
        If INDF0 = 0 Then               '/ Check array until final 0.
            'PRODH = xxReturnByte        '/ Error then send same byte Return_Var
            xxEnableReturn = 0
            Return 
        EndIf
        If INDF0 = PRODL Then Break  
        Inc PRODH                       '/ Retrieve the result of the search.
        Inc xxFSR0
    Loop   
    xxEnableReturn = 1
    Return
#endIfMacro-
This Macro is prepared to support the 2 systems.

EXAMPLE 3:

You can't always initialize the return variable before the Procedure. Then it is the Procedure that must deliver, without confusion, an error variable.

I have used this trick several times and it works well too.
The trick is to deliver an extra byte from the Procedure.

If the Procedure must deliver a Byte value, then a Word Variable (2 Bytes) is generated. If the Procedure returns a Word value, then a Long value (3 Bytes) is generated.
    Dim ReturnWord As Word
    Dim ProcedureReturn As ReturnWord.LowByte
    Dim ErrorReturn As ReturnWord.HighByte

    Index = 9

    ProcedureReturn = 255                  '/ Load a value to control the Procedure.
    HRSOut "Index : ",Dec Index,CR 

    ReturnWord = LookUpRAM3(TableNumbers,Index,ProcedureReturn)

    HRSOut "Result: ",Dec ProcedureReturn,CR            '/ Byte Result of the Procedure

    '/ Testing the error byte sent by the Procedure.
    If ErrorReturn = $0F Then
        HRSOut "ERROR: Variable Index out of range! ",CR
    EndIf
The Procedure is generated in this way:
    Dim wPROD As PRODL.Word

Proc LookUpRAM3(ByRef pArrayIn As xxFSR0, pIndex As Byte, pResult As wPROD.LowByte), Word
    #ifdef watchdog_req
    Clrwdt
    #endif
    xxFSR1 = xxFSR0 + pIndex
    '/--------------------------------------------------------------------------
    Do
        If POSTINC0 = 0 Then Break  '/ Check array until final 0.
    Loop   
    xxFSR0 = xxFSR0 - 2
    '/--------------------------------------------------------------------------
    If xxFSR1 > xxFSR0 Then             '/ If index is not correct then exit
        Result.LowByte = wPROD.LowByte  '/ Send the same Return_Var value for the Procedure
        Result.HighByte = $0F           '/ Send an error value
        ExitProc                        '/ Error pIndex is out of range.
    EndIf
    Result.LowByte = INDF1              '/ Send a correct value for the Procedure
    Result.HighByte = 0                 '/ Send a NO error value
EndProc

I hope this work has been useful.
Regards

01/07/2023 Update the library
Fixed error in the LookDownRAM2 Macro.
73's de EA3AGV