bug in access bank register selection code

Coding and general discussion relating to the compiler

Moderators: David Barker, Jerry Messina

Post Reply
Jerry Messina
Swordfish Developer
Posts: 1211
Joined: Fri Jan 30, 2009 6:27 pm
Location: US

bug in access bank register selection code

Post by Jerry Messina » Mon Feb 08, 2010 8:00 pm

There appears to be an issue with the compiler generating incorrect code for registers located at the edge of the upper access bank.

I think this bug was first noticed by RangerBob in the thread "Getting USB working in 18F87J50" (http://www.sfcompiler.co.uk/forum/viewtopic.php?t=710),
but I just thought I'd point out that it affects ALL processors, and not just the 87J50 (since it just bit me in the backside while working on another pic).

The issue is that the proper bank select isn't being set for register accesses to the location right before the upper access bank area.
For most processors with the access bank in two $80 byte chunks, this is the register at $F7F (which for most processors isn't used...no harm, no foul).

However, for most of the "J" series parts (USB), and ones with CANbus or LCD controls, the access bank is split at $60 bytes, and the upper SFR area ($F5F) is used. No matter what I tried, while I could get the .idf file to report the proper access bank usage, the code generator would always goof-up access to this reg, and incorrectly assume it was in the access bank (which it isn't).

The code below can be used to demonstrate the issue.

Code: Select all

//
// access bank test
//
'device = 18F452
device = 18F4685
'device = 18F87J50
'device = 18F66J11
'device = 18F8390

// this entry in the SF 18Fxxxx.bas file controls the access bank usage
'#variable _maxaccess = $80
'#variable _maxaccess = $60

// registers around the top access bank
dim 
    REG_AT_AB_MINUS2 as byte absolute ($1000 - (256-_maxaccess) - 2),
    REG_AT_AB_MINUS1 as byte absolute ($1000 - (256-_maxaccess) - 1), // THIS IS THE PROBLEM AREA
    REG_AT_AB_START as byte absolute ($1000 - (256-_maxaccess)),
    REG_AT_AB_PLUS1 as byte absolute ($1000 - (256-_maxaccess) + 1)
    
// ram vars in the lower access bank. these are not a problem, they're
// just here to verify that SF allocates and accesses them properly.
// reserve a big chunk to take up most of the lower access bank (minus system vars)
const SYS_VAR_SIZE = $1a
dim dummy(_maxaccess-SYS_VAR_SIZE-1) as byte
// these should be right around the end of the lower access bank
dim 
    var_at_ab_end_minus1 as byte,
    var_at_ab_end as byte,
    var_at_ab_end_plus1 as byte

main:
    ' upper access bank
    ' reg NOT in access bank (req's bank select)... correct
    REG_AT_AB_MINUS2 = 1
    ' this reg is the last one NOT in access bank...req's bank select
    REG_AT_AB_MINUS1 = 2    // THIS IS WHERE THE ERROR OCCURS
    ' start of upper access bank (no bank select req'd)... correct
    REG_AT_AB_START = 3
    ' also in upper access bank... correct
    REG_AT_AB_PLUS1 = 4
    
    ' lower access bank
    var_at_ab_end_minus1 = 1    ' use access bank ok
    var_at_ab_end = 2           ' last var to use access bank
    var_at_ab_end_plus1 = 3     ' this one should need a bank select

    ' so dummy array doesn't get optimized out...     
    clear(dummy)

You can get around the issue by using indirect addressing for this register, perhaps something like the following (adapted from USBsystem.bas)

Code: Select all

{
****************************************************************************
* Name    : SetRAMPtr                                                      *
* Purpose : Helper routine for setting RAM                                 *
****************************************************************************
}
inline sub SetRAMPtr(pAddress as FSR0, pValue as INDF0)
end sub

{
****************************************************************************
* Name    : GetRAMPtr                                                      *
* Purpose : Helper routine for getting RAM byte                            *
****************************************************************************
}
inline function GetRAMPtr(pAddress as FSR0) as INDF0
end function

' use indirect addressing to access the problem register
SetRAMPtr(@REG_AT_AB_MINUS1, $55)
dummy(0) = GetRamPtr(@REG_AT_AB_MINUS1)
Note that the affected register has different uses depending on the pic in question.

Jerry

edit note: added '@' addressof operator to examples

Post Reply