Work at SourceForge, help us to make it a better place! We have an immediate need for a Support Technician in our San Francisco or Denver office.

Close

#2140 [PIC14] dereferencing pointers is broken

closed-fixed
5
2014-07-07
2013-03-03
Raphael Neider
No

(Copied original report by Jacob Joseph from "Re: [Sdcc-user] PIC14 Issue with IRP bank selection" on 2013-02-20:)

Hello again.

In testing more, it appears that this short example is insufficient to
reproduce the issue. Sorry for any confusion.

I couldn't make a demonstrative toy example, so I've instead attached
a pruned section of the code that originally caused me trouble. It
does illustrate incorrect use of the STATUS.IRP register.

The pointer use of interest is in set_tris():

(main.c:125 -- 137)
void set_tris( uchar pin, uchar val) {
print("TRIS: ");
printhex(*PINS[pin].tris);
print("\r\n");

if (val)
*PINS[pin].tris |= (1 << PINS[pin].pinnum);
else
*PINS[pin].tris ^= (1 << PINS[pin].pinnum);

printhex(*PINS[pin].tris);
print("\r\n");
}

The print() and printhex() function calls are there because they
happen to trigger the issue. Before code pruning, they wrote to a
circular buffer, but currently do nothing.

The code generated for access to INDF is of the form :

(main.asm:671 -- 682)
CALL __gptrget1
PAGESEL $
BANKSEL r0x100A
MOVWF r0x100A
BANKSEL FSR
MOVWF FSR
BCF STATUS,7
BANKSEL r0x100E
BTFSC r0x100E,0
BSF STATUS,7
BANKSEL INDF
MOVF INDF,W

The problem is that the register used in the BTFSC is not correctly
initialized. Depending upon the previous use of this register, the
IRP bit is set arbitrarily. For example, r0x100E = 0x79 in the
attached code, the result of:

(main.asm:649 -- 650)
MOVLW (__str_2 + 0)
MOVWF r0x100E

I'd appreciate any discussion of this.

Thanks again.
~Jacob

On Mon, 18 Feb 2013 20:03:34 -0500
Jacob Joseph <jacob@jjoseph.org> wrote:

> Hi.
>
> I'm using SDCC to target a PIC16F887 and am having some difficulty
> with correct behavior of pointers to file registers. The code
> generated by SDCC appears to set the STATUS.IRP bank selection bit
> incorrectly in some cases. In particular, indirect access to the
> TRISC register (0x87, bank 1) generates code with IRP==1, which causes
> the indireciton to act instead upon the BAUDCTL register (0x187, bank
> 3).
>
> Consider the following example:
>
> --------
> /* sdcc --use-non-free --debug-xtra -mpic14 -p16f887 test_irp.c */
>
> #define __16f887
> #define NO_BIT_DEFINES
> #define NO_LEGACY_NAMES
> #include <pic16f887.h>
>
> // These pointers must be explicitly defined as being to data space,
> // or 'check_data' in macros.inc results in them being generic, and
> // skipped.
> __data unsigned char *TRISCptr = &TRISC;
>
> void main(void) {
>
> volatile unsigned char a;
>
> a = *TRISCptr;
>
> while(1);
>
> }
> ---------
>
> The generated code sets FSR = 0x87, as it should. However, before
> accessing INDF, it sets bit 7 of STATUS. This is incorrect:
>
> MOVWF
> FSR ;id=162,key=00a,inCond:10,outCond:1,flow seq=001 ;;;
> gen.c:5556:SetIrp *{* ;; >>> gen.c:5577:SetIrp
> ;; BANKOPT1 BANKSEL dropped; STATUS present in all of FSR's banks
> BCF
> STATUS,7 ;id=165,key=00b,inCond:21,outCond:21,flow seq=001 ;;
> >>> gen.c:5580:SetIrp BANKSEL
> >>> r0x1004 ;id=207,key=00c,inCond:0,outCond:0,flow seq=001
> BTFSC
> r0x1004,0 ;id=167,key=00d,inCond:21,outCond:0,flow
> seq=001 ;<>Start of new flow, seq=0x2 ancestor = 0x1 ; from: 001 ;
> to: 003 ;; >>> gen.c:5581:SetIrp
> BSF
> STATUS,7 ;id=169,key=000,inCond:21,outCond:21,flow
> seq=002 ;<>Start of new flow, seq=0x3 ancestor = 0x1 ; from: 002
> 001 ; to: 004 ;; *** genNearPointerGet 5951
> ;; >>> gen.c:5958:genNearPointerGet
> BANKSEL
> INDF ;id=208,key=000,inCond:0,outCond:0,flow seq=003
> MOVF INDF,W ;id=172,key=001,inCond:1,outCond:14,flow
> seq=003
>
>
> I'd appreciate any help with this.
>
> Thanks.
> ~Jacob

Discussion

  • Raphael Neider
    Raphael Neider
    2013-03-03

    • milestone: --> fixed
    • status: open --> closed-fixed
     
  • Raphael Neider
    Raphael Neider
    2013-03-03

    Fixed in r8446.
    The backend failed to infer the proper operand size: dereferencing a pointer to a pointer to char (*PINS[pin].tris) resulted in the first pointer derefence (reading PINS[pin].tris from *(PINS + 0x05*pin + 2)) was byte-sized already, when in fact we needed to read 2 bytes (__data *).

    Thanks for reporting this.

    Raphael