|
|
View previous topic :: View next topic |
Author |
Message |
mathewss
Joined: 07 Aug 2008 Posts: 17
|
problem comparing #bit values |
Posted: Tue Sep 23, 2008 11:00 am |
|
|
I was trying to compress my code a little by replacing int8 flags TRUE/FALSE with #BIT fields. Seems this code change messed up my logic badly.
I did some digging and it seems that the compiler is not producing the correct ASM code.
For me the following code outputs "HI" yet my logic is clear.
Is this a bug or just my misunderstanding on how #bit can be used.
Re
Sean M
Code: |
//test.c
// PCM compiler version 4.070;3/11/2008 on linux.
// using a DLP-245PG-G board.
#include <16F877A.h> // Select the development device
#device *=16F877A
#fuses HS,WDT,PUT,NOPROTECT,NOBROWNOUT,NOLVP,NOCPD,NOWRT // Effectively just suggested programmer settings
#use delay(clock=20M)
#define PIN_WR PIN_B2
#define PIN_RD PIN_B1
#define PIN_TXE PIN_E2
#define PIN_RXF PIN_E1
#separate
char m_getc();
#separate
void m_putc(char);
#separate
BOOLEAN m_kbhit();
void main(void) {
char testbits=0;
#bit testbit0 = testbits.0
#bit testbit1 = testbits.1
testbit0=1;
testbit1=1;
if(testbit1 != testbit0) {
printf(m_putc,"HI\r\n");
}
}
char m_getc() {
char c;
while(input(PIN_RXF)==1);//wait for USB data to arrive
set_tris_d( 0xff );//all input
output_low(PIN_RD);//pull RD low
delay_us(20);
c = input_d();//read data
output_high(PIN_RD);//take RD back high
// send back a byte
return c;
}
void m_putc(char c) {
//send the byte back through the USB interface
set_tris_d( 0x0 );//all output
while(input(PIN_TXE)==1);//when TXE is high do not write
output_d(c);
delay_us(50);
output_low(PIN_WR);//PIN_B2=0
delay_us(20);
output_high(PIN_WR);//PIN_B2=1
}
BOOLEAN m_kbhit() {
return (input(PIN_RXF)!=1) ? TRUE: FALSE;
}
|
|
|
|
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Tue Sep 23, 2008 11:38 am |
|
|
I'm also stumbling over this CCS special from time to time.
In most places, CCS is treating the bit values correctly as binary value. But in some places, the compiler seems to find a way to misunderstand them, e. g. in the above comparison
Code: | (testbit1 != testbit0) |
To be treated right, unconditionally, the expression must look like
Code: | ((testbit1!=0) != (testbit0 !=0)) |
As an additional remark, the same thing happens with int1 variables, that are residing in different bit positions and logical valued expressions as
Code: | (testbit & 1 != testbit & 2) |
As far as I see, this behaviour is specicific to CCS, it also existed in V3. I regard it as non-compliant to the C standard. If you're using a lot of different processors and C-compilers, it's difficult to remember always the
eccentricities of each one.
Regards,
Frank |
|
|
mathewss
Joined: 07 Aug 2008 Posts: 17
|
|
Posted: Tue Sep 23, 2008 8:35 pm |
|
|
Thanks Frank very much what that is what I figured.
Reading the ASM code my test case used it sure didnt seem right.
The ASM output from your method looks right. Now can it be improved?
Anyone think a method exists with fewer instructions? 10 instructions to do this seems a bit much. If i find a better way I will build a macro or something to do the job in ASM.
Code: |
.................... if((testbit1!=0) != (testbit0 !=0)) {
003D: MOVLW 00
003E: BTFSC 21.1
003F: MOVLW 01
0040: MOVWF 23
0041: MOVLW 00
0042: BTFSC 21.0
0043: MOVLW 01
0044: SUBWF 23,W
0045: BTFSC 03.2
0046: GOTO 052
|
Re
Sean M |
|
|
Ttelmah Guest
|
|
Posted: Wed Sep 24, 2008 7:33 am |
|
|
I'd suggest a different approach.
I think the problem comes about because of the change in the way that 'one bit' values are propagated to eight bit values in the latter CCS forms, rather than CCS2. The #bit directive, is treated as a single bit _of_ an eight bit value, rather than an genuine 'one bit' value.
When dealing with 8bit values, the latter compilers test for true/false, by only testing the LSb of the values. This was actually done to be compliant with ANSI recommendations, but is then being misapplied to the #bit values...
Short values, don't have this problem. So (for the current compilers that support arrays of bits), use:
Code: |
union bits {
char c;
short b[8];
};
//Then in the main:
union bits testbits;
testbits.b[0]=1;
testbits.b[1]=1;
if (testbits.b[0] != testbits.b[1]) {
|
This gives:
Code: |
00068: BSF 11.0
.................... testbits.b[1]=1;
0006A: BSF 11.1
.................... if (testbits.b[0] != testbits.b[1]) {
0006C: CLRF 00
0006E: BTFSC 11.1
00070: BSF 00.0
00072: MOVF 11,W
00074: XORWF 00,W
00076: ANDLW 01
|
Which is basically as efficient as possible. :-)
Best Wishes |
|
|
mathewss
Joined: 07 Aug 2008 Posts: 17
|
|
Posted: Wed Sep 24, 2008 9:41 am |
|
|
Sweeet....
thats a huge improvement thanks. |
|
|
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Wed Sep 24, 2008 10:58 am |
|
|
Interesting. The example shows, that the compiler basically is able to treat bit variables correct and efficient, if it recognizes them, as expectable. |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|