Hi
I am comming from CCS and GNUAVR, and I am missing some background about how to manipulate bit-level registers or variables.
Typically, the pic has the ASM functions such as BCF, BSF, BTFSC, BTFSS.
I currently only see a solution to read a full byte (register or variable) to set or clear or test a bit, for set or clear write it back to the right place.
Also I would like to not only set or clear a given bit, ie RA1 or RA2, but make this variable.
Ie, I want to have a routine that sets or clears a bit 1,2,3,4... in a raw.
In GNUAVR, I know the _BV function, in CCS, you find BIT_SET(reg+var/reg,bit), BIT_CLEAR(reg+var,bit), BIT_TEST(reg+var,bit).
is this a missing function in SDCC ?
Thanks for any help.
Hi,
you can use
#define BIT_SET(VAR, BIT) VAR |= (1 << (BIT))
#define BIT_CLR(VAR, BIT) VAR &= ~(1 << (BIT))
#define BIT_TEST(VAR, BIT) ((VAR) & (1 << (BIT)))
SDCC will automatically replace single-bit accesses with the bit-manipulation instructions offered by the target architecture.
I do not know what 'reg+var' is supposed to mean, but the above should get you started.
Best regards
Raphael
thank you for the input, I must make something wrong as I tried your code couple of days ago. I just checked again and copied the 2 options I had out of an interrupt routine:
...
#define BIT_SET(VAR, BIT) VAR |= (1 << (BIT))
#define BIT_CLR(VAR, BIT) VAR &= ~(1 << (BIT))
#define BIT_TST(VAR, BIT) ((VAR) & (1 << (BIT)))
....
if(++raw==8)raw=0;
tmp=0xff;
tmp=tmp ^ (1 << raw); // enable led raw (active low)
PORTB=tmp;
//the above code works, each bit of PORTB gets 0 in a raw.
// but with your macro it would be simpler but that does not work !
// is it only limited to variables and not to registers ?
PORTB=0xff;
BIT_CLR(PORTB,raw);
// should do the same, but does not work
// I am using a 16f887
P.S. with VAR/REG I ment applicable to variables and PIC registers within SDCC.
What does "does not work" mean?
If all the PORTB-pins are 0, you might not have set them up as digital pins. Try
ANSEL=ANSELH=0;
before modifying the register (ANSELH is the important one for PORTB, see datasheet):
If you assign tmp to PORTB, the hardware overwrites all bits and you are fine.
If you clear individual bits, the hardware executes read-modify-write and -- unfortunately -- all pins read as 0 when configured as analog inputs (the power-on default, ANSEL=ANSELH=0xff).
BTW: If you want to specify the bit to modify at runtime, the hardware cannot use BCF/BSF/BTF/... because these require a literal (compile-time constant) bit index. The compiler will generate a loop for (1 << (BIT)) and modify the PORT via IORWF or ANDWF instead.
Compiler efficiency or missing optimizer flag?
Hi I discovered that the compiler is handling the bit code in different ways, is this a mistake from my side of using them or a bug/enhancement in the compiler optimizer ?
example using the following definitions:
#define BIT_SET(VAR, BIT) VAR |= (1 << (BIT))
#define BIT_CLR(VAR, BIT) VAR &= ~(1 << (BIT))
#define BIT_TEST(VAR, BIT) ((VAR) & (1 << (BIT)))
// fonctions specifics a notre example
#define test_bPousAck BIT_TEST(PousAck,0)
#define set_bAck BIT_SET(PousAck,0)
#define clear_bAck BIT_CLR(PousAck,0)
#define test_bPous BIT_TEST(PORTC,2)
char test_poussoir(void)
{
// on a pressé
if(!test_bPousAck) {if( test_bPous==0) {set_bAck; return 1;}}
// si non, toujours pressé on ne fait rien
// état pas pressé
else
if(test_bPous) clear_bAck;
// si non on ne fait rien
return 0;
}
generates:
_test_poussoir ;Function start
; 2 exit points
; .line 74; "test_bouton.c" if(!test_bPousAck) {if( test_bPous==0) {set_bAck; return 1;}}
BTFSC _PousAck,0
GOTO _00147_DS_
BANKSEL _GPIO
BTFSC _GPIO,2
GOTO _00148_DS_
BSF _PousAck,0
MOVLW 0x01
GOTO _00149_DS_
_00147_DS_
; .line 79; "test_bouton.c" if(test_bPous) clear_bAck;
BANKSEL _GPIO
BTFSS _GPIO,2
GOTO _00148_DS_
BCF _PousAck,0
_00148_DS_
; .line 81; "test_bouton.c" return 0;
MOVLW 0x00
_00149_DS_
RETURN
which is ok/perfect, but I only found this after many tests, I would prefere to write
char test_poussoir(void)
{
// on a pressé
if((!test_bPousAck)&( test_bPous==0)) {set_bAck; return 1;}
// si non, toujours pressé on ne fait rien
// état pas pressé
else
if(test_bPous) clear_bAck;
// si non on ne fait rien
return 0;
}
but this code which in my mind is equivalent generates much more code
;; Starting pCode block
_test_poussoir ;Function start
; 2 exit points
; .line 74; "test_bouton.c" if((!test_bPousAck)&( test_bPous==0)) {set_bAck; return 1;}
MOVLW 0x01
ANDWF _PousAck,W
MOVWF r0x1001
MOVF r0x1001,W
MOVLW 0x00
BTFSC STATUS,2
MOVLW 0x01
MOVWF r0x1002
MOVLW 0x04
BANKSEL _GPIO
ANDWF _GPIO,W
MOVWF r0x1001
MOVF r0x1001,W
MOVLW 0x00
BTFSC STATUS,2
MOVLW 0x01
;;1 MOVWF r0x1003
ANDWF r0x1002,F
MOVF r0x1002,W
BTFSC STATUS,2
GOTO _00145_DS_
BSF _PousAck,0
MOVLW 0x01
GOTO _00147_DS_
_00145_DS_
; .line 79; "test_bouton.c" if(test_bPous) clear_bAck;
BANKSEL _GPIO
BTFSS _GPIO,2
GOTO _00146_DS_
BCF _PousAck,0
_00146_DS_
; .line 81; "test_bouton.c" return 0;
MOVLW 0x00
_00147_DS_
RETURN
; exit point of _test_poussoir
ignoring the bit maniplulation.
Is there any trick, or am I doing any mistake using SDCC ?
Thanks for any advice
Rolf
if ((!test_bPousAck)&( test_bPous==0)) {set_bAck; return 1;}
You use bitwise AND '&', which is (in this case) pretty inefficient. Using logical AND '&&' yields much better results for me:
_test_poussoir ;Function start
; 2 exit points
; .line 20; "bit-cond.c" if ((!test_bPousAck) && (test_bPous == 0)) {
BANKSEL _PousAck
BTFSC _PousAck,0
GOTO _00108_DS_
BANKSEL _PORTC
BTFSC _PORTC,2
GOTO _00108_DS_
; .line 21; "bit-cond.c" set_bAck; return 1;
BANKSEL _PousAck
BSF _PousAck,0
MOVLW 0x01
GOTO _00111_DS_
_00108_DS_
; .line 27; "bit-cond.c" if (test_bPous)
BANKSEL _PORTC
BTFSS _PORTC,2
GOTO _00109_DS_
; .line 28; "bit-cond.c" clear_bAck;
BANKSEL _PousAck
BCF _PousAck,0
_00109_DS_
; .line 31; "bit-cond.c" return 0;
MOVLW 0x00
_00111_DS_
RETURN
Best regards
Raphael
Looks like a closed discussion.