• AVR Freaks

Hot!Problem with PSECT in assembly file

Page: 12 > Showing page 1 of 2
Author
COSMO LITTLE
Starting Member
  • Total Posts : 76
  • Reward points : 0
  • Joined: 2010/07/01 04:29:34
  • Location: 0
  • Status: offline
2019/09/17 00:53:58 (permalink)
0

Problem with PSECT in assembly file

Dear Experts,
I have just started an assembly routine as part of a long and complicated C program. This is to do something which is nearly impossible in C:  signed long multiply keeping the 64bit product, and accumulating this with 64 bit precision. This is for implementation of a IIR filter, where floating point does not provide sufficient precision.
   I have successfully used assembly routines with the XC16, but not the XC8.
 
   The (template) assembly file links OK, and can be called from the C routine, however the local variables defined in the assembly routine do not appear in the symbol table. The data PSECT also does not appear in the map file. Strangely, the linker does not give any errors. I have tried various PSECTS, with class=DATA, class=BANK5, etc.
  Without knowing the absolute address of the variables, I cannot confirm that these are actually accessed in the code.
 
best regards
 
Cosmo Little
 
 
;assembly routine to multiply two signed long variables with 64 bit result,
;and to accumulate the result with 64 bit precision
;developmet version 1.00 17/09/19
    
    #include <xc.inc>
 
 
GLOBAL _mult64accum,result ; make globally accessible
EXTRN _mult_x,_mult_y,_accum_high
 
 
PSECT asmvar, local,class=RAM
 
result: DS 8
accum64: DS 8
    
    
PSECT assembly,local,class=CODE,reloc=2
    


    
; routine to multiply two long signed integers, and accumulate the 64bit product
    
_mult64accum:
 

    MOVF BANKMASK(_mult_x),W
    MULWF BANKMASK(_mult_y)
    MOVF PRODL,W
    ADDWF result,F
    MOVF PRODH,W
    ADDWFC result+1,F
    MOVF result+1,W
    MOVWF accum64


    RETURN

#1

28 Replies Related Threads

    davekw7x
    Entropy++
    • Total Posts : 1827
    • Reward points : 0
    • Joined: 2012/01/16 12:01:07
    • Location: Second star on the right, straight on till morning
    • Status: offline
    Re: Problem with PSECT in assembly file 2019/09/17 10:59:34 (permalink)
    +1 (1)
    COSMO LITTLE
    ...something which is nearly impossible in C:  signed long multiply keeping the 64bit product, and accumulating this with 64 bit precision.



    I have been hoping an Assembly Language expert would weigh in.  (I rank myself to be about number 10,000 among the 10,001 experts on this forum.)
    So I can't offer help or hope in writing or linking or testing Assembler code.

    However...
    Sometimes I just can't help myself, and I decided to make a couple of comments.

    First of all, the hardware multipler on a 'K42 device is capable of multiplying two eight-bit integers to create a 16-bit integer.  Equation 12-1 and Example 12-3 in the Data Sheet, DS40001919E,  show the sequence for multiplying two 16-bit integers.  There is a lot of stuff adding cross products.  Now, extend that to 32x32, and you have a lot more stuff.

    Next-to-bottom line (Opinion): I think your code may multiply 8x8 and accumulate 16-bits.  (I didn't analyze very carefully or attempt to test).  No way does it multiply 32x32 and accumulate 64.

    Now...
    One reason I moved from XC8 version 1.45 to version 2.xx (now up to 2.10) is that the C99 mode supports 64-bit integers.  Even if you have reasons not to move to C99, you can still, maybe, see a way to do your multiply-accumulate function by making a test program and looking at the .lst file to see the assembly instructions for your functionality.  It wouldn't shock me to hear that an expert can improve on the compiler-generated code, but at least maybe this would be a starting point.

    Bottom line:
    Here's the relevant part of a little test I added to my PIC18F27K42 evaluation project for C99:


    // Make these volatile so that they don't get optimized into constants
    // by the simple test program (so that you can get a real feel for
    // actual application code)
    volatile uint64_t accum64;
    volatile uint64_t result;
    volatile uint32_t mult_x;// = 0x12345678;
    volatile uint32_t mult_y;// = 0x87654321;

    // Uses global variables mult_x, mult_y, accum64
    // I might not use a function for this, but simply put the
    // calculation in-line.  More generated code, less time.
    //
    void mult_accum(void)
    {
         result = (uint64_t)mult_x*(uint64_t)mult_y;
         accum64 += result;
    }
    // A more "normal" multiply-accumulate function to add the product to
    // a 64-bit previously accumulated value.
    // If you also want to return the 64-bit multiplication result, you
    // could create another parameter, a pointer to uint64_t to save
    // the product term.
    uint64_t m_a(uint32_t x, uint32_t y, uint64_t ac)
    {
        return  ac + (uint64_t)x * (uint64_t)y;
    }

    void init_system(void);

    void main(void)
    {
        // Initialze clock, timer, uart, etc...
        init_system();

        __delay_ms(100); // Give it a little time to settle down
        printf("\r\nCompiled on %s at %s by XC8 version %u\r\n",
                __DATE__, __TIME__, __XC8_VERSION);
        mult_x = 0x12345678;
        mult_y = 0x87654321;
        accum64 = 0x1111111111111111;
        printf("mult_x  = %10lu = 0x%08lX\r\n", mult_x, mult_x);
        printf("mult_y  = %10lu = 0x%08lX\r\n", mult_y, mult_y);
        printf("accum64 = %llu = 0x%016llX\r\n\r\n", accum64, accum64);

        // Using globals
        mult_accum();
        printf("mult_accum:\r\n");
        printf("  result  = %20llu = 0x%016llX\r\n", result, result);
        printf("  accum64 = %20llu = 0x%016llX\r\n", accum64, accum64);

        // Using parameters
        uint64_t ac64 = 0x1111111111111111;
        ac64 = m_a(mult_x, mult_y, ac64);
        printf("m_a:\r\n");
        printf("  ac64    = %20llu = 0x%016llX\r\n", accum64, accum64);

    // Make these volatile so that they don't get optimized into constants
    // by the simple test program (so that you can get a real feel for
    // actual application code)
    volatile uint64_t accum64;
    volatile uint64_t result;
    volatile uint32_t mult_x;// = 0x12345678;
    volatile uint32_t mult_y;// = 0x87654321;

    // Uses global variables mult_x, mult_y, accum64
    // I might not use a function for this, but simply put the
    // calculation in-line.
    //
    void mult_accum(void)
    {
         result = (uint64_t)mult_x*(uint64_t)mult_y;
         accum64 += result;
    }
    // A more "normal" multiply-accumulate function to add the product to
    // a 64-bit previously accumulated value.
    // If you also want to return the 62-bit multiplication result, you
    // could create another parameter, a pointer to uint64_t to save
    // the product term.
    uint64_t m_a(uint32_t x, uint32_t y, uint64_t ac)
    {
        return  ac + (uint64_t)x * (uint64_t)y;
    }

    void init_system(void);

    void main(void)
    {
        // Initialze clock, timer, uart, etc...
        init_system();

        __delay_ms(100); // Give it a little time to settle down
        printf("\r\nCompiled on %s at %s by XC8 version %u\r\n",
                __DATE__, __TIME__, __XC8_VERSION);
        mult_x = 0x12345678;
        mult_y = 0x87654321;
        accum64 = 0x1111111111111111;
        printf("mult_x  = %10lu = 0x%08lX\r\n", mult_x, mult_x);
        printf("mult_y  = %10lu = 0x%08lX\r\n", mult_y, mult_y);
        printf("accum64 = %llu = 0x%016llX\r\n\r\n", accum64, accum64);

        // Using globals
        mult_accum();
        printf("mult_accum:\r\n");
        printf("  result  = %20llu = 0x%016llX\r\n", result, result);
        printf("  accum64 = %20llu = 0x%016llX\r\n", accum64, accum64);

        // Using parameters
        uint64_t ac64 = 0x1111111111111111;
        ac64 = m_a(mult_x, mult_y, ac64);
        printf("m_a:\r\n");
        printf("  ac64    = %20llu = 0x%016llX\r\n", accum64, accum64);
    // Other stuff


    Output (XC8 version 2.10, C99 mode, optimization level 1):
    Compiled on Sep 17 2019 at 10:23:12 by XC8 version 2100
    mult_x  =  305419896 = 0x12345678
    mult_y  = 2271560481 = 0x87654321
    accum64 = 1229782938247303441 = 0x1111111111111111

    mult_accum:
      result  =   693779765864729976 = 0x09A0CD0570B88D78
      accum64 =  1923562704112033417 = 0x1AB1DE1681C99E89
    m_a:
      ac64    =  1923562704112033417 = 0x1AB1DE1681C99E89

    Results verified correct by external means, not involving XCanything or C language programs.


    Regards,

    Dave


    Footnote:
    The opinions expressed here are not necessarily my own.
    It's these dang voices in my head.
    post edited by davekw7x - 2019/09/17 11:13:21

    Sometimes I just can't help myself...
    #2
    mad_c
    Super Member
    • Total Posts : 1195
    • Reward points : 0
    • Joined: 2010/12/12 17:48:27
    • Location: Brisbane, Australia
    • Status: offline
    Re: Problem with PSECT in assembly file 2019/09/17 13:49:29 (permalink)
    +3 (3)
    COSMO LITTLE
       The (template) assembly file links OK, and can be called from the C routine, however the local variables defined in the assembly routine do not appear in the symbol table.

    They are not 'local' in any way; these can be accessed from any routine. However, there are a few issues with how they are defined.
     
    First consider defining these in as global objects in C code, as this is much easier to do safely. If you must define them in assembly there are several things you must do to fix them. Tell the linker that the psect should be placed in RAM, not program memory, using the space=1 flag. Second, you will need to ensure that the code generator is aware that you will be claiming RAM after it has executed (and allocated all the RAM needs). There is a section in the User's Guide, 4.12.3.4 ABSOLUTE PSECTS which explains what you need to do. However, hopefully, but now you are now thinking about defining these in C code.
     
    Jeff.
     
    #3
    COSMO LITTLE
    Starting Member
    • Total Posts : 76
    • Reward points : 0
    • Joined: 2010/07/01 04:29:34
    • Location: 0
    • Status: offline
    Re: Problem with PSECT in assembly file 2019/09/18 09:09:20 (permalink)
    0
    ;assembly routine to multiply two signed long variables with 64 bit result,
    ;and to accumulate the result with 64 bit precision
    ;development version 1.00 17/09/19
        
        #include <xc.inc>
        

     
    PSECT asmvar,class=BANK5,space=1,abs,ovrld
    ORG 500h

    x: DS 4
    y: DS 4
    result: DS 8
    accum64: DS 8
    FLAGS: DS 1
        
    GLOBAL _mult64accum,x,y,result,accum64,FLAGS ; make globally accessible
    EXTRN _mult_x,_mult_y,_accum_high
        
        
        
    PSECT assembly,local,class=CODE,reloc=2
        
    ; routine to multiply two long signed integers, and accumulate the 64bit product
        
    _mult64accum:
        
    ;transfer C variables to local variables using movff
        
        MOVFF _mult_x,x
        MOVFF _mult_x+1,x+1
        MOVFF _mult_x+2,x+2
        MOVFF _mult_x+3,x+3
        
        MOVFF _mult_y,y
        MOVFF _mult_y+1,y+1
        MOVFF _mult_y+2,y+2
        MOVFF _mult_y+3,y+3
        
    ;set bank 5
        
        MOVLB 5
        
    ;parameter is passed in w. If w=0, proceed with routine. If w=1, reset accumulator
        
        MOVF WREG,W
        BZ NORESET
        
    ;reset accumulator
        
        CLRF accum64
        CLRF accum64+1
        CLRF accum64+2
        CLRF accum64+3
        CLRF accum64+4
        CLRF accum64+5
        CLRF accum64+6
        CLRF accum64+7
        
        RETURN
     
        
    NORESET:
    ;test for either or both multiplicands negative
        
        CLRF FLAGS
        BTFSC x+3,7
        BSF FLAGS,0
        BTFSC y+3,7
        BSF FLAGS,1
        
    ;complement negative multiplicands
        
        BTFSS FLAGS,0
        BRA TEST_MULT_Y
        
    ;complement _mult_x
        
        COMF x,F
        COMF x+1,F
        COMF x+2,F
        COMF x+3,F
        
        MOVLW 1

        ADDWF x,F
        CLRF WREG
        ADDWFC x+1,F
        ADDWFC x+2,F
        ADDWFC x+3,F

    TEST_MULT_Y:
        
        BTFSS FLAGS,1
        BRA STARTMULT
        
    ;complement _mult_y
        
        COMF y,F
        COMF y+1,F
        COMF y+2,F
        COMF y+3,F
        
        MOVLW 1

        ADDWF y,F
        CLRF WREG
        ADDWFC y+1,F
        ADDWFC y+2,F
        ADDWFC y+3,F
        
        
     
    STARTMULT:
        MOVF x,W
        MULWF y
        MOVFF PRODL,result
        MOVFF PRODH,result+1 ; zero order product goes to result(0,1)
      

        MOVF x+1,W
        MULWF y+1
        MOVFF PRODL,result+2
        MOVFF PRODH,result+3 ;second order product goes to result(2,3)

        MOVF x+2,W
        MULWF y+2
        MOVFF PRODL,result+4
        MOVFF PRODH,result+5 ;4th order product goes to result(4,5)
        
        MOVF x+3,W
        MULWF y+3
        MOVFF PRODL,result+6
        MOVFF PRODH,result+7 ;6th order product goes to result(6,7)
      
        MOVF x+2,W
        MULWF y+3
        MOVF PRODL,W
        ADDWF result+5
        MOVF PRODH,W
        ADDWFC result+6 ;5th order product added to result(5,6), carry added to result(7)
        CLRF WREG
        ADDWFC result+7
        
        MOVF x+3,W
        MULWF y+2
        MOVF PRODL,W
        ADDWF result+5
        MOVF PRODH,W
        ADDWFC result+6 ;5th order product added to result(5,6), carry added to result(7)
        CLRF WREG
        ADDWFC result+7

        MOVF x+1,W
        MULWF y+3
        MOVF PRODL,W
        ADDWF result+4
        MOVF PRODH,W
        ADDWFC result+5
        CLRF WREG
        ADDWFC result+6 ;4th order product added to result(4,5), carry added to result(6,7)
        ADDWFC result+7
        
        MOVF x+3,W
        MULWF y+1
        MOVF PRODL,W
        ADDWF result+4
        MOVF PRODH,W
        ADDWFC result+5
        CLRF WREG
        ADDWFC result+6 ;4th order product added to result(4,5), carry added to result(6,7)
        ADDWFC result+7
        
        MOVF x+2,W
        MULWF y+1
        MOVF PRODL,W
        ADDWF result+3
        MOVF PRODH,W
        ADDWFC result+4
        CLRF WREG
        ADDWFC result+5
        ADDWFC result+6 ;3rd order product added to result(3,4), carry added to result(5,6,7)
        ADDWFC result+7
        
        MOVF x+1,W
        MULWF y+2
        MOVF PRODL,W
        ADDWF result+3
        MOVF PRODH,W
        ADDWFC result+4
        CLRF WREG
        ADDWFC result+5
        ADDWFC result+6 ;3rd order product added to result(3,4), carry added to result(5,6,7)
        ADDWFC result+7
        
        MOVF x+3,W
        MULWF y
        MOVF PRODL,W
        ADDWF result+3
        MOVF PRODH,W
        ADDWFC result+4
        CLRF WREG
        ADDWFC result+5
        ADDWFC result+6 ;3rd order product added to result(3,4), carry added to result(5,6,7)
        ADDWFC result+7
        
        MOVF x,W
        MULWF y+3
        MOVF PRODL,W
        ADDWF result+3
        MOVF PRODH,W
        ADDWFC result+4
        CLRF WREG
        ADDWFC result+5
        ADDWFC result+6 ;3rd order product added to result(3,4), carry added to result(5,6,7)
        ADDWFC result+7
        
        MOVF x,W
        MULWF y+2
        MOVF PRODL,W
        ADDWF result+2
        MOVF PRODH,W
        ADDWFC result+3
        CLRF WREG
        ADDWFC result+4
        ADDWFC result+5
        ADDWFC result+6 ;second order product added to result(2,3), carry added to result(4,5,6,7)
        ADDWFC result+7
        
        MOVF x+2,W
        MULWF y
        MOVF PRODL,W
        ADDWF result+2
        MOVF PRODH,W
        ADDWFC result+3
        CLRF WREG
        ADDWFC result+4
        ADDWFC result+5
        ADDWFC result+6 ;second order product added to result(2,3), carry added to result(4,5,6,7)
        ADDWFC result+7
        
        MOVF x+1,W
        MULWF y
        MOVF PRODL,W
        ADDWF result+1
        MOVF PRODH,W
        ADDWFC result+2
        CLRF WREG
        ADDWFC result+3
        ADDWFC result+4
        ADDWFC result+5
        ADDWFC result+6 ;first order product added to result(1,2), carry added to result(3,4,5,6,7)
        ADDWFC result+7
        
        MOVF x,W
        MULWF y+1
        MOVF PRODL,W
        ADDWF result+1
        MOVF PRODH,W
        ADDWFC result+2
        CLRF WREG
        ADDWFC result+3
        ADDWFC result+4
        ADDWFC result+5
        ADDWFC result+6 ;first order product added to result(1,2), carry added to result(3,4,5,6,7)
        ADDWFC result+7
        
    ;end of multiplication, 64bit result in result[8].
        
    ;result may be negative if either one of the operands was negative. check FLAGS and complement result if necessary
        
        BTFSS FLAGS,0
        BTFSC FLAGS,1
        BRA COMPLEMENTRESULT
        
    ACCUMULATERESULT:
        
        MOVF result,W
        ADDWF accum64
        MOVF result+1,W
        ADDWFC accum64+1
        MOVF result+2,W
        ADDWFC accum64+2
        MOVF result+3,W
        ADDWFC accum64+3
        MOVF result+4,W
        ADDWFC accum64+4
        MOVF result+5,W
        ADDWFC accum64+5
        MOVF result+6,W
        ADDWFC accum64+6
        MOVF result+7,W
        ADDWFC accum64+7
        
    ;copy ms 32 bits of accum to c variable accum_high
        
        MOVFF accum64+4,_accum_high
        MOVFF accum64+5,_accum_high+1
        MOVFF accum64+6,_accum_high+2
        MOVFF accum64+7,_accum_high+3
        
        RETURN
        
    COMPLEMENTRESULT:
        
        COMF result,F
        COMF result+1,F
        COMF result+2,F
        COMF result+3,F
        COMF result+4,F
        COMF result+5,F
        COMF result+6,F
        COMF result+7,F
        
        MOVLW 1
        
        ADDWF result,F
        CLRF WREG
        ADDWFC result+1,F
        ADDWFC result+2,F
        ADDWFC result+3,F
        ADDWFC result+4,F
        ADDWFC result+5,F
        ADDWFC result+6,F
        ADDWFC result+7,F
        
        
        GOTO ACCUMULATERESULT



    Dear Dave and Jeff
     
    Thank you for your replies
     
    1/- I was not aware of the update to xc8 to use 64 bit integers. If I had been, I would probably have implemented the filter using c. I have downloaded the version 2.1, and find that as part of the download there is a new user guide that is apparently not available elsewhere on the Microchip website. It has further details on the use of assembly routines.
    2/- Yesterday I completed the assembler version, which as Dave pointed out, accumulates 16 cross products to do the 32bit multiplication. Although this sounds complicated, it is quite logical and is no problem to program.
    3/- The new manual has a section on using an absolute PSECT, which finally got my variables into the symbol table. For clarity I placed the assembler variables in bank5, which was otherwise unused. I had a lot of trouble with bank selecting, so I copied the global C variables into local variables using movff instructions. I was then able to set the bank to bank5 for the entire routine.
    4/- I originally considered declaring the 64 bit variables in C, but could not think of any way of doing this.
    5/- everything now works, except for some reason the global assembler variables are not available in the watch symbol table. However I can live with this, as I can use the file register table to check their values.
     
    regards
     
    Cosmo Little
    #4
    du00000001
    Just Some Member
    • Total Posts : 3076
    • Reward points : 0
    • Joined: 2016/05/03 13:52:42
    • Location: Germany
    • Status: offline
    Re: Problem with PSECT in assembly file 2019/09/18 09:21:53 (permalink)
    +1 (1)
    COSMO LITTLE
    4/- I originally considered declaring the 64 bit variables in C, but could not think of any way of doing this.

     
    If supported, the declaration (un)signed long long results in 64-Bit integers of the respective sort. (Former versions of XC8 propagated the ... long long to 32-Bit data.)

    PEBKAC / EBKAC / POBCAK / PICNIC (eventually see en.wikipedia.org)
    #5
    1and0
    Access is Denied
    • Total Posts : 9771
    • Reward points : 0
    • Joined: 2007/05/06 12:03:20
    • Location: Harry's Gray Matter
    • Status: offline
    Re: Problem with PSECT in assembly file 2019/09/18 10:59:17 (permalink)
    +2 (2)
    XC8 version 2.xx has 64-bit integer types, which can multiply 64-bit by 64-bit with result of 64-bit.
     
    If you want multiplication of 32-bit by 32-bit with result of 64-bit, here are some C functions.
     
    COSMO LITTLE

    ;result may be negative if either one of the operands was negative. check FLAGS and complement result if necessary

        BTFSS FLAGS,0
        BTFSC FLAGS,1
        BRA COMPLEMENTRESULT


    For speed use assembly as you have but I think your routine has a bug.  Hint: the product of two negative numbers is positive.
    #6
    1and0
    Access is Denied
    • Total Posts : 9771
    • Reward points : 0
    • Joined: 2007/05/06 12:03:20
    • Location: Harry's Gray Matter
    • Status: offline
    Re: Problem with PSECT in assembly file 2019/09/18 11:48:23 (permalink)
    0
    Also, you could optimize and speed up your assembly routine by adding two cross products at a time, instead of one a time.
    #7
    ric
    Super Member
    • Total Posts : 23893
    • Reward points : 0
    • Joined: 2003/11/07 12:41:26
    • Location: Australia, Melbourne
    • Status: online
    Re: Problem with PSECT in assembly file 2019/09/18 13:37:10 (permalink)
    0
    I haven't see any mention of exactly was PIC this is aimed at.
    The XC8 64 bit support only works on PIC18 and enhanced PIC16, not traditional PIC16.
    I see an "add with carry" instruction in the assembly, and mention of "bank 5", so it can't be old fashioned PIC16 anyway.
     

    I also post at: PicForum
    Links to useful PIC information: http://picforum.ric323.co...opic.php?f=59&t=15
    NEW USERS: Posting images, links and code - workaround for restrictions.
    To get a useful answer, always state which PIC you are using!
    #8
    1and0
    Access is Denied
    • Total Posts : 9771
    • Reward points : 0
    • Joined: 2007/05/06 12:03:20
    • Location: Harry's Gray Matter
    • Status: offline
    Re: Problem with PSECT in assembly file 2019/09/18 14:15:21 (permalink)
    +1 (1)
    OP uses MOVFF and hardware multiplier in Post #4, so it's a PIC18.
    #9
    1and0
    Access is Denied
    • Total Posts : 9771
    • Reward points : 0
    • Joined: 2007/05/06 12:03:20
    • Location: Harry's Gray Matter
    • Status: offline
    Re: Problem with PSECT in assembly file 2019/09/18 19:32:07 (permalink)
    +1 (1)
    Furthermore, negating the multiple bytes variables can be done in half the program memory and half the instruction cycles by subtraction from zero, instead of one's complement and addition of one.
    #10
    dan1138
    Super Member
    • Total Posts : 3232
    • Reward points : 0
    • Joined: 2007/02/21 23:04:16
    • Location: 0
    • Status: offline
    Re: Problem with PSECT in assembly file 2019/09/18 19:54:56 (permalink)
    +1 (1)
    As the OP (COSMO LITTLE) seems to need a complete example here is one:
    /*
     * File:   main.c
     * Author: dan118
     *
     * Created on September 18, 2019, 6:10 PM
     */

    #include <xc.h>
    /*
     * Assign these to fixed memory locations in the common (ACCESS) bank
     */
    volatile long m1 __at(0x0000);
    volatile long m2 __at(0x0004);
    volatile struct { unsigned long lo; unsigned long hi; } PRODUCT __at(0x0008);
    volatile struct { unsigned long lo; unsigned long hi; } MAC     __at(0x0010);
    /*
     * 32x32 MAC, best case 142 clocks, mid case 150 clocks, worst case 155 clocks.
     */
    void mac(void)
    {
    /*
     * Zero out high DWORD of PRODUCT register
     */
        __asm("    CLRF    _PRODUCT+4,C");
        __asm("    CLRF    _PRODUCT+5,C");
        __asm("    CLRF    _PRODUCT+6,C");
        __asm("    CLRF    _PRODUCT+7,C");
    /*
     * Check sign of multiplicand
     */
        __asm("    MOVLW   0");
        __asm("    BTFSS   _m1+3,7,C");
        __asm("    BRA     _m1PLUS");
        __asm("    NEGF    _m1+0,C");
        __asm("    SUBFWB  _m1+1,F,C");
        __asm("    SUBFWB  _m1+2,F,C");
        __asm("    SUBFWB  _m1+3,F,C");
        __asm("    BTG    _PRODUCT+7,7,C");
        __asm("_m1PLUS:");
    /*
     * Check sign of multiplier
     */
        __asm("    BTFSS   _m2+3,7,C");
        __asm("    BRA     _m2PLUS");
        __asm("    NEGF    _m2+0,C");
        __asm("    SUBFWB  _m2+1,F,C");
        __asm("    SUBFWB  _m2+2,F,C");
        __asm("    SUBFWB  _m2+3,F,C");
        __asm("    BTG    _PRODUCT+7,7,C");
        __asm("_m2PLUS:");
    /*
     * do 32 x 32 multiply
     */
        __asm("    MOVF    _m1+0,W,C");
        __asm("    MULWF   _m2+0,C");
        __asm("    MOVF    PRODL,W");
        __asm("    MOVWF   _PRODUCT+0,C");
        __asm("    MOVF    PRODH,W");
        __asm("    MOVWF   _PRODUCT+1,C");
        __asm("    MOVF    _m1+0,W,C");
        __asm("    MULWF   _m2+2,C");
        __asm("    MOVF    PRODL,W");
        __asm("    MOVWF   _PRODUCT+2,C");
        __asm("    MOVF    PRODH,W");
        __asm("    MOVWF   _PRODUCT+3,C");
        __asm("    MOVF    _m1+0,W,C");
        __asm("    MULWF   _m2+1,C");
        __asm("    MOVF    PRODL,W");
        __asm("    ADDWF   _PRODUCT+1,F,C");
        __asm("    MOVF    PRODH,W");
        __asm("    ADDWFC  _PRODUCT+2,F,C");
        __asm("    MOVF    _m1+0,W,C");
        __asm("    MULWF   _m2+3,C");
        __asm("    MOVF    PRODL,W");
        __asm("    ADDWFC  _PRODUCT+3,F,C");
        __asm("    MOVF    PRODH,W");
        __asm("    ADDWFC  _PRODUCT+4,F,C");
        __asm("    MOVLW   0");
        __asm("    ADDWFC  _PRODUCT+5,F,C");
        __asm("    MOVF    _m1+1,W,C");
        __asm("    MULWF   _m2+0,C");
        __asm("    MOVF    PRODL,W");
        __asm("    ADDWF   _PRODUCT+1,F,C");
        __asm("    MOVF    PRODH,W");
        __asm("    ADDWFC  _PRODUCT+2,F,C");
        __asm("    MOVF    _m1+1,W,C");
        __asm("    MULWF   _m2+2,C");
        __asm("    MOVF    PRODL,W");
        __asm("    ADDWFC  _PRODUCT+3,F,C");
        __asm("    MOVF    PRODH,W");
        __asm("    ADDWFC  _PRODUCT+4,F,C");
        __asm("    MOVLW   0");
        __asm("    ADDWFC  _PRODUCT+5,F,C");
        __asm("    MOVF    _m1+1,W,C");
        __asm("    MULWF   _m2+1,C");
        __asm("    MOVF    PRODL,W");
        __asm("    ADDWF   _PRODUCT+2,F,C");
        __asm("    MOVF    PRODH,W");
        __asm("    ADDWFC  _PRODUCT+3,F,C");
        __asm("    MOVF    _m1+1,W,C");
        __asm("    MULWF   _m2+3,C");
        __asm("    MOVF    PRODL,W");
        __asm("    ADDWFC  _PRODUCT+4,F,C");
        __asm("    MOVF    PRODH,W");
        __asm("    ADDWFC  _PRODUCT+5,F,C");
        __asm("    MOVLW   0");
        __asm("    ADDWFC  _PRODUCT+6,F,C");
        __asm("    MOVF    _m1+2,W,C");
        __asm("    MULWF   _m2+0,C");
        __asm("    MOVF    PRODL,W");
        __asm("    ADDWF   _PRODUCT+2,F,C");
        __asm("    MOVF    PRODH,W");
        __asm("    ADDWFC  _PRODUCT+3,F,C");
        __asm("    MOVF    _m1+2,W,C");
        __asm("    MULWF   _m2+2,C");
        __asm("    MOVF    PRODL,W");
        __asm("    ADDWFC  _PRODUCT+4,F,C");
        __asm("    MOVF    PRODH,W");
        __asm("    ADDWFC  _PRODUCT+5,F,C");
        __asm("    MOVLW   0");
        __asm("    ADDWFC  _PRODUCT+6,F,C");
        __asm("    MOVF    _m1+2,W,C");
        __asm("    MULWF   _m2+1,C");
        __asm("    MOVF    PRODL,W");
        __asm("    ADDWF   _PRODUCT+3,F,C");
        __asm("    MOVF    PRODH,W");
        __asm("    ADDWFC  _PRODUCT+4,F,C");
        __asm("    MOVF    _m1+2,W,C");
        __asm("    MULWF   _m2+3,C");
        __asm("    MOVF    PRODL,W");
        __asm("    ADDWFC  _PRODUCT+5,F,C");
        __asm("    MOVF    PRODH,W");
        __asm("    ADDWFC  _PRODUCT+6,F,C");
        __asm("    MOVLW   0");
        __asm("    ADDWFC  _PRODUCT+7,F,C");
        __asm("    MOVF    _m1+3,W,C");
        __asm("    MULWF   _m2+0,C");
        __asm("    MOVF    PRODL,W");
        __asm("    ADDWF   _PRODUCT+3,F,C");
        __asm("    MOVF    PRODH,W");
        __asm("    ADDWFC  _PRODUCT+4,F,C");
        __asm("    MOVF    _m1+3,W,C");
        __asm("    MULWF   _m2+2,C");
        __asm("    MOVF    PRODL,W");
        __asm("    ADDWFC  _PRODUCT+5,F,C");
        __asm("    MOVF    PRODH,W");
        __asm("    ADDWFC  _PRODUCT+6,F,C");
        __asm("    MOVLW   0");
        __asm("    ADDWFC  _PRODUCT+7,F,C");
        __asm("    MOVF    _m1+3,W,C");
        __asm("    MULWF   _m2+1,C");
        __asm("    MOVF    PRODL,W");
        __asm("    ADDWF   _PRODUCT+4,F,C");
        __asm("    MOVF    PRODH,W");
        __asm("    ADDWFC  _PRODUCT+5,F,C");
        __asm("    MOVF    _m1+3,W,C");
        __asm("    MULWF   _m2+3,C");
        __asm("    MOVF    PRODL,W");
        __asm("    ADDWFC  _PRODUCT+6,F,C");
        __asm("    MOVF    PRODH,W");
        __asm("    ADDWFC  _PRODUCT+7,F,C");
    /*
     * Adjust sign of product
     */
        __asm("    BTFSS   _PRODUCT+7,7,C");
        __asm("    BRA     _PRODUCT_POS");
        __asm("    BCF     _PRODUCT+7,7,C");
        __asm("    MOVLW   0");
        __asm("    NEGF    _PRODUCT+0,C");
        __asm("    SUBFWB  _PRODUCT+1,F,C");
        __asm("    SUBFWB  _PRODUCT+2,F,C");
        __asm("    SUBFWB  _PRODUCT+3,F,C");
        __asm("    SUBFWB  _PRODUCT+4,F,C");
        __asm("    SUBFWB  _PRODUCT+5,F,C");
        __asm("    SUBFWB  _PRODUCT+6,F,C");
        __asm("    SUBFWB  _PRODUCT+7,F,C");
        __asm("_PRODUCT_POS:");
    /*
     * Add product to accumulator
     */
        __asm("    MOVF    _PRODUCT+0,W,C");
        __asm("    ADDWF       _MAC+0,F,C");
        __asm("    MOVF    _PRODUCT+1,W,C");
        __asm("    ADDWFC      _MAC+1,F,C");
        __asm("    MOVF    _PRODUCT+2,W,C");
        __asm("    ADDWFC      _MAC+2,F,C");
        __asm("    MOVF    _PRODUCT+3,W,C");
        __asm("    ADDWFC      _MAC+3,F,C");
        __asm("    MOVF    _PRODUCT+4,W,C");
        __asm("    ADDWFC      _MAC+4,F,C");
        __asm("    MOVF    _PRODUCT+5,W,C");
        __asm("    ADDWFC      _MAC+5,F,C");
        __asm("    MOVF    _PRODUCT+6,W,C");
        __asm("    ADDWFC      _MAC+6,F,C");
        __asm("    MOVF    _PRODUCT+7,W,C");
        __asm("    ADDWFC      _MAC+7,F,C");
    /*
     * If CARRY and SIGN do not match then an overflow occurred
     */
    }

    void main(void)
    {
        /* these help keep the XC8 optimizer from eliminating these objects as "unused" */
        MAC.lo = 0;
        MAC.hi = 0;
        PRODUCT.lo = 0;
        PRODUCT.hi = 0;
        
        m1 = 2147483647;
        m2 = 2147483647;
        mac();
        m1 = -2147483648; /* Note: XC8 asserts a waring but this is a correct value */
        mac();
        m1 = -2147483648; /* Note: XC8 asserts a waring but this is a correct value */
        m2 = -2147483648; /* Note: XC8 asserts a waring but this is a correct value */
        mac();
        Nop();
        /*
         * Just hang here
         */
        for(;;)
        {
        }
    }


    I have run this on the MPLABX v5.25 simulator and it looks like it works but this code has not been really tested.

    YOU HAVE BEEN WARNED!

    <EDIT>
    Changed signed operand handling as suggested in post #20 by 1and0. (Nice, Thanks!)
    Use only common (ACCESS) bank references, no MOVFF opcodes either.
    Added some comments, reduced RAM usage.
    Tested in simulator with PIC18F46K42.
    Seems to still work.

    YOU HAVE STILL BEEN WARNED!
    post edited by dan1138 - 2019/09/19 19:53:35
    #11
    davekw7x
    Entropy++
    • Total Posts : 1827
    • Reward points : 0
    • Joined: 2012/01/16 12:01:07
    • Location: Second star on the right, straight on till morning
    • Status: offline
    Re: Problem with PSECT in assembly file 2019/09/18 22:44:57 (permalink)
    +1 (1)
    ric
    I haven't see any mention of exactly was PIC this is aimed at.



    I wouldn't have gone to the trouble of testing (or posting) if I had to guess.
     
    From the assembly_routines_lst.txt attachment on the original post:

    Microchip Technology PIC18 Macro Assembler V1.45 build -152302408
                               Tue Sep 17 08:26:27 2019

         1                               processor    18F46K42


     
    Regards.

    Dave
    post edited by davekw7x - 2019/09/18 22:47:42

    Sometimes I just can't help myself...
    #12
    ric
    Super Member
    • Total Posts : 23893
    • Reward points : 0
    • Joined: 2003/11/07 12:41:26
    • Location: Australia, Melbourne
    • Status: online
    Re: Problem with PSECT in assembly file 2019/09/18 23:26:08 (permalink)
    +1 (1)
    Well spotted Dave.
    I wish users wouldn't make us go searching through their attachments to learn this basic detail...
     

    I also post at: PicForum
    Links to useful PIC information: http://picforum.ric323.co...opic.php?f=59&t=15
    NEW USERS: Posting images, links and code - workaround for restrictions.
    To get a useful answer, always state which PIC you are using!
    #13
    1and0
    Access is Denied
    • Total Posts : 9771
    • Reward points : 0
    • Joined: 2007/05/06 12:03:20
    • Location: Harry's Gray Matter
    • Status: offline
    Re: Problem with PSECT in assembly file 2019/09/19 07:38:13 (permalink)
    +1 (1)
    COSMO LITTLE

        MOVFF PRODL,result
        MOVFF PRODH,result+1 ; zero order product goes to result(0,1)

    5/- everything now works ...

     
    dan1138
     
        __asm("    MOVFF   PRODL,_PRODUCT+0");
        __asm("    MOVFF   PRODH,_PRODUCT+1");
     

    I have run this on the MPLABX v5.25 simulator and it looks like it works but this code have not been really tested.
    YOU HAVE BEEN WARNED!

     
    davekw7x
     
         1                               processor    18F46K42


    I don't know how OP tested his code and claimed everything works.  If the device is a K42 then *ALL* the assembly code posted in this thread will NOT work as intended!!!
     
    #14
    dan1138
    Super Member
    • Total Posts : 3232
    • Reward points : 0
    • Joined: 2007/02/21 23:04:16
    • Location: 0
    • Status: offline
    Re: Problem with PSECT in assembly file 2019/09/19 12:36:37 (permalink)
    0
    1and0
    dan1138
        __asm("    MOVFF   PRODL,_PRODUCT+0");
        __asm("    MOVFF   PRODH,_PRODUCT+1");

    I have run this on the MPLABX v5.25 simulator and it looks like it works but this code have not been really tested.
    YOU HAVE BEEN WARNED!

     
    I don't know how OP tested his code and claimed everything works.  If the device is a K42 then *ALL* the assembly code posted in this thread will NOT work as intended!!!



    @1and0,
    Is there an issue with the MOVFF opcode in the PIC18F46K42?
     
    My usage works in the simulator, I don't have any PIC18F46K42 to try this code in a real controller.
    #15
    1and0
    Access is Denied
    • Total Posts : 9771
    • Reward points : 0
    • Joined: 2007/05/06 12:03:20
    • Location: Harry's Gray Matter
    • Status: offline
    Re: Problem with PSECT in assembly file 2019/09/19 12:44:14 (permalink)
    0
    dan1138
    @1and0,
    Is there an issue with the MOVFF opcode in the PIC18F46K42?
     
    My usage works in the simulator, I don't have any PIC18F46K42 to try this code in a real controller.

    The K42 devices cripple the MOVFF instruction, where it can access only the lower 4K bytes data space (Banks 0-15).  SFRs such as PRODH and PRODL are located in Bank 63.
     
    <edit> The MOVFFL instruction can access 16K bytes data space, but it takes three words and three cycles.
    post edited by 1and0 - 2019/09/19 13:08:03
    #16
    dan1138
    Super Member
    • Total Posts : 3232
    • Reward points : 0
    • Joined: 2007/02/21 23:04:16
    • Location: 0
    • Status: offline
    Re: Problem with PSECT in assembly file 2019/09/19 15:07:24 (permalink)
    +2 (2)
    1and0
    The K42 devices cripple the MOVFF instruction, where it can access only the lower 4K bytes data space (Banks 0-15).  SFRs such as PRODH and PRODL are located in Bank 63.



    This is true but PRODH and PRODL can also be read using their ACCESS bank addresses of 0xF4 & 0xF3.
     
    Remember that all SFRs in the address range of 0x3F60 to 0x3FFF are mapped to the ACCESS bank 0x60 to 0xFF.
    In the PIC18F46K42 data sheet, (Figure 4-4 DS40001919E-page 45).
     
    The assembly code I posted depends on ALL of the RAM and SFRs being accessible using only the ACCESS bank.
     
    <EDIT>
    I looked at the actual code generated and the XC8 assembler replaced my MOVFF with the MOVFFL opcode.
    I will fix my code to use the common (ACCESS) bank.
    post edited by dan1138 - 2019/09/19 17:09:11
    #17
    ric
    Super Member
    • Total Posts : 23893
    • Reward points : 0
    • Joined: 2003/11/07 12:41:26
    • Location: Australia, Melbourne
    • Status: online
    Re: Problem with PSECT in assembly file 2019/09/19 15:18:53 (permalink)
    +1 (1)
    AFAIK, the MOVFF instruction does not observe the access bank, so as 1and0 states, it can't access the PRODx registers. (There's no "a" bit in the opcode).
    That calls into question all the example multiply code in the K42 datasheet, which does precisely that...
     

    I also post at: PicForum
    Links to useful PIC information: http://picforum.ric323.co...opic.php?f=59&t=15
    NEW USERS: Posting images, links and code - workaround for restrictions.
    To get a useful answer, always state which PIC you are using!
    #18
    1and0
    Access is Denied
    • Total Posts : 9771
    • Reward points : 0
    • Joined: 2007/05/06 12:03:20
    • Location: Harry's Gray Matter
    • Status: offline
    Re: Problem with PSECT in assembly file 2019/09/19 18:31:09 (permalink)
    +1 (1)
    ric
    AFAIK, the MOVFF instruction does not observe the access bank, so as 1and0 states, it can't access the PRODx registers. (There's no "a" bit in the opcode).
    That calls into question all the example multiply code in the K42 datasheet, which does precisely that...

    Another copy 'n paste errata. :(
     
    Regarding the MOVFF instruction and the SFRs, I agree with NorthGuy here where Microchip should have kept the SFRs in the lower memory (Banks 15 and below). This way MOVFF would not be limited and able to move data between commonly-used SFRs and the lower RAM, especially the Access RAM.

    Oh well, perhaps Microchip will implement this for the PIC18 K43 family. ;)
    #19
    1and0
    Access is Denied
    • Total Posts : 9771
    • Reward points : 0
    • Joined: 2007/05/06 12:03:20
    • Location: Harry's Gray Matter
    • Status: offline
    Re: Problem with PSECT in assembly file 2019/09/19 18:46:12 (permalink)
    +1 (1)
    dan1138
     
    Use only common (ACCESS) bank references, no MOVFF opcodes either.
    Added some comments, reduced RAM usage.
    Tested in simulator with PIC18F46K42.
    Seems to still work.

    As I said in Post #10, to negate a multiple bytes variable, it is more efficient to subtract from zero than to complement and add one. So replace this
    /*
     * Check sign of multiplicand
     */
        __asm("    BTFSS   _m1+3,7,C");
        __asm("    BRA     _m1PLUS");
        __asm("    MOVLW   0");
        __asm("    NEGF    _m1+0,C");
        __asm("    COMF    _m1+1,F,C");
        __asm("    ADDWFC  _m1+1,F,C");
        __asm("    COMF    _m1+2,F,C");
        __asm("    ADDWFC  _m1+2,F,C");
        __asm("    COMF    _m1+3,F,C");
        __asm("    ADDWFC  _m1+3,F,C");
        __asm("    BTG    _PRODUCT+7,7,C");
        __asm("_m1PLUS:");
    /*
     * Check sign of multiplier
     */
        __asm("    BTFSS   _m2+3,7,C");
        __asm("    BRA     _m2PLUS");
        __asm("    MOVLW   0");
        __asm("    NEGF    _m2+0,C");
        __asm("    COMF    _m2+1,F,C");
        __asm("    ADDWFC  _m2+1,F,C");
        __asm("    COMF    _m2+2,F,C");
        __asm("    ADDWFC  _m2+2,F,C");
        __asm("    COMF    _m2+3,F,C");
        __asm("    ADDWFC  _m2+3,F,C");
        __asm("    BTG    _PRODUCT+7,7,C");
        __asm("_m2PLUS:");

    with this
    /*
     * Check sign of multiplicand
     */
        __asm("    MOVLW   0");
        __asm("    BTFSS   _m1+3,7,C");
        __asm("    BRA     _m1PLUS");
        __asm("    NEGF    _m1+0,C");
        __asm("    SUBFWB  _m1+1,F,C");
        __asm("    SUBFWB  _m1+2,F,C");
        __asm("    SUBFWB  _m1+3,F,C");
        __asm("    BTG    _PRODUCT+7,7,C");
        __asm("_m1PLUS:");
    /*
     * Check sign of multiplier
     */
        __asm("    BTFSS   _m2+3,7,C");
        __asm("    BRA     _m2PLUS");
        __asm("    NEGF    _m2+0,C");
        __asm("    SUBFWB  _m2+1,F,C");
        __asm("    SUBFWB  _m2+2,F,C");
        __asm("    SUBFWB  _m2+3,F,C");
        __asm("    BTG    _PRODUCT+7,7,C");
        __asm("_m2PLUS:");

    and replace this
        __asm("    MOVLW   0");
        __asm("    NEGF    _PRODUCT+0,C");
        __asm("    COMF    _PRODUCT+1,F,C");
        __asm("    ADDWFC  _PRODUCT+1,F,C");
        __asm("    COMF    _PRODUCT+2,F,C");
        __asm("    ADDWFC  _PRODUCT+2,F,C");
        __asm("    COMF    _PRODUCT+3,F,C");
        __asm("    ADDWFC  _PRODUCT+3,F,C");
        __asm("    COMF    _PRODUCT+4,F,C");
        __asm("    ADDWFC  _PRODUCT+4,F,C");
        __asm("    COMF    _PRODUCT+5,F,C");
        __asm("    ADDWFC  _PRODUCT+5,F,C");
        __asm("    COMF    _PRODUCT+6,F,C");
        __asm("    ADDWFC  _PRODUCT+6,F,C");
        __asm("    COMF    _PRODUCT+7,F,C");
        __asm("    ADDWFC  _PRODUCT+7,F,C");

    with this
        __asm("    MOVLW   0");
        __asm("    NEGF    _PRODUCT+0,C");
        __asm("    SUBFWB  _PRODUCT+1,F,C");
        __asm("    SUBFWB  _PRODUCT+2,F,C");
        __asm("    SUBFWB  _PRODUCT+3,F,C");
        __asm("    SUBFWB  _PRODUCT+4,F,C");
        __asm("    SUBFWB  _PRODUCT+5,F,C");
        __asm("    SUBFWB  _PRODUCT+6,F,C");
        __asm("    SUBFWB  _PRODUCT+7,F,C");

    #20
    Page: 12 > Showing page 1 of 2
    Jump to:
    © 2019 APG vNext Commercial Version 4.5