avr-libc-dev
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[avr-libc-dev] vector section disable, vector redirection


From: Jörg Diederich
Subject: [avr-libc-dev] vector section disable, vector redirection
Date: Tue, 14 Aug 2007 23:16:23 +0100

hello,
i've been working on a part of software which bases on another, already 
installed part of software at the avr. in order to use interrupt vectors in the 
part mentioned first, two steps were necessary. for both i'd like to discuss an 
improvement in the current avr-libc.

first, it was necessary to prevent any vectors are included. this could easily 
done by including '*(.vectors)' in the DISCARD-section in the linker script. 
Unfortunatly, the '__bad_interrupt' func of the gcrt references section 
.vectors. it can't easily discarded too because it is placed in the 
.text-section.
as an easy workaround i would suggest to use another, special named section for 
this. one simple name would be .bad_vectors. this would enable to discard this 
in a simple way. the only neccessary changes in avr-libc would be to include 
.bad_vectors right after .vectors in any linker script. the advantage would be 
in a simple way to remove any vectors from a linked applicaton. if i remember 
correctly, it is possible to use vector space as normal program space, btw.

second, a redirection of all interrupts is performed. on every interrupt a 
table in SRAM is asked for the function pointer to jump to. a naive approach 
results in very much program space, as the avr-gcc pushed and pops all 
registers in an ISR with an call inside (3,2kB on the at90can128). using naked 
ISR's is not the smallest thinkable way, as in every ISR the same instructions 
are included. that's why my supervisor and me developed the redirection scheme 
attached below (ca. 500byte). for me it's unknown if there is any place in the 
avr-libc for vector redirections, but any hints are very welcome *g*. (i'm 
sorry for long posting, but attachment are often ignored, 'cause of more effort)
the weakness of the redirection table is the set of a vector name in the 
following procedure:

extern inthandler redir_tab[];

uint8_t
set_int_handler( inthandler handler, uint8_t idx )
{
[..]
        if( idx-- && idx < ((_VECTORS_SIZE / 4) - 1 ) ) {
          /* 
           * first, we are one ahead
           * 4 for size of each jump instructions, 1 cause of ignored reset 
           * vector
           */
          redir_tab[idx] = handler; 
          ret = 0;
        }
[..]
}

i would like to use the vector names defined by the avr-libc as an index into 
the redirection table (as the second argument in a call). at the moment, i'm 
forced to use self-written definitions, because unfortunatly again, the 
avr-libc-names are symbols and therefore addresses in program space. the 
suggestion is to change the vector definition in avr/interrupt.h:

#define ISR(vector)                                     \
  void _VECTOR(vector) (void) __attribute__ ((signal)); \
  void _VECTOR(vector) (void)
#endif

(and the others too, of course)
the original macro just uses 

#define ISR(vector)                                     \
  void vector (void) __attribute__ ((signal)); \
  void vector (void)
#endif

instead of defining each vector with _VECTOR(N) in each io.h-instance, it could 
easily be defined in interrupt.h.
each io.h-instance therefore could only define interrupt names like this:

/* External Interrupt Request 0 */
#define INT0_vect                       1
#define SIG_INTERRUPT0                  1

instead of now 
/* External Interrupt Request 0 */
#define INT0_vect                       _VECTOR(1)
#define SIG_INTERRUPT0                  _VECTOR(1)

the benefit is, that each vector name is simply the number the interrupt was 
given once by atmel. so any redirection or usage of an interrupt could use the 
name as an index. the necessary changes in avr-libc are 12 changed function 
macros in interrupt.h, plus the change in each io.h-instance. the latter could 
be done by an sed-script, i can think about it, if necessary.

i would like the read your opinion. and any hints as well :)

bye jörg


asm-code of redirection procedure:

#include <avr/io.h>
        
; set size of a single vector
#define VECTOR_SIZE 4

; size of redirection vector
#define REDIRVEC_SIZE 8

;  size of redirection table entry
#define REDIRTAB_SIZE 2


; macro for initializing interrupt vectors. see gcrt for prototype
.macro redir name
        .if (. - redirs < (_VECTORS_SIZE  / VECTOR_SIZE * REDIRVEC_SIZE))
        .global \name
        \name:                                          
                push r18                                ; save call-used 
                                                        ; register
                ldi r18, (. - redirs)/REDIRVEC_SIZE * 2 ; index into redir_tab
                jmp redir_func                          ; jump to redir function
                                                        ; TODO: MEGA-arch 
                                                        ; dependent
        .endif
.endm

; macro for initializing redirection table. see gcrt for prototype
.macro redir_default cnt
        .if (. - redir_tab < ((_VECTORS_SIZE  / VECTOR_SIZE - 1) * \
                                REDIRTAB_SIZE))
        ; ignore one entry (the one for the reset vector)
        .word redir_default 
        .endif
.endm


; all the following belongs into text
.text
.global redirs
.func redirs    
; redir macro calls
redirs:
        redir _VECTOR(1)
[...]
        redir _VECTOR(56)
.endfunc

        
; default redirection symbol. similar to the bad_interrupt of avr-libc
; performs nothing more than a return
.global redir_default
.set redir_default, 0   
        
; global redirection routine
; saves registers as needed and redirect to the address specified in 
; redirection table
.global redir_func
.func redir_func
redir_func:                             
redir_func_store:                       ; save used registers. Saves all 
                                        ; call-used registers. Called routines 
                                        ; SHOULD do this by default. But 
                                        ; ignored for the sake of clarity and 
                                        ; in case of naked routines 
        push r1                         ; save zero register
        eor r1, r1                      ; clear zero register, as assumed to
                                        ; always be zero
        push r0                         ; save temporary register
                                        ; long names (__zero_reg__) 
                                        ; first avaiable in macros.inc
        in r0, _SFR_IO_ADDR(SREG)       ; load status. SREG is a SFR macro
        push r0                         ; save loaded status. Assumes irqs are 
                                        ; disabled
       push r19                        ; save other call-used registers
        push r20                        ;
        push r21                        ;
        push r22                        ;
        push r23                        ;
        push r24                        ;
        push r25                        ;
        push XL                         ;
        push XH                         ;
        push ZL                         ; save lower Z pointer   
        push ZH                         ; save upper Z pointer
                                
redir_func_jmp:                         ; compute jump address
        ldi XH, hi8(redir_tab)          ; load upper part of vector table 
                                        ; address  
        ldi XL, lo8(redir_tab)          ; load lower part of vector table 
                                        ; address  
        add XL, r18                     ; add offset to vector table address.
                                        ; Was set with index by caller. Assumes 
                                        ; less or equal 0x80 vector table 
                                        ; entries
        adc XH, r1                      ; add carry now
        ld ZL, X+                       ; load content of address, which is
                                        ; the (lower) jump address
        ld ZH, X                        ; load upper jump address
        sbiw ZL, 0                      ; test for zero
        breq redir_func_restore         ; skip next call, if zero
        icall                           ; jump to address pointed by Z pointer

redir_func_restore:                     ; back from vector routine. restore 
                                        ; used registers
        pop ZH                          ; restore higher Z pointer       
        pop ZL                          ; restore lower Z pointer        
        pop XH                          ; restore call-used registers
        pop XL                          ;
        pop r25                         ;
        pop r24                         ;
        pop r23                         ;
        pop r22                         ;
        pop r21                         ;
        pop r20                         ;
        pop r19                         ;
        pop r0                          ; restore status register into temporary
        out _SFR_IO_ADDR(SREG), r0      ; load status register
        pop r0                          ; restore temporary register     
        pop r1                          ; restore zero register  
        pop r18                         ; resore first saved and used 
        reti                            ; return from redirection and so return
                                        ; from interrupt
.endfunc                                ; end of redirection routine    

; all the following belongs to data
.data
.global redir_tab
.func redir_tab 
redir_tab:
        redir_default 1
[...]
        redir_default 56
.endfunc        
        
.end            


=


-- 
Powered By Outblaze




reply via email to

[Prev in Thread] Current Thread [Next in Thread]