O SDCC pobremente suporta relocação de código. Ele traz os switches --ivt-loc e --code-loc (endereço das tabelas de vetores de interrupções e código) mas eles são ineficientes, incapazes, moribundos!
Recentemente descobri uma diretiva de compilação (#pragma) que pareceu ser promissor e tem feito o que eu preciso. Mas funciona de forma pobre, pois não consigo relocar o start point default do programa (main) para o ponto que eu preciso... então vamos para os artifícios.
Entendendo a Relocação
Quando o sistema possui um pré-inicializador, que pode ser um bootloader. O programa do usuário não precisa assumir o endereço absoluto. E para que não acabe apagando o bootloader, o seu código normalmente é adicionado no final daquele setor.Os compiladores normalmente irão gerar seus códigos executáveis almejando o endereçamento padrão e farão a sua linkedição com as bibliotecas de inicialização necessários (crt, c0t, c0rt...).
No caso da relocação, o compilador terá que gerar nova origem (ORG) e todos os branches, jumps, goto's, skip tests, memory access deverão observar esse novo endereço e calcular os seus "saltos" baseado nessa nova origem.
Na compilação, um dos arquivos gerados é o .LST. Ele possui a listagem em assembly, com a referencia de endereço de cada linha de código.
Vamos pegar o nosso programinha de blink!
#define __18F252
#include "pic18fregs.h"
#pragma config OSC=HS, OSCS=OFF, PWRT=OFF, BOR=OFF, WDT=OFF, CCP2MUX=OFF, LVP=OFF, CP0=OFF, CP1=OFF, CP2=OFF, CP3=OFF
int main()
{
TRISB=0xFD;
while(1) {
PORTB=(PORTB^0x02);
}
}
Veja o código da função "main()" sem relocação - in natura.
; ; Starting pCode block
S_blink__main code
_main:
; .line 20; blink.c TRISB=0xFD;
00000a 0efd movlw 0xfd MOVLW 0xfd
00000c 6e93 movwf 0x93, 0 MOVWF _TRISB
_00106_DS_:
; .line 22; blink.c PORTB=(PORTB^0x02);
00000e 7281 btg 0x81, 0x1, 0 BTG _PORTB, 1
000010 d7fe bra 0xe BRA _00106_DS_
000012 0012 return 0 RETURN
No código acima, eu removi os preâmbulos de inicialização CRT/C0T do sdcc (sdcc_gsinit...). Veja que a função main, começa no endereço 0x0a; o loop e o branch (BRA) apontam para 0x0e;
O label __0106_DS_ marca o inicio e fim do loop "while (1)..."
Vou relocar o código para o endereço 0x800
; ; Starting pCode block
S_blink___main code 0X000800
__main:
; .line 18; blink.c int _main()
000800 cfd9 movff 0xfd9, 0xfe5 MOVFF FSR2L, POSTDEC1
000802 ffe5
000804 cfe1 movff 0xfe1, 0xfd9 MOVFF FSR1L, FSR2L
000806 ffd9
; .line 20; blink.c TRISB=0xFD;
000808 0efd movlw 0xfd MOVLW 0xfd
00080a 6e93 movwf 0x93, 0 MOVWF _TRISB
_00106_DS_:
; .line 22; blink.c PORTB=(PORTB^0x02);
00080c 7281 btg 0x81, 0x1, 0 BTG _PORTB, 1
00080e d7fe bra 0x80c BRA _00106_DS_
000810 cfe4 movff 0xfe4, 0xfd9 MOVFF PREINC1, FSR2L
000812 ffd9
000814 0012 return 0 RETURN
Eu marquei em amarelo, as referências de endereços. Veja que o compilador teve que relocar o código. Isto é, atribuir novos endereços e corrigir os saltos para a nova faixa.
Problemas à vista
Estou usando o SDCC 3.3. Portanto o que eu disser aqui, é somente associado ao SDCC 3.3 (não testei em outras versões).Como eu disse, o suporte de relocação de código para PIC no SDCC é pobre. Com muita pesquisa você vai cair nas seguintes dicas:
1) --code-loc
2) --ivt-loc
3) usar #pragma code
4) alterar o .lkr do gputils
Cada uma delas tem a sua particularidade.
--code-loc
--code-loc não faz o que diz fazer. Ele relocaria o código para o endereço desejado. Mas isso não ocorre. NUNCA! :( (you boor!)(sorry, SDCC team, --code-loc is would never be in PIC)
--ivt-loc
--ivt-loc faz o que tem de fazer, mas é somente para tabelas de vetores. Se você tiver alguma função tipo __interrupt. Ele irá relocar o código para os endereços de vetores a partir do ponto informado.Adicione o trecho de código abaixo ao nosso blink.c
void isr_high() __critical __interrupt 1 {
PORTA=!PORTA;
}
compile-o
sdcc --use-non-free -p18f252 -mpic16 blink.c
Por fim abra o blink.lst e inspecione o seu conteúdo...
S_blink__isr_high code 0X000008
_isr_high:
; .line 15; blink.c PORTA=!PORTA;
000008 5080 movf 0x80, 0, 0 MOVF _PORTA, W
00000a 80d8 bsf 0xd8, 0, 0 BSF STATUS, 0
00000c 66e8 tstfsz 0xe8, 0 TSTFSZ WREG
00000e 90d8 bcf 0xd8, 0, 0 BCF STATUS, 0
000010 6a80 clrf 0x80, 0 CLRF _PORTA
000012 3680 rlcf 0x80, 0x1, 0 RLCF _PORTA, F
Agora compile com essa linha de comando:
sdcc --use-non-free -p18f252 -mpic16 --ivt-loc=0x200 blink.c
O código será relocado:
_isr_high:
; .line 15; blink.c PORTA=!PORTA;
000208 5080 movf 0x80, 0, 0 MOVF _PORTA, W
00020a 80d8 bsf 0xd8, 0, 0 BSF STATUS, 0
00020c 66e8 tstfsz 0xe8, 0 TSTFSZ WREG
00020e 90d8 bcf 0xd8, 0, 0 BCF STATUS, 0
000210 6a80 clrf 0x80, 0 CLRF _PORTA
000212 3680 rlcf 0x80, 0x1, 0 RLCF _PORTA, F
I FOUND A BUG! SDCC não está gerando RETFIE (return from Interrupt) no final das ISR's quando se usa __naked! Bom, nada que um __asm RETFIE __endasm; não resolva. Mas fica o alerta!
o --ivt-loc não reloca o main... então falta somente essa parte.
--//--
Nos próximos artigos vamos explorar o #pragma e o .lkr! Tem coisa boa vindo aí!
Nenhum comentário:
Postar um comentário