Subject:
Re: [gnupic] SDCC 2.6.0, finds pic14 header files but not pic16
From:
Dave Tweed ####@####.####
Date:
3 Aug 2006 22:57:00 +0100
Message-Id: <E1G8lBY-0005Un-00@pop-canoe.atl.sa.earthlink.net>
[Following up to myself ...]
I wrote:
> On processors with multiple memory spaces, you must be careful to take
> advantage of whatever storage class qualifiers the compiler provides on
> both variables and the pointers that point to them, in order to give
> the compiler the information it needs to produce more highly optimized
> code.
>
> I know nothing about the details of SDCC for the PIC, but if there's a
> way to tell it that both of the pointers can only point to objects in
> on-chip RAM, I'm sure the generated code will look much better to you.
I got curious, so I downloaded, built and installed SDCC 2.6.0 to try
this out. I got:
_strcpy_ram:
; .line 6; strcpy.c void strcpy_ram (near char *des, near char *src)
MOVFF FSR2L, POSTDEC1
MOVFF FSR1L, FSR2L
MOVFF r0x00, POSTDEC1
MOVFF r0x01, POSTDEC1
MOVFF r0x02, POSTDEC1
MOVFF r0x03, POSTDEC1
MOVFF r0x04, POSTDEC1
MOVLW 0x02
MOVFF PLUSW2, r0x00
MOVLW 0x03
MOVFF PLUSW2, r0x01
MOVLW 0x04
MOVFF PLUSW2, r0x02
MOVLW 0x05
MOVFF PLUSW2, r0x03
_00110_DS_:
; .line 8; strcpy.c while ((*des++ = *src++)) ;
MOVFF r0x02, FSR0L
MOVFF r0x03, FSR0H
MOVFF INDF0, r0x04
INCF r0x02, F
BTFSC STATUS, 0
INCF r0x03, F
MOVFF r0x00, FSR0L
MOVFF r0x01, FSR0H
MOVFF r0x04, INDF0
INCF r0x00, F
BTFSC STATUS, 0
INCF r0x01, F
MOVF r0x04, W
BTFSS STATUS, 2
GOTO _00110_DS_
MOVFF PREINC1, r0x04
MOVFF PREINC1, r0x03
MOVFF PREINC1, r0x02
MOVFF PREINC1, r0x01
MOVFF PREINC1, r0x00
MOVFF PREINC1, FSR2L
RETURN
... which is pretty much what I expected. Not a huge improvement, but it
now uses 2-byte pointers and inline code to do the gets and puts of the
data bytes.
I'm a bit surprised that the documentation for the generic pointers talks
about the three distinct memory spaces, but the discussion about memory
models and pointers only talks about "near" and "far". Seems like a bit
of a disconnect there.
It's too bad (in this particular case) that the compiler reserves two of
the three FSRs for managing the C stack. I can see how that's probably
the best choice for function-calling performance in general. It would be
interesting to see whether an optimization could be introduced that would
free up FSR2 inside functions that access their arguments only once (at
the beginning) for use as a second data pointer. Then you could conceivably
get code something like this:
_strcpy_ram:
; .line 6; strcpy.c void strcpy_ram (near char *des, near char *src)
MOVFF FSR2L, POSTDEC1
MOVFF FSR1L, FSR2L
MOVFF FSR2H, POSTDEC1 ; save FSR2 for caller
MOVF PREINC2, W ; dummy access to adjust pointer
MOVFF PREINC2, FSR0L ; copy arguments directly to FSRs
MOVFF PREINC2, FSR0H
MOVF PREINC2, W ; special handling as FSR2 switches
MOVFF PREINC2, FSR2H ; from one use to another
MOVWF FSR2L
_00110_DS_:
; .line 8; strcpy.c while ((*des++ = *src++)) ;
MOVF POSTINC2, W ; do the move as two steps
MOVWF POSTINC0 ; so we can examine the data byte
BNZ _00110_DS_
MOVFF PREINC1, FSR2H ; restore FSR2
MOVFF PREINC1, FSR2L
RETURN
I'm pretty sure this would work even with interrupts enabled, as long as
the ISRs only use FSR1 and preserve FSR2 without assuming anything about
its contents.
I can't imagine what it would take to describe these optimizations to
SDCC, and this serves mainly to illustrate why you write your critical
low-level routines in assembly on most 8-bit machines, especially the
ones that aren't particularly "C-friendly". Use the C code mainly to
glue together low-level functions into larger modules and systems.
-- Dave Tweed