Jump to content
Mike McLaren

Efficient Way To Twos Complement A Signed Int?

Recommended Posts

Hi guys,

 

What's the most efficient way to twos compliment a signed int, please? I've tried a couple ways but it uses considerably more code than I'm used to with assembly language. Why the use of CompTempVar's?

 

Thanks in advance, Mike

 

		 binl = 0 - binl;	   // twos complement the temperature
00DE  0834   MOVF gbl_binl, W
00DF  3C00   SUBLW 0x00
00E0  00C5   MOVWF CompTempVar20
00E1  0935   COMF gbl_binl+D'1', W
00E2  00C6   MOVWF CompTempVar21
00E3  1803   BTFSC STATUS,C
00E4  0AC6   INCF CompTempVar21, F
00E5  0845   MOVF CompTempVar20, W
00E6  00B4   MOVWF gbl_binl
00E7  0846   MOVF CompTempVar21, W
00E8  00B5   MOVWF gbl_binl+D'1'

	 binl = ~binl; binl++;  //
00E9  0934   COMF gbl_binl, W
00EA  00C5   MOVWF CompTempVar22
00EB  0935   COMF gbl_binl+D'1', W
00EC  00C6   MOVWF CompTempVar23
00ED  0845   MOVF CompTempVar22, W
00EE  00B4   MOVWF gbl_binl
00EF  0846   MOVF CompTempVar23, W
00F0  00B5   MOVWF gbl_binl+D'1'
00F1  0AB4   INCF gbl_binl, F
00F2  1903   BTFSC STATUS,Z
00F3  0AB5   INCF gbl_binl+D'1', F

Share this post


Link to post
Share on other sites

Looks like you have optimisation disabled. Here is what I got:

 

 

signed int binl;
binl = ~binl; binl++; 
004E  09A0   COMF main_1_binl, F
004F  09A1   COMF main_1_binl+D'1', F
0050  0AA0   INCF main_1_binl, F
0051  1903   BTFSC STATUS,Z
0052  0AA1   INCF main_1_binl+D'1', F

 

Regards,

Pavel

Share this post


Link to post
Share on other sites

Hi Pavel,

 

How do I turn it on? I thought the #pragma in the code below was turning it on. I'm using v7.05 inside MPLAB 8.84.

 

 

   #include <system.h>

  #pragma DATA _CONFIG1, _FOSC_INTOSC & _WDTE_OFF & _MCLRE_OFF
  #pragma DATA _CONFIG2, _PLLEN_OFF & _LVP_OFF

  #pragma CLOCK_FREQ 8000000	   // 8 MHz INTOSC
  #pragma OPTIMIZE "a"

Edited by Mike McLaren

Share this post


Link to post
Share on other sites

Hi

 

I'm not sure about the precedence of #pragma agaisn't command-line options, maybe you should verify the last ones.

In MPLAB open the menu Project->Buil Options.

Verify either global "project" options or the specific "C" file options.

These are the ones that are applied to the compiler and linker command lines.

 

Best regards

 

Jorge

Edited by JorgeF

Share this post


Link to post
Share on other sites

Hi Jorge,

 

Under "Project:Build Options for Project" the [on] checkbox for "Optimization" is checked in both the <BoostLink Linker> tab and the <BoostC C Compiler for PIC16> tab. Under "Project:Build Options for File" there is only one tab labeled <BoostC C Compiler for PIC16> and the [on] checkbox for "Optimization" is also checked there.

Share this post


Link to post
Share on other sites

The code that I posted was produced with optimisation level 2 which is the default one. So in theory you don't need to specify any optimisation arguments to get similar result.

 

Try to remove the optimisation pragma. Does MPLAB show you the compiler command line? If it does check that it does not use any -On command line argument (except -O2 which is ok).

 

Note that the optimisation pragma works an function level. This means that it will only apply for a function that follows the pragma statement.

 

Regards,

Pavel

Share this post


Link to post
Share on other sites

Hi Pavel,

 

In the output window during a build operation both the compiler and linker command lines are shown, and both show the use of a '-O1' parameter. This '-O1' parameter also seems to be the default when I look in the <project> <build options> <project> and <sourcefilename> dialog boxes, and there doesn't seem to be a way to change the parameter.

 

It doesn't appear that '-O2' is the default optimization level, at least when BoostC is being used in MPLAB (version 8.84).

 

Is there a fix for this problem, please?

 

Cheerful regards, Mike

 

post-5933-0-38871400-1336953873_thumb.jpg

Edited by Mike McLaren

Share this post


Link to post
Share on other sites

I see. Try to add -O2 into the compiler "Additional command line options" field. If MPLAB puts it after -O1 than the last one will be used. If this doesn't work add #pragma OPTIMIZE "2" before the function you want to optimise and this will apply level 2 optimisation to it.

 

Regards,

Pavel

Share this post


Link to post
Share on other sites

Hi

 

I made the same tests and the situation is

 

In MPLAB 8 optimization optios are only "ON" (-O1)and "OFF" (-O1) (checkboxes), the extra data column is disabled.

If I put -O2 in the extra command-line options -O switch appears twicw in the issued command line.

 

Executing: "C:\Program Files (x86)\SourceBoost\boostc_pic16.exe" LEDS_A.c -O0  -W1  -t 16F886 -O2

 

 

It seems MPLAB8 integration needs a small review.

 

Best regards

Jorge

Edited by JorgeF

Share this post


Link to post
Share on other sites

Hi Jorge,

 

Those are the same results I am getting. Thank you for double checking.

 

Adding -O2 in the 'additional command line options' field in all three dialog boxes does not appear to do anything. That is, the -O2 shows up at the end of the command lines in the output window but the optimization is still missing in the code.

 

Cheerful regards, Mike

Edited by Mike McLaren

Share this post


Link to post
Share on other sites

If you leave the optimization boxes un-ticked the program defaults to level 2 optomization, if you tick the boxes it selects level 1. Unfortunatlty MPLAB comes up in the default state with the optimization boxes ticked and hence level 1 optimization but as long as you aware of the problem it's no great inconviniance to un-tick the boxes at the start of each project.

Share this post


Link to post
Share on other sites

That's not happening, Alex. Did you try it?

 

When you un-tick the check boxes -O0 shows up as the default parameter in all three of those dialog boxes and here's the output from the build;

 

 

Clean: Deleting intermediary and output files.

Clean: Done.

Executing: "C:\Program Files (x86)\SourceBoost\boostc_pic16.exe" 16F1828_DS18B20.c -O0 -W1 -t 16F1828

BoostC Optimizing C Compiler Version 7.05 (for PIC16 architecture)

http://www.sourceboost.com

Copyright© 2004-2011 Pavel Baranov

Copyright© 2004-2011 David Hobday

 

Single user Lite License (Unregistered) for 0 node(s)

Limitations: PIC12,PIC16 max code size:2048 words, max RAM banks:2, Non commercial use only

 

 

16F1828_DS18B20.c

 

success

Executing: "C:\Program Files (x86)\SourceBoost\boostlink_pic.exe" "C:\Users\Michael\Documents\PIC Projects\4-Digit Experiments\16F1828_DS18B20.obj" -O0 -p "16F1828 DS18B20" -t 16F1828

BoostLink Optimizing Linker Version 7.05

http://www.sourceboost.com

Copyright© 2004-2011 Pavel Baranov

Copyright© 2004-2011 David Hobday

 

 

Optimisation level:0 - Off

Building CASM file

Memory Usage Report

===================

RAM available:256 bytes, used:63 bytes (24.7%), free:193 bytes (75.3%),

Heap size:113 bytes, Heap max single alloc:95 bytes

ROM available:4096 words, used:815 words (19.9%), free:3281 words (80.1%)

 

 

 

success

Loaded C:\Users\Michael\Documents\PIC Projects\4-Digit Experiments\16F1828 DS18B20.COF.

BUILD SUCCEEDED: Mon May 14 09:57:09 2012

 

 

Darn, I was hoping this would be an easy fix or a procedural problem on my part...

 

Cheerful regards, Mike

Share this post


Link to post
Share on other sites

Hi all

 

Alex is write.

 

Mike, you have to "untick" (leave clear) both the "On" and the "Off" checkboxes.

At first as they behave similarly to radio buttons, I didn't even try to clear both of them.

 

 

Best regards

 

Jorge

Share this post


Link to post
Share on other sites

Hi guys,

 

I'm afraid it's not doing what you say it supposed to do on my machine (Windows 7 laptop, MPLAB v8.84, BoostC v7.05)...

 

With both the <on> and <off> check boxes un-ticked (off) in all three dialogs here's what the command lines look like in the output window when I perform a build;

 

Executing: "C:\Program Files (x86)\SourceBoost\boostc_pic16.exe" 16F1828_DS18B20.c -W1  -t 16F1828
Executing: "C:\Program Files (x86)\SourceBoost\boostlink_pic.exe"  "C:\Users\Michael\Documents\PIC Projects\4-Digit Experiments\16F1828_DS18B20.obj" -p "16F1828 DS18B20" -t 16F1828

 

Then, leaving both <on> and <off> check boxes un-ticked, I tried adding an additional command line parameter in all three dialogs and here's what the command lines looked like in the output window during a build;

 

Executing: "C:\Program Files (x86)\SourceBoost\boostc_pic16.exe" 16F1828_DS18B20.c -W1  -t 16F1828 -O2

Executing: "C:\Program Files (x86)\SourceBoost\boostlink_pic.exe"  "C:\Users\Michael\Documents\PIC Projects\4-Digit Experiments\16F1828_DS18B20.obj" -p "16F1828 DS18B20" -t 16F1828 -O2

 

Unfortunately, the -O2 optimization is not working. Both procedures generate the same of program memory and that "twos complement" code is still using 11 words of memory instead of 5 words.

 

What do you think guys? I appreciate the help. Would you like to see a sample source file or zipped MPLAB project file?

 

Cheerful regards, Mike

Edited by Mike McLaren

Share this post


Link to post
Share on other sites

I didn't have this optimization problem when I was running BoostC v6.97 so could this just be a problem with the BoostC version 7 implementation?

Share this post


Link to post
Share on other sites

Hi Mike

 

All the testing I made along this thread was done indistinctively in two PCs, at home or at the office, but the results where allways the same that Pavel posted above.

 

PC 1: Win Vista 32 bit + MPLAB 8.83 + BoostC 7.05

PC 2: Win 7 Pro 64 bit + MPLAB 8.80 + BoostC 7.05

 

The command lines you show in your post are consistent with your options in the project.

If there are no command-line switches neither #pragmas controling the optimization level, BoostC defaults to maximum (same as -O2).

 

If you feel like it, just post a zip with your samples, I will give it a try in one, or both, of my machines.

 

 

Best regards

Jorge

Edited by JorgeF

Share this post


Link to post
Share on other sites

Thank you for the offer, Jorge:

 

I created a simple small project with just a few lines of code and, son-of-a-gun, optimizing worked. However, still "no joy" when I tried again with my other programs. Anyway, here's a zip'ed project for PIC16F1828 that exhibits the problem. The output for the "binl = -binl;" instruction uses eleven words instead of the optimized five words, no matter what I have tried so far.

 

Thank you for your help and kind consideration.

 

Cheerful regards, Mike

 

16F1828 DS18B20 Project.zip

Share this post


Link to post
Share on other sites

Mike,

 

Try taking out the whole asm block immediately after your problem line (binl is used there too) and see what happens.

 

Not offering a solution but maybe just a clue as to what is going on!

 

BTW shouldn't if(negflag = binl.15) be if(negflag == binl.15)?

 

Regards

 

davidb

Share this post


Link to post
Share on other sites

Hi

 

It looks like David hit the spot.

Comenting out the ASM block, leads to an optimized code in the "binl = -binl" statement.

 

The diference in the generated code is the use of a temporary word during the complement operation.

With asm block:

temp <-- -binl; binl <-- temp;

Without the asm block:

binl <-- - binl;

 

I don't know how or why ASM block is afecting the optimization algorithms, but it definitelly is.

 

Just while writing this post, I made one more test.

I removed the comment of the ASM block as a whole and commented out only the instructions refering to "binl".

"Et voilá", the complement gets optimized.

So we can conclude that is the explicit mention of the "binl" in the ASM instructions that is preventing the optimization of the "binl = -binl" statement.

 

 

Best regards

Jorge

 

PS: After reading the comment on Mike code, I think the " if(negflag = binl.15) " is intentional and not an error. Makes code a little harder to understand, but is perfectly legal. ;)

Edited by JorgeF

Share this post


Link to post
Share on other sites

Hi Guys,

 

Have you tried putting an underscore before the asm ( _asm {...} ).

 

Cheers

 

Reynard

Share this post


Link to post
Share on other sites

Hi

 

BINGO!!!

Reynard just put the finger where it hurts.

 

 

In fact using plain "asm" or "_asm" makes a diference, confirmed by some more testing.

 

As stated in the BoostC manual at beginning of page 64, is exactly the optimizations features that get afected by this small detail.

The odd detail is that use of "asm" afected optimizations outside of the ASM block, and in this particular case before it.

 

But anyway, Mike got is problem sorted out and I learned a couple more things also, so "its been a good day". :)

 

Best regards

Jorge

Share this post


Link to post
Share on other sites

Hi Guys,

 

It looks like the compiler is turning off optimizing during a "plain" asm block but is not restoring it at the end of the block.

 

Something for the todo list.

 

Cheers

 

Reynard

Share this post


Link to post
Share on other sites

Thank you Gentlemen. I really appreciate your effort and help.

 

Now I just need to find a better way to convert a binary number to decimal (0000..9999) or packed BCD (0x0000..0x9999) that doesn't cost 200 words of memory (grin).

 

Cheerful regards, Mike

Edited by Mike McLaren

Share this post


Link to post
Share on other sites

Hi MIke

 

I didn't did any digging in your code, but my first aproach to converting Bin->BCD is the shift/add 3 algorithm

http://www.johnloomi...bin_to_bcd.html

or in PDF

http://people.ee.duk...D_Converter.pdf

Its easy to implement in a loop form and can be adjusted to whatever number of digits you want .

 

There is allways the option to use a couple of lookup tables if you can't spare the processing time for the convertion.

 

 

Best regards

 

Jorge

Edited by JorgeF

Share this post


Link to post
Share on other sites

Hi Guys,

 

Can I impose on you kind folks again, please? The following few lines of code from my updated program (attached below) appears to use 191 words of program memory space (ouch!).

 


   thou = bin/1000;
   thou %= 10;
   huns = bin/100;
   huns %= 10;
   tens = bin/10;
   tens %= 10;
   ones = bin%10;

 

Since the bin variable is signed int type the compiler output includes code to twos complement a negative value in each of those division instructions. But the bin variable has already been converted to an absolute just before this set of instructions.

 

Do you kind folks have any suggestions for improving the overhead for this binary-to-decimal conversion code, please?

 

TIA and cheerful regards, Mike

16F1828 DS18B20 Project.zip

Share this post


Link to post
Share on other sites

Hi

 

The compiler doesn't now, and doesn't care with what your code is doing with the variables content.

It just cares with the way variables are declared.

 

I made a quick test and with the following change the code size reduce from 112 to 61 program words.

 


{
u16 xx=bin;

   thou = xx/1000;		 //
   thou %= 10;			  //
   huns = xx/100;		  //
   huns %= 10;			  //
   tens = xx/10;		   //
   tens %= 10;			  //
   ones = xx%10;		   //
}

.

 

The result is

 


{
unsigned int xx=bin;
01A5  0826	  MOVF gbl_bin, W
01A6  00C6	  MOVWF main_85_xx
01A7  0827	  MOVF gbl_bin+D'1', W
01A8  00C7	  MOVWF main_85_xx+D'1'


   thou = xx/1000;		 //
01A9  0846	  MOVF main_85_xx, W
01AA  00C8	  MOVWF __div_16_1_00003_arg_a
01AB  0847	  MOVF main_85_xx+D'1', W
01AC  00C9	  MOVWF __div_16_1_00003_arg_a+D'1'
01AD  30E8	  MOVLW 0xE8
01AE  00CA	  MOVWF __div_16_1_00003_arg_b
01AF  3003	  MOVLW 0x03
01B0  00CB	  MOVWF __div_16_1_00003_arg_b+D'1'
01B1  20E9	  CALL __div_16_1_00003
01B2  084F	  MOVF CompTempVarRet137, W
01B3  00A0	  MOVWF gbl_owbuff

   thou %= 10;			  //
01B4  0820	  MOVF gbl_owbuff, W
01B5  00C8	  MOVWF __rem_8_8_00000_arg_a
01B6  300A	  MOVLW 0x0A
01B7  00C9	  MOVWF __rem_8_8_00000_arg_b
01B8  20BB	  CALL __rem_8_8_00000
01B9  084C	  MOVF CompTempVarRet143, W
01BA  00A0	  MOVWF gbl_owbuff

   huns = xx/100;		  //
01BB  0846	  MOVF main_85_xx, W
01BC  00C8	  MOVWF __div_16_1_00003_arg_a
01BD  0847	  MOVF main_85_xx+D'1', W
01BE  00C9	  MOVWF __div_16_1_00003_arg_a+D'1'
01BF  3064	  MOVLW 0x64
01C0  00CA	  MOVWF __div_16_1_00003_arg_b
01C1  01CB	  CLRF __div_16_1_00003_arg_b+D'1'
01C2  20E9	  CALL __div_16_1_00003
01C3  084F	  MOVF CompTempVarRet137, W
01C4  00A1	  MOVWF gbl_owbuff+D'1'

   huns %= 10;			  //
01C5  0821	  MOVF gbl_owbuff+D'1', W
01C6  00C8	  MOVWF __rem_8_8_00000_arg_a
01C7  300A	  MOVLW 0x0A
01C8  00C9	  MOVWF __rem_8_8_00000_arg_b
01C9  20BB	  CALL __rem_8_8_00000
01CA  084C	  MOVF CompTempVarRet143, W
01CB  00A1	  MOVWF gbl_owbuff+D'1'

   tens = xx/10;		   //
01CC  0846	  MOVF main_85_xx, W
01CD  00C8	  MOVWF __div_16_1_00003_arg_a
01CE  0847	  MOVF main_85_xx+D'1', W
01CF  00C9	  MOVWF __div_16_1_00003_arg_a+D'1'
01D0  300A	  MOVLW 0x0A
01D1  00CA	  MOVWF __div_16_1_00003_arg_b
01D2  01CB	  CLRF __div_16_1_00003_arg_b+D'1'
01D3  20E9	  CALL __div_16_1_00003
01D4  084F	  MOVF CompTempVarRet137, W
01D5  00A2	  MOVWF gbl_owbuff+D'2'

   tens %= 10;			  //
01D6  0822	  MOVF gbl_owbuff+D'2', W
01D7  00C8	  MOVWF __rem_8_8_00000_arg_a
01D8  300A	  MOVLW 0x0A
01D9  00C9	  MOVWF __rem_8_8_00000_arg_b
01DA  20BB	  CALL __rem_8_8_00000
01DB  084C	  MOVF CompTempVarRet143, W
01DC  00A2	  MOVWF gbl_owbuff+D'2'

   ones = xx%10;		   //
01DD  0846	  MOVF main_85_xx, W
01DE  00C8	  MOVWF __rem_16_1_00004_arg_a
01DF  0847	  MOVF main_85_xx+D'1', W
01E0  00C9	  MOVWF __rem_16_1_00004_arg_a+D'1'
01E1  300A	  MOVLW 0x0A
01E2  00CA	  MOVWF __rem_16_1_00004_arg_b
01E3  01CB	  CLRF __rem_16_1_00004_arg_b+D'1'
01E4  20CB	  CALL __rem_16_1_00004
01E5  084F	  MOVF CompTempVarRet139, W
01E6  00A3	  MOVWF gbl_owbuff+D'3'

}

 

 

Even so, I think that, in terms of code size, you can do a better job if you change it to a loop of sucessive divisions by 10.

If you look closely to the abose code generated by the compiler, you can see a clear source of overhead.

The succesive calls to the library functions "div_16" and "rem_16", generate a lot of code just for parameter passing.

 

 

I recovered this algorithm from one of my own programs.

Variable names/types are corrected to fit your definitions.

 

{
u16 xx = bin;

for(u08 i=3; i; i--)
	{
	owbuff[i] = xx % 10;
	xx /= 10;
	}
owbuff[0] = xx;
}

 

Applied this to your program and the compiler generated 42 program words for it.

 

 

 

 

Best regards

Jorge

Edited by JorgeF

Share this post


Link to post
Share on other sites

Hi Jorge:

 

Thank you very much.

 

I did try using an unsigned int and I saw the same improvement you did. I just defined an unsigned bin16 variable at the same absolute location as the signed bin variable. Code sized dropped from 112 words, plus 79 words for library code, down to 62 words, plus 79 words. Speed improved too, going from 1903 cycles down to 1783 cycles. So total savings was 50 words.

 

I like your loop code but while it uses only 39 words (in my program), the overhead is 101 words when you factor in the rem_16_1 and div_16_1 library code. Still, that's a significant improvement, going from 191 words total down to 101 words. That's a savings of 90 words but the processing time increases to ~2300 cycles.

 

This afternoon I tried a small 17 word (isochronous) assembly language routine and code that mimics the divide and modulo functions in your loop example. Total is 35 words (no library code required) and it processes the four digits in only 750 cycles. It's not very elegant, and certainly not very C'ish, but it does come a lot closer to the kind of performance and overhead I was hoping for.

 

Cheerful regards, Mike

 


      huns = b2d16();          //
      huns |= (b2d16() << 4);  //
      ones = b2d16();          //
      ones |= (b2d16() << 4);  //
      disphi = huns;           //
      displo = ones;           //


  char b2d16()                 //
  { u08 ctr = 16;              // repeat for 16 bits
    u08 rem = 0;               //
  div10:
    asm rlf    _bin+0,W        //
    asm rlf    _bin+1,F        //
    asm rlf    _rem,F          // move msb into 'rem'
    asm movlw  10              //
    asm subwf  _rem,W          // does 10 go in?
    asm skpnc                  // no, skip, else
    asm movwf  _rem            // update 'rem'
    asm rlf    _bin+0,F        // capture borrow bit
    asm decfsz _ctr,F          //
    asm bra    div10           //
    return rem;                // returns successive least
  }                            // significant %10 digits

Edited by Mike McLaren

Share this post


Link to post
Share on other sites

Ray,

 

Thank you for the message. As I mentioned in my reply, you should post your questions here for the benefit of other Forum members. For now, I'll try to give a brief answer to your question about code to implement CRC8 and if you need more details, please reply here, or start a new thread.

 

I did add code to the experimental program for CRC8 but instead of using a separate function I decided to implement bit level cumulative CRC8 code in the owrw() "bit" function to reduce memory and processing overhead. The code uses 8 words of memory, 1 variable, and zero cycles if you consider that the code executes during the delay used to fill-out the 60-usec read/write bit slot timing. I think I came up with relatively simple CRC8 code;

 

 

 /*                                                                  *
  *  K8LH cumulative CRC8 calculation (preserves data bit in Carry)  *
  *                                                                  */
  //asm clrf   _wreg           // wreg already 0 (see above)
    asm rlf    _wreg,W         // save C (wreg = 0x00 or 0x01)
    asm xorwf  _crc,F          // xor b0 bits, result in 'crc'
    asm lsrf   _crc,F          // zero result from xor (C=0)?
    asm skpnc                  // yes, skip, else
    asm iorlw  0x18            // wreg = x8+x5+x4+1 poly and b0 bit
    asm rrf    _wreg,W         // restore C (wreg = 0x8C or 0x00)
    asm xorwf  _crc,F          // apply the polynomial, or not
 /*                                                                  *
  *  wrap up the 60-usec "r/w slot"                                  *
  *                                                                  */
  //asm movlb  owtris          // bank 1 (inserted by compiler)
    asm bsf    owtris,owpin    // set owpin to hi-z '1' @ 61-usecs
    intcon.GIE = 1;            // interrupts on
  }                            //

 

Please let me know if you have additional questions.

 

Cheerful regards, Mike

Share this post


Link to post
Share on other sites

Join the conversation

You are posting as a guest. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...

×
×
  • Create New...