Hi Jonathan,

> I'm trying to get the following assignment to work with the PIC16 port
> of sdcc. Is there a reason the sdcc assembler is so complex and more
> to the point a reason for it not working?
>
> PORTBbits.RB4 = PORTBbits.RB0
>
> The sdcc generated binary doesn't seem to work and generates the
> following assembler:
> 0000d2   6a00     clrf   0, 0                 CLRF    r0x00
> 0000d4   b081     btfsc  0x81, 0, 0           BTFSC    _PORTBbits, 0
> 0000d6   2a00     incf   0, 0x1, 0            INCF    r0x00, F
> 0000d8   5000     movf   0, 0, 0              MOVF    r0x00, W
> 0000da   0b01     andlw  0x1                  ANDLW    0x01
> 0000dc   38e8     swapf  0xe8, 0, 0           SWAPF    WREG, W
> 0000de   6ef4     movwf  0xf4, 0              MOVWF    PRODH
> 0000e0   5081     movf   0x81, 0, 0           MOVF    _PORTBbits, W
> 0000e2   0bef     andlw  0xef                 ANDLW    0xef
> 0000e4   10f4     iorwf  0xf4, 0, 0           IORWF    PRODH, W
> 0000e6   6e81     movwf  0x81, 0              MOVWF    _PORTBbits

This is a more complicated case than one might believe due to PORTB
being volatile, but even if you used non-volatile variables, the
generated code would be the same so I will go into more details on the
volatility problem here.

The real problem is that the compiler is not smart enough to take the
left-hand side as a (one-of-two-values) pseudo-literal value; however,
only literal assignments to a single bit are optimized using BCF/BSF
instructions. The compiler first reads the bitfield, turns its value
into a char (or int), and then assigns the general integer value to the
bitfield.

If I find the time, I will try to have it optimized into
; read PORTBbits.RB0
CLRF    r0x00
BTFSC   _PORTBbits, 0
INCF    r0x00, F
MOVF    r0x00, W
ANDLW   0x01
; assign to PORTBbits.RB4
BTFSC   WREG, 0
BSF    _PORTBbits, 4
BTFSS   WREG, 0
BCF    _PORTBbits, 4


The even better (optimal?) variant

MOVF    _PORTBbits, W
BTFSC   WREG, 0
BSF     _PORTBbits, 4
BTFSS   WREG, 0
BCF     _PORTBbits, 4

is out of reach for the compiler.
Note: PORTBbits must be copied into WREG in order to guarantee a
consistent value on the following 2 bittests; required by PORTB being
volatile...

Using the semantically equivalent

void t4(void) {
  // TRISB and PORTB setup skipped for brevity
  while (1) {
    if (PORTBbits.RB0) {
      PORTBbits.RB4 = 1;
    } else {
      PORTBbits.RB4 = 0;
    }
  }
}

and --optimize-df I get the pretty good

_t4:
_00133_DS_:
;       .line   53; port.c      if (PORTBbits.RB0) {
        BTFSS   _PORTBbits, 0
        BRA     _00130_DS_
;       .line   54; port.c      PORTBbits.RB4 = 1;
        BSF     _PORTBbits, 4
        BRA     _00133_DS_
_00130_DS_:
;       .line   56; port.c      PORTBbits.RB4 = 0;
        BCF     _PORTBbits, 4
        BRA     _00133_DS_
        RETURN

taking 5 (if true) or 6 cycles per iteration.

> I had a colleague send me the Hi-TECH assembler instruction! which
> does work.
>
> 3FF8    8881     BSF 0xf81, 0x4, ACCESS

Unconditionally setting RB4 is not what you asked for in the program,
there is obviously some conditional code missing; probably similar to
what t4() above yields, though possibly using more BTFSx and less BRA.

I hope the workaround is kind'a acceptable,
Raphael





-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/
_______________________________________________
Sdcc-user mailing list
Sdcc-user@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/sdcc-user

Reply via email to