This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

HALCoGen generated code does not export stack addresses

Other Parts Discussed in Thread: HALCOGEN

Hello,


we want to implement some application on top of HALCoGen genrated code. We need to perform special handling of different exection mode and we need to know the addresses of e.g. abort stack. All stack sizes can be setup in HALCoGen and generated into sys_core.asm. The corrosponding function does setup all stacks but the addresses of each stack are not expported for furhter use in other modules. For this code part no user sections forseen to implement a workaround

Might this be changed in further HALCoGen versions?

  • I submitted an enhancement request: SDOCM00122698
  • I implement next functions

    stack_utils_.asm:

    	.data
    userSp  .word 0
    fiqSp   .word 0
    svcSp   .word 0
    irqSp   .word 0
    abortSp .word 0
    undefSp .word 0
    	.def   userSp
        .def   fiqSp
        .def   svcSp
        .def   irqSp
        .def   abortSp
        .def   undefSp
    
    	.text
    	.arm
    
        .def     _ReadStackPointers_
        .asmfunc
    _ReadStackPointers_
        cps   #17
    	LDR  R0, fiqSpConst
    	str  sp, [r0]
    
        cps   #18
    	LDR  R0, irqSpConst
    	str  sp, [r0]
    
        cps   #19
    	LDR  R0, svcSpConst
    	str  sp, [r0]
    
        cps  #23
    	LDR  R0, abortSpConst
    	str  sp, [r0]
    
        cps  #27
    	LDR  R0, undefSpConst
    	str  sp, [r0]
    
        cps   #31
    	LDR  R0, userSpConst
    	str  sp, [r0]
    
        bx    lr
    
        .endasmfunc
    
    userSpConst  .word userSp
    fiqSpConst   .word fiqSp
    svcSpConst   .word svcSp
    irqSpConst   .word irqSp
    abortSpConst .word abortSp
    undefSpConst .word undefSp
    
    

    stack_utils.h:

    #ifndef __STACK_UTILS_H_
    #define __STACK_UTILS_H_
    
    #include <stdint.h>
    #include "oprintf.h"
    #include "rx_stdbool.h"
    
    typedef struct {
        uint16_t size;
        uint16_t used;
        uint32_t base;
    } stack_info_t;
    
    typedef struct {
        stack_info_t user;
        stack_info_t svc;
        stack_info_t fiq;
        stack_info_t irq;
        stack_info_t abort;
        stack_info_t undef;
    } stacks_info_t;
    
    void _ReadStackPointers_ (void);
    uint16_t get_user_stack_free (void);
    
    void read_stacks_info(stacks_info_t* info);
    bool diag_report_stack(ostream_t* stream);
    #endif /* __STACK_UTILS_H_ */
    

    stack_utils.c:

    #include <inttypes.h>
    #include "stack_utils.h"
    #include "log.h"
    #include "diag_report.h"
    #include "rx_io.h"
    #include "table_utils.h"
    
    extern uint32_t userSp;
    extern uint32_t svcSp;
    extern uint32_t fiqSp;
    extern uint32_t irqSp;
    extern uint32_t abortSp;
    extern uint32_t undefSp;
    
    #define USER_STACK_HEAD ((const uint32_t*)0x08000000)
    
    #define RAM_HEAD 0x08000000U
    
    #define SVC_STACK_SIZE 0x100
    
    uint16_t get_user_stack_free (void) {
        const uint32_t* p = USER_STACK_HEAD;
        while (*p == 0) {
            p++;
        }
        return (uint16_t) ((p - USER_STACK_HEAD) * 4);
    }
    
    static void get_used (stack_info_t* s) {
        const uint8_t* head = (const uint8_t*) (s->base - s->size);
        uint32 free_size = 0;
        while (head [free_size] == 0 && free_size < s->size) {
            free_size++;
        }
        s->used = s->size - free_size;
    }
    
    void read_stacks_info (stacks_info_t* info) {
        RAISE_PRIVILEGE;
        _ReadStackPointers_ ();
        info->undef.base = undefSp;
        info->undef.size = undefSp - abortSp;
        get_used (&info->undef);
    
        info->abort.base = abortSp;
        info->abort.size = abortSp - irqSp;
        get_used (&info->abort);
    
        info->irq.base = irqSp;
        info->irq.size = irqSp - fiqSp;
        get_used (&info->irq);
    
        info->fiq.base = fiqSp;
        info->fiq.size = fiqSp - svcSp;
        get_used (&info->fiq);
    
        info->svc.base = svcSp;
        info->svc.size = SVC_STACK_SIZE;
        get_used (&info->svc);
    
        info->user.base = svcSp - SVC_STACK_SIZE;
        info->user.size = info->user.base - RAM_HEAD;
        get_used (&info->user);
        RESET_PRIVILEGE;
    }
    
    #define REPORT(name)   oprintf(stream, "║%6s │%5" PRIu16 " │%5" PRIu16 " │%5" PRIu16 " │%5" PRIu16 " ║" _SE, #name, info.name.size, info.name.used, info.name.size-info.name.used, (uint16_t)(info.name.used*100LU/info.name.size))
    
    bool diag_report_stack (ostream_t* stream) {
        static stacks_info_t info;
        static const table_col_t cols [] =
            {
                { 7, "Stack" },
                { 6, "Size" },
                { 6, "Used" },
                { 6, "Free" },
                { 6, "% used" }, };
    
        table_header (stream, cols, RX_ARRAY_SIZE(cols));
        read_stacks_info (&info);
        REPORT(user);
        REPORT(svc);
        REPORT(fiq);
        REPORT(irq);
        REPORT(abort);
        REPORT(undef);
        table_row_bottom (stream, cols, RX_ARRAY_SIZE(cols));
        return true;
    }
    

  • We was thinking to implemting something simliar as a workaround.

    Discussion of your function:

    The function _ReadStackPointers_ need to be executed somewhere to habe the SP-variables set. Is this considered to be added in the HALCoGen startup / init code?

    We need SP information any time and the SP-variables are not refreshed, and the _ReadStackPointers_ function gives the current value rather than the init value´, dependent to time of execution. Let assume the function is called once after init if the stacks, the SP-variables are never refreshed and a bit flip mitght get the value invalid (if not ECC protected)

    Our need / goal:

    For us it would be sufficient to have the intial stack boundaries just as a symbol - globally available.

  • My code is only workaround. This code currently used for diagnostic purposes to control stack usage. Another idea - simple script what convert halcogen .dil file to header file.
    For sample
    DRIVER.SYSTEM.VAR.RAM_STACK_ABORT_LENGTH.VALUE=0x00000100
    DRIVER.SYSTEM.VAR.RAM_STACK_ABORT_BASE.VALUE=0x08000900
    converted to
    #define DRIVER_SYSTEM_VAR_RAM_STACK_ABORT_LENGTH_VALUE 0x00000100
    #define DRIVER_SYSTEM_VAR_RAM_STACK_ABORT_BASE_VALUE 0x08000900
    And call this script as prebuild step
  • Ok, for workaround both variants can be considered.
    So in a possible next release of HALCoGen the export of stack addresses are on the roadmap?