[PicForth] Large amounts of text seem to cause PicForth to generate bad code

David McNab david at rebirthing.co.nz
Thu Dec 2 15:13:31 CET 2004


Alex Holden wrote:
>> unless you can post some code.
> Unfortunately there's about 1200 lines of it and creating a minimal 
> example which demonstrates this particular problem is easier said than 
> done.

My heart does go out to you. I have the 'pleasure' of putting out 
similar fires on occasion with my code - which is at 5000 lines of 
source and growing.

> Note that it's not crashing when it tries to 'type' the help text; in 
> fact it crashes even if the program doesn't call 'type' at all. And the 
> crash symptoms are different every time I reset it, but always 
> exceptionally weird.

Now, it's smelling like an electrical issue.

A couple of weeks ago, I was wondering why my proto board was giving 
weird random results, particularly if I moved my hand to within a few cm 
of the board. Turned out that I hadn't wired the pullup resistor to 
MCLR, so it was a fluke the board worked at all.

> Sometimes (usually) it prints random jibberish to 
> the serial port; sometimes it doesn't. Sometimes the ISR dies (as 
> evidenced by the 'heartbeat' LED stopping); sometimes it doesn't. 
> Sometimes it even starts printing the bootloader question mark prompt 
> over and over again in an infinite loop.

Yep, you're definitely in the eye of a maelstrom.

> This time it's 
> proving exceptionally difficult, largely due to the randomness of the 
> symptoms (giving me no clue where to look) and the amount of code 
> involved (over 2000 instructions).
> 
> I think I'm going to have to try harder to come up with a minimal 
> example, but I suspect 'minimal' will still require something that uses 
> more than 2Kwords of program memory.

I've got my code broken up into driver modules plus main application 
module. And for every driver, I've got a separate test program. This has 
saved my sanity more times than I dare to count.

What you're seeing is that your program is going off into the boonies in 
different ways.

Without seeing your code, I can only offer some general 
philosophy/encouragement (and some diagnostic code - attached)

1) there is a clear and definite cause of the problems you're seeing, 
and it's most likely very simple
2) sometimes it requires an altered state of consciousness (or at least 
shifting your cognitive processes out of the regular groove) to see 
what's going wrong
3) suspect everything - leave no stone unturned
4) hopefully, you've got your code structured so that you can disable 
certain bits without significantly altering control/data flow in the 
rest of your system. For instance:
  - try disabling all interrupts
  - try disabling all on-chip devices (eg, ADC, USART, etc

5) more specific - if you've got any code words, be sure that you're 
setting bank bits and PCLATH correctly
6) In the disassembly output, inspect all boundaries - 256-byte 
boundaries, and 2k boundaries - ensuring that you're not getting burned 
by the PICs nefarious data and program memory discontiguities
7) rename some of your functions, and insert stub replacements which do 
nothing but consume the right amount of stack and return something plausible
8) this one has saved my soul - I've got a routine called '.s' which 
dumps out the stack to tty (modules attached). stack leakage has caused 
probably 50% of the weird bugs I've seen
9) you /can/ fix it :)

Hope this helps

-- 
Cheers
David
-------------- next part --------------
\ @+leo-ver=4
\ @+node:@file libtty.fs
\ @@language forth

\ libtty.fs
\ 
\ driver for on-chip USART

\ @+others
\ @+node:includes
needs picflash.fs
needs libstrings.fs

needs libttycore.fs

\ @-node:includes
\ @+node:tty.poll
\ ( -- 1|0 ) depending on whether incoming char is available

: tty.poll

    rcif bit-set?
;
   
\ @-node:tty.poll
\ @+node:tty.puts
\ puts a string to tty
\ (string via 'c"' literals)

: tty.puts ( -- )

    begin
        str-char dup
    while
        tty.putc
    repeat
    drop
;

\ @-node:tty.puts
\ @+node:tty.putsl
\ puts, followed by crlf

: tty.putsl
    tty.puts
    tty.crlf
;

\ @-node:tty.putsl
\ @+node:tty"
meta

: tty"
    meta> c" tty.puts
;

: ttyl"
    meta> c" tty.putsl
;

target

\ @-node:tty"
\ @-others

\ @-node:@file libtty.fs
\ @-leo
-------------- next part --------------
\ @+leo-ver=4
\ @+node:@file libttycore.fs
\ @@language forth

\ libttycore.fs
\ 
\ just the core tty routines - tty.init, tty.getc, tty.putc

\ @+others
\ @+node:pin assignments
6 pin-c tty.pin-TX
7 pin-c tty.pin-RX

\ @-node:pin assignments
\ @+node:constants
\ constants for various baudrates and clock frequencies
\ (refer datasheet, table 10-4)

$81 constant 9k6 at 20MHz
$40  constant 19k2 at 20MHz
$4a  constant 28k8 at 20MHz
$24  constant 33k6 at 20MHz
$14  constant 57k6 at 20MHz

\ set your baudrate here by uncommenting ONE of the below

\ 9k6 at 20MHz constant tty.baudrate
\ 19k2 at 20MHz constant tty.baudrate
\ 28k8 at 20MHz constant tty.baudrate
\ 33k6 at 20MHz constant tty.baudrate
57k6 at 20MHz constant tty.baudrate

\ @-node:constants
\ @+node:variables
variable tty.char
\ @-node:variables
\ @+node:tty.init
\ code foo
\ 	porta adjust-bank clrf
\ 	eedata adjust-bank clrf
\ 	0 adjust-bank drop
\ 	return
\ end-code

: tty.init

\    reg-rp0      bcf    \ BCF   STATUS,5
\    reg-rp1      bcf    \ BCF   STATUS,6
\    $40          movlw  \ MOVLW .64
\    portc        movwf  \ MOVWF PORTC
    $40 portc !
    
    \ banksel TRISA       ; bank1
\    reg-rp0      bsf    \ BSF   STATUS,5
\    reg-rp1      bcf    \ BCF   STATUS,6

    \ set RC6 & RC7 as input
\    trisc 6      bsf    \ BSF   TRISC,6
\    trisc 7      bsf    \ BSF   TRISC,7
    tty.pin-RX >input
    tty.pin-TX >input

    \ BAUD RATE SETTINGS - see BAUDRATE equates above
\    tty.baudrate movlw   \ MOVLW BAUDRATE
\    spbrg        movwf  \ MOVWF SPBRG
    tty.baudrate spbrg !
    
    \     movlw     b'00100100'    ; brgh = 1
\    $24          movlw  \ MOVLW .36
\    txsta        movwf  \ movwf     TXSTA           ; enable Async Transmission, set brgh
    $24 txsta !

    \ banksel RCSTA       ; bank0
\    reg-rp0      bcf    \ BCF   STATUS,5
\    reg-rp1      bcf    \ BCF   STATUS,6
\    $90          movlw  \ MOVLW .144
\    rcsta        movwf  \ MOVWF RCSTA
    $90 rcsta !

    \ a few reads to ensure buffer is empty
\    rcreg ,w     movf   \    MOVF  RCREG,W
\    rcreg ,w     movf   \    MOVF  RCREG,W
\    rcreg ,w     movf   \    MOVF  RCREG,W
    rcreg @ drop
    rcreg @ drop
    rcreg @ drop

    \ PROVIDE A SETTLING TIME FOR START UP
\    tty.char     clrf
\ label: tty.init-0
\    tty.char ,f  decfsz \ DECFSZ tty_char,1
\    tty.init-0   goto   \ GOTO   tty_init_warmup
    0
    begin dup while 1+ repeat drop

\    return

;

\ @-node:tty.init
\ @+node:tty.putc
\ ( ch -- ) waits till line available, then transmits char

: tty.putc
    begin
        txif bit-set?
    until
    txreg !
;

\ @-node:tty.putc
\ @+node:tty.getc
\ ( -- ch ) waits for incoming char, returns it

: tty.getc

    \ wait till char available
    begin
        rcif bit-set?
    until

    \ and fetch it
    rcreg @
;

\ @-node:tty.getc
\ @+node:tty.crlf
: tty.crlf

    $0d tty.putc
    $0a tty.putc
;

\ @-node:tty.crlf
\ @-others

\ @-node:@file libttycore.fs
\ @-leo
-------------- next part --------------
\ @+leo-ver=4
\ @+node:@file libttyhex.fs
\ @@language forth
\ libttyhex.fs
\ 
\ Words for sending/receiving hex data over tty

\ @+others
\ @+node:includes
needs libttycore.fs

\ @-node:includes
\ @+node:tty.put4x
\ puts a hex nybble to tty

: tty.put4x ( nyb -- )

    $f and
    dup $a < if
        $30
    else
        $37
    then
    + tty.putc
;

\ @-node:tty.put4x
\ @+node:tty.put8x
\ puts an 8-bit number to tty as hex

: tty.put8x ( n -- )

    dup swapf-tos tty.put4x
    tty.put4x
;

\ @-node:tty.put8x
\ @+node:tty.get4x
\ fetches a hex nybble from tty, ignoring any non-hex chars

: tty.get4x

    begin
        \ optimisation attempt
        tty.getc [char] 0 -
        dup 9 <= if
            true
        else
            $11 - $df and
            dup 6 <= if
                $a + true
            else
                drop false
            then
        then
    until
;

\ @-node:tty.get4x
\ @+node:tty.get8x
\ retrieves a byte from tty as hex chars

: tty.get8x

    tty.get4x swapf-tos tty.get4x +

;

\ @-node:tty.get8x
\ @-others

\ @-node:@file libttyhex.fs
\ @-leo
-------------- next part --------------
\ @+leo-ver=4
\ @+node:@file libstacktrace.fs
\ @@language forth

\ libstacktrace.fs
\ 
\ words for stack leak debugging
\ mainly .s, which dumps stack to tty

\   - invoke .s-init anytime after startup, to mark the bottom of stack
\   - invoke .s anytime thereafter to send a stack dump to tty

\ @+others
\ @+node:includes
[ifundef] any-@
needs libfetch.fs
[then]

[ifundef] tty.init
needs libtty.fs
needs libttyhex.fs
[then]

\ @-node:includes
\ @+node:variables
variable .s-base

\ @-node:variables
\ @+node:stack tracing
\ @+node:.s-init
code .s-init
    fsr     ,w  movf
    .s-base     movwf
    .s-base ,f  decf
    return
end-code

\ @-node:.s-init
\ @+node:.s
: .s  \ stack dump via tty

    \ stack-base tty.put8x tty.crlf

    \ tty"  Stk(toplast): "
    $20 tty.putc
    fsr @ .s-base @            ( top bottom )
    swap                       ( bottom top )
    begin
        2dup                   ( bottom top bottom top )
        >=                     ( bottom top f )
    while                      ( bottom top )
        over @ tty.put8x       ( bottom top )
        $20 tty.putc           ( .. )
        swap 1- swap           ( bottom-1 top )
    repeat
    drop drop

    \ tty"  (more): " tty.getc drop 
    tty.crlf
;

\ @-node:.s
\ @-node:stack tracing
\ @-others

\ @-node:@file libstacktrace.fs
\ @-leo


More information about the PicForth mailing list