makro parameter type

Coding and general discussion relating to the compiler

Moderators: David Barker, Jerry Messina

Post Reply
janni
Posts: 51
Joined: Wed Aug 24, 2022 2:30 pm

makro parameter type

Post by janni » Sat Sep 03, 2022 2:57 pm

Is there a way to recognise type of parameter passed to makro? Size of the parameter may be determined with sizeOf or checkParam, but how to differentiate integer from word or longint from longword?

Jerry Messina
Swordfish Developer
Posts: 1473
Joined: Fri Jan 30, 2009 6:27 pm
Location: US

Re: makro parameter type

Post by Jerry Messina » Sun Sep 04, 2022 1:31 pm

I'm not aware of a way to tell if it's a signed/unsigned type.

janni
Posts: 51
Joined: Wed Aug 24, 2022 2:30 pm

Re: makro parameter type

Post by janni » Mon Sep 05, 2022 12:07 pm

Oh well, I'll have to have 2 macros instead of one then. Just thought that if it's possible to get from the compiler info about variable being declared a float and not a longword then there could as well be a way to recognize signed type.

User avatar
David Barker
Swordfish Developer
Posts: 1214
Joined: Tue Oct 03, 2006 7:01 pm
Location: Saltburn by the Sea, UK
Contact:

Re: makro parameter type

Post by David Barker » Mon Sep 05, 2022 4:22 pm

You can use overloaded inline subs. There is an assignment cost but without knowing what you are trying to do, I don't know if it's worth it...

janni
Posts: 51
Joined: Wed Aug 24, 2022 2:30 pm

Re: makro parameter type

Post by janni » Mon Sep 05, 2022 7:43 pm

Thank you David - I already have ideas to use this feature in other cases. I've built own math library to avoid some shortcomings (from my point of view) of the present one and to add diagnostics. Thanks to the effectiveness of macros in SF it produces no unnecessary overhead though obviously it will not be as convenient in use as internal math library. On the other hand, beside the built-in diagnostics and more predictable behaviour at range limits, it's faster on average, and in some cases produces results even much faster - and I need that speed advantage.

An example macro looks like this

Code: Select all

// integer multiplication y=x1*x2
public macro mul(y,x1,x2)
  if checkparam(y,cpInteger) and checkparam(x1,cpInteger) and checkparam(x2,cpInteger) then
    if sizeof(x1)=1 and sizeof(x2)=1 then
      y=x1*x2
    elseif sizeof(x1)=4 or sizeof(x2)=4 then 
      D0.asLongword=x1
      D4.asLongword=x2
      Mul_32x32_U
      y=D0.asLongword
    elseif sizeof(x1)=2 or sizeof(x2)=2 then 
      D0.asWord=x1
      D4.asWord=x2
      Mul_16x16_U()
      y=D0.asLongword
    end if
  else
    checkparam(etError, "Every parameter of mul must be an integer!")  
  end if    
end macro {mul(y,x1,x2)} 
SF compiler nicely takes care of adjusting to the resulting type and one may mix types of arguments with additional time savings in cases like

Code: Select all

mul(longword_var,word_var,word_var)
where 16-bit multiplication routine is used instead of 32-bit one as it already produces 32-bit result.

Jerry Messina
Swordfish Developer
Posts: 1473
Joined: Fri Jan 30, 2009 6:27 pm
Location: US

Re: makro parameter type

Post by Jerry Messina » Tue Sep 06, 2022 11:16 am

where 16-bit multiplication routine is used instead of 32-bit one...
Most of the multi-byte multiply routines in the library use a 'loop and add' algorithm instead of the hdw multiplier.

I'm not sure what the original rational for using a 32-bit multiply for 16x16 was since the library has code for a 16x16=32 that uses the MUL instruction, but it's been that way for a looong time. Maybe to (potentially) save code space??

A quick glance at the 16x16 MUL routine looks like it's correct. The only thing I see as a potential issue is that the two routines use different system registers for input/output. I'll take a closer look at it.

janni
Posts: 51
Joined: Wed Aug 24, 2022 2:30 pm

Re: makro parameter type

Post by janni » Tue Sep 06, 2022 4:53 pm

Jerry Messina wrote:
Tue Sep 06, 2022 11:16 am
Most of the multi-byte multiply routines in the library use a 'loop and add' algorithm instead of the hdw multiplier.
So I've noticed. Additionally, signed 16-bit multiplication uses 32x32-bit routine and it takes 810 cycles to finish while specialised routine with hardware multiplication does it in 47 cycles (just an example for some numbers). That's the most excessive example for my need of optimisation though. Other comparisons are not nearly that bad.
I'm not sure what the original rational for using a 32-bit multiply for 16x16 was since the library has code for a 16x16=32 that uses the MUL instruction, but it's been that way for a looong time. Maybe to (potentially) save code space??
It certainly saves space if one routine is used for different arguments but with PIC18 processors it seems unnecessary. Anyway, one may always force the compiler to use routines for one type of variables with typecasting.
A quick glance at the 16x16 MUL routine looks like it's correct. The only thing I see as a potential issue is that the two routines use different system registers for input/output. I'll take a closer look at it.
If you need some help (if not with coding then with testing) then I'm willing.

I've noticed that the unsigned 16-bit division routine can easily be optimised (I've replaced the SB_SVx variables with the short Dx ones):

Code: Select all

// D0,1/D4,5 -> D0(W),1 remainder in D6,7
sub DVD16X16()
  asm
    CLRF	D7		
    CLRF	D6
             
    MOVLW	16
    MOVWF	D16
  DVD16X16LP:
    RLCF	D1,W
    RLCF	D6,F
    RLCF	D7,F
    MOVF	D4,W
    SUBWF	D6,F
    MOVF	D5,W
    //BTFSS	STATUS,C
    //INCFSZ	D5,W
    //SUBWF	D7,F
    SUBWFB	D7,F
    BC		DVD16X16LP2
    MOVF	D4,W
    ADDWF	D6,F
    MOVF	D5,W
    //BTFSC	STATUS,C
    //INCFSZ	D5,W
    //ADDWF	D7,F
    ADDWFC	D7,F
    BCF		STATUS,C
  DVD16X16LP2:
    RLCF	D0,F
    RLCF	D1,F
    DECFSZ	D16,F
    BRA		DVD16X16LP
    MOVF	D0,W
  end asm
 end sub {DVD16X16}
The six commented instructions are replaced by two which leads to (potentially) 64 cycles shorter execution time.

Jerry Messina
Swordfish Developer
Posts: 1473
Joined: Fri Jan 30, 2009 6:27 pm
Location: US

Re: makro parameter type

Post by Jerry Messina » Wed Sep 07, 2022 11:06 am

Thanks for that Janni.
If there's anything else you care to share we'll be doing an update soon to add the "const data at address" feature, so now's a good time.
It certainly saves space if one routine is used for different arguments but with PIC18 processors it seems unnecessary
Saving space is usually a good thing, but in this case it's quite a bit slower, and it's only a handful of bytes anyway. I'll look at switching it over to use MUL.

janni
Posts: 51
Joined: Wed Aug 24, 2022 2:30 pm

Re: makro parameter type

Post by janni » Wed Sep 07, 2022 1:44 pm

Jerry Messina wrote:
Wed Sep 07, 2022 11:06 am
If there's anything else you care to share we'll be doing an update soon to add the "const data at address" feature, so now's a good time.
That depends on how big changes are you willing to make :wink: . More seriously, as I doubted you'd be making any, I stopped mimicking present internal math routines so my library is not a simple replacement. To tell the truth, I got a bit carried away and, exploiting the possibilities of SF macros, I've added even more detailed routines, like 16x8 and 32x8 bit multiplication. And, besides diagnostic flags, an exception mechanism that forces program to jump to a predetermined place in case of error :roll: .

Anyway, I can share the whole library and help in adjusting what you find applicable if you agree at least to preserve the diagnostic option (as an option, i.e. activated with appropriate define). SF already uses internal variable in floating-point routines so I used the same byte for statuses (last three bits are prepared to accommodate my version of floating-point math lib and may be skipped).

Code: Select all

dim FM_stat as D24 		// math statuses    
const
    _FM_IOV=0,
    _FM_FOV=1,
    _FM_FDZ=2,
    _FM_NAN=3,
    _FM_DOM=4,
    _FM_FUN=5,
    _FM_RND=6,
    _FM_SAT=7

Note that to reduce code I have most of signed routines using the unsigned ones, like

Code: Select all

//-------------- Division, 8-bit unsigned
//       Input:  D0, D4 (D13)
//       Output: D0, remainder in D8
//       Uses:   D12, D13
//               D13 bits: 0 - result to be negated
//                         2 - remainder to be negated (negative dividend)
//                         7 - signed division
public sub Div_8x8_U()
  asm-
        CLRF     D13		// unsigned
        // entry for signed division
        CLRF     D8
        
        MOVF     D4,F		// divisor is zero?
        BNZ      Div_8x8_UL1	// ...no
        MOVF     D0,F		// dividend is zero, as well?
  end asm      
  #ifdef FM_FLAGS
  asm-      
        BTFSC    STATUS,Z
        BSF      FM_stat,_FM_NAN// ...yes, set NAN flag
        BZ       $+6
        BSF      FM_stat,_FM_FDZ// ...no, set FDZ flag
        BSF      FM_stat,_FM_FOV
  end asm      
  #endif
  asm-        
        MOVLW    0x7F		//    set max value according
        BTFSC    D13,2		//    to sign of dividend, if signed
        MOVLW    0x80
        BTFSS    D13,7		//    or to FF, if unsigned
        MOVLW    0xFF
        MOVWF    D0
  end asm   
  #ifdef FM_EXCEPTIONS
  asm-
        goto     GoFMerror
  end asm     
  #else
  asm-     
        RETURN
  end asm     
  #endif 
  asm-       
      Div_8x8_UL1:
        MOVF     D0,W		// dividend is zero?
        BTFSC    STATUS,Z
        RETLW    0

        MOVLW    8		// actual division
        MOVWF    D12
        RLCF     D0,W
        RLCF     D8,F
        MOVF     D4,W
        SUBWF    D8,F
        BC       $+6
        ADDWF    D8,F
        BCF      STATUS,C
        RLCF     D0,F
        DECFSZ   D12,F
        BRA      $-18
        
        BTFSS    D13,7		// signed?
        RETURN			// ...no
        
        BTFSC    D13,2		// remainder supposed to be negative?
        NEGF     D8
        
        BTFSS    D13,0		// result supposed to be negative?
        BRA      $+6
        NEGF     D0
        RETURN
        
        BTFSS    D0,7		// overflow (-128/-1)?
        RETURN
        DECF     D0,F		// ...yes, set max positive value
				//    (remainder is zero)
  end asm      
  #ifdef FM_FLAGS
  asm-       
        BSF      FM_stat,_FM_IOV// ...set IOV flag
  end asm
  #endif        
  #ifdef FM_EXCEPTIONS
  asm-
        goto     GoFMerror
  end asm
  #endif
 end sub {Div_8x8_U}


//-------------- Division, 8-bit signed (short)
//       Input:  D0, D4
//       Output: D0, remainder in D8
//       Uses:   D12, D13
//               D13 bits: 0 - result to be negated
//                         2 - remainder to be negated (negative dividend)
//                         7 - signed division
public sub Div_8x8_S()
  asm-
        CLRF     D13
        BSF      D13,7

        BTFSS    D0,7		// negative dividend?
        BRA      $+8
        NEGF     D0
        INCF     D13,F
        BSF      D13,2		// ...yes, remainder to be negated
        BTFSS    D4,7		// negative divisor?
        BRA      $+6
        NEGF     D4
        INCF     D13,F		// if D13.0=1 then result to be negated
        goto     Div_8x8_U+2
  end asm
  BEGIN_SB_COMMENT_BLOCK()	// force compiler to include Div_16x16_U
   addressof(Div_8x8_U)
  END_SB_COMMENT_BLOCK()  
 end sub {Div_8x8_S}

Jerry Messina
Swordfish Developer
Posts: 1473
Joined: Fri Jan 30, 2009 6:27 pm
Location: US

Re: makro parameter type

Post by Jerry Messina » Wed Sep 07, 2022 2:20 pm

check your PM

Post Reply