According to the ARM manual, __irq is a keyword defining the interrupt handlers in C code. However, I am not clear what would do keywords like:
__irq_arm
__irq_arm_ramfunc
__irq_XXXX
.....
HOWEVER,
after reviewing the original of the code, it was pretty clear that there are spaces between __irq and __arm, as well as between __irq and __ramfunc. Therefore, my question is no longer valid. One should always look the code on the screen, instead from some handouts ...
Related
I'm trying to gain some insight on how Apples OS signpost implementation works. I'm working with the C API (there is also a Swift API). My ultimate goal is trying to build a RAII style C++ wrapper class for them, which is harder as it might seem.
Expanding the os_signpost_emit_with_type macro reveals that it creates static strings from the string literals passed to that macro that look like this:
__attribute__((section("__TEXT,__oslogstring,cstring_literals"), internal_linkage)) static const char string_name[] __asm (OS_STRINGIFY(OS_CONCAT(LOS_##_ns, __COUNTER__))) = "string literal";
These strings will later appear as names for the signposts in the instruments profiler. What I get from reading that code, is that the string is placed in a specific section of the binary so that the profiler can find it. What's confusing me is the __asm statement before the assignment. Obviously via the __COUNTER__ macro, it expands to something like __asm ("LOS_##_ns0"), __asm ("LOS_##_ns1") with the number being unique for every string. I have very little in depth knowledge when it comes to assembly, I tried to research the meaning of that statement a bit but got no useful results.
My try-and-error testing revealed that the uniqueness of that numerical appendix generated by the __COUNTER__ macro matters, if two duplicated values occur the string with that duplicated value will shadow the other one in the profiler output.
Can anyone with assembly know how explain what's going on here to a C++ developer like me?
Bonus question: Would there be any way to generate that instruction from within C++ code where the unique numerical value here generated by __COUNTER__would be taken from some variable?
A general note: for information on clang extensions, you generally have to refer to the gcc documentation instead. clang aims to be compatible with gcc and so they didn't bother to write independent docs.
So in your example, a few different extensions are being used. Note that none of them are part of standard C or C++.
__attribute__((section ("foo")) places the variable in the section named foo, by having the compiler emit a .section directive into the assembly before placing the label for the variable. See https://gcc.gnu.org/onlinedocs/gcc-12.2.0/gcc/Common-Variable-Attributes.html#Common-Variable-Attributes. It sounds like you already know about this.
asm in a declaration isn't really inline assembly per se; it simply tells the compiler what symbol name to use for this variable when it emits the assembly code. The __asm is just a variant spelling of asm. See https://gcc.gnu.org/onlinedocs/gcc-12.2.0/gcc/Asm-Labels.html#Asm-Labels. So int foo asm("bar") = 7; defines a variable which will be referred to as foo in C source, but whose label in assembly will be named bar.
__COUNTER__ is a special macro defined by the gcc/clang preprocessor that simply increments every time it is expanded. See https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html#Common-Predefined-Macros
I've been stuck for a while on how to set up a callback when an exception occurs.
I have this test code:
void main()
{
long * bad = (long*)0x0A000000; //Invalid address
//When the following line gets executed
//it causes an error and the debugger sends me to an assembly file.
*bad = 123456789;
}
The assembly file that I am sent to looks like this(fragment of the real file):
.macro DEFAULT_ISR_HANDLER name=
.thumb_func
.weak \name
\name:
1: b 1b /* endless loop */
.endm
DEFAULT_ISR_HANDLER SRC_IRQHandler /*Debugger stops on this line*/
As I understand DEFAULT_ISR_HANDLER is a macro that defines an endless loop.
What I want to do is define my own function in a C file, that I could call when an exception occurs, instead of calling whats defined in the DEFAULT_ISR_HANDLER macro.
My question is, How would I define a macro, in that assembly, that calls an specific C function?
Hopefully I explained myself. Any information or direction around this topic is appreciated.
In case it's relevant I am using GCC ARM compiler v5.4_2016q3
Thanks,
Isaac
EDIT
I am using a Cortex-M3.
Until now I realized I was talking about processor exceptions. According to the datasheet there is a list with 16 exception types.
Apparently, the way it works is that all the exception types are being redirected to the macro, which in turn calls some thumb function and afterwards an endless loop(according to DEFAULT_ISR_HANDLER above in code).
What I would like to do is define my own function in a C file, for convenience, so every time any type of processor exception appear, I could control how to proceed.
You have two options:
Just define a C function with the void SRC_IRQHandler(void) signature and since the macro is defining the default handler as weak, your function will override the default handler in the linking stage.
There should be a place in your project where SRC_IRQHandler is placed in what is called a Vector Table in the Cortex-M3 architecture. You can replace the name of this function with your own C function and your function will be called when this interrupt (exception) happens.
The cortex-m family in general has well more than 16 exceptions there are those plus as many interrupts are implemented by that core, 32, 64, 128, 256. But it is all fundamentally the same. The way the cortex-m family works is they perform the EABI call for you if you will, they preserve some of the registers and then start execution at the address called out in the vector table done in such a way that you can have the address of a normally compiled C function directly in the table. Historically you needed to wrap that function with some code to preserve and restore the state and often instruction sets have a special return from interrupt, but the cortex-m they did a bit different.
so knowing that then the next question is how do you get that address in the table, and that depends on your code, build system, etc. Those handlers might be setup to point to an address in ram and maybe you are running on an RTOS and there is a function you call runtime to register a function for an exception then the RTOS changes the code or some data value in ram that is tied into their handler which essentially wraps around yours. or you are making the vector table in assembly or some other tool specific thing (although assembly is there, works and easy) and you simply count down the right number of entries (or add a hundred more entries so you can count down to the right entry) and place the name of your C function.
good idea to disassemble or do some other check on the result before running to double check that you have placed the handler address at the right physical address for that interrupt/exception.
Will this compile and work as meant under Linux GCC ?
In the LoRa Gateway Stack hosted at Github I found the following construct in loragw_hal.h
enum lgw_radio_type_e {
LGW_RADIO_TYPE_NONE,
LGW_RADIO_TYPE_SX1255,
LGW_RADIO_TYPE_SX1257
};
#define LGW_RF_CHAIN_NB 2 /* number of RF chains */
and then in loragw_hal.c
static enum lgw_radio_type_e rf_radio_type[LGW_RF_CHAIN_NB];
edit: the array is not initialized at any place in the code
and then in the function
setup_sx125x(uint8_t rf_chain, uint32_t freq_hz)
the following switch statement is used to select the rf chain according to the rf_chain argument
switch (rf_radio_type[rf_chain]) {
case LGW_RADIO_TYPE_SX1255:
// some code
break;
case LGW_RADIO_TYPE_SX1257:
// some code
break;
default:
DEBUG_PRINTF("ERROR: UNEXPECTED VALUE %d FOR RADIO TYPE\n",
rf_radio_type[rf_chain]);
break;
}
rf_chain argument is set to 1, when the function is called, and it selects the default Error 'unexpected rf chain' of course.
The copyright holder Semtech Inc. support, points always to this code, if you have any problems with their product, as reference.
But I have the feeling that this code wouldn't run anyway without any modifications.
So my question to the forum here is, aside from that this construct above makes not really sense, is that not a faulty construct anyway ?
Will this compile and work as meant under Linux GCC ?
I try to use this code under GCC ARM and it does NOT work as it seems to be planned.
You seem to be trying to draw attention to this:
enum lgw_radio_type_e {
LGW_RADIO_TYPE_NONE,
LGW_RADIO_TYPE_SX1255,
LGW_RADIO_TYPE_SX1257
};
#define LGW_RF_CHAIN_NB 2 /* number of RF chains */
[...]
static enum lgw_radio_type_e rf_radio_type[LGW_RF_CHAIN_NB];
[...] the array is not initialized at any place in the code
It is not a particular problem that the array is not explicitly initialized. File-scope variables (and static block-scope variables) are subject to default initialization if no explicit initializer is provided. In this case, the array declaration is equivalent to
static enum lgw_radio_type_e rf_radio_type[2] = {
LGW_RADIO_TYPE_NONE, LGW_RADIO_TYPE_NONE
};
That seems to be quite sensible in itself.
You go on to say,
[...] when the function is called, and it selects the default Error 'unexpected rf chain' of course.
I don't see any reason to expect a different case to be selected, but neither do I see any justification for assuming that a different one would not be selected. Nor is it clear under what circumstances the switch itself is executed at all.
One would normally expect one or both elements of rf_radio_type to be set during driver initialization if in fact the corresponding hardware is present. If the overall code (not just the parts you've presented) is correct, then probably it will not execute the presented switch when rf_radio_type[rf_chain] has a value different from both LGW_RADIO_TYPE_SX1255 and LGW_RADIO_TYPE_SX1257. On the other hand, printing the error message is essentially harmless in itself; if the driver prints it then that may be merely a quality-of-implementation issue, not a functional flaw.
So my question to the forum here is, aside from that this construct
above makes not really sense, is that not a faulty construct anyway ?
No, it isn't. And as far as I can tell, all constructs presented make as much sense as can be expected when taken out of context as they have been.
Will this compile and work as meant under Linux GCC ?
You have presented several individually valid C fragments, but they do not together constitute a valid translation unit. It is possible to form a complete, valid translation unit containing all those fragments that will compile successfully and do absolutely anything. The fragments will not inherently interfere with compilation, nor necessarily cause malfunction.
I try to use this code under GCC ARM and it does NOT work as it seems to be planned.
I find your apparent confidence in your assessment of the intended behavior of the overall code to be a bit optimistic.
edit: the array is not initialized at any place in the code
As pointed out in another answer, variables with static storage duration are required by the C standard to get implicitly initialized to zero if the programmer didn't set them explicitly. So this is code fine as far as the C standard is concerned.
However, writing code relying on initialization of static storage duration variables in .bss is recognized as bad practice in embedded systems programming. This is because the code that does the copy-down of .data and zero initialization of .bss is often omitted on embedded systems, as a very common non-standard practice in order to speed up program start-up.
Such a non-standard option is usually called "minimal/compact/fast start-up" or similar in the compiler options. If you have such an option enabled - which is quite common - the code won't work.
Good practice is to initialize such variables later on in "run-time" instead, before they are used for the first time.
Summary: the code is sloppily written, since the intention here is to provide portable code across many different microcontroller platforms, rather than to provide code for some PC. I would guess it was written by some kind of PC programmer, as is often the case for these protocol stacks.
currently I'm developing a project for an ATMega8 (AVR) microprocessor. I came across the expression:
__C_task void my_Function(){
}
What does "__C_task" attribute do?
Google says that it's an IAR-specific identifier that tags a function as never returning. The GCC equivalent is the noreturn attribute.
void my_Function(void) __attribute__((noreturn));
void my_Function(void)
{
...
}
it denotes a "non returning" function (I've seen it being used in ATMEL microprocessor C code where C is a High-level Language :) )
This site says __C_task is equivalent to gcc's __attribute__((noreturn)).
In addition, in avr-gcc there are the function attributes OS_main and OS_task, respectively. (Both still sparsely documented.)
Apparently, avr-gcc may save "call-saved" registers on the stack even when a function is declared noreturn. This may or may not make sense for 'normal' functions, but for (concurrent) tasks managed by a task scheduler with context-switching (an "OS") and its own stack mangement on a per-task basis it's just a waste of space on the stack because the task will not return to any caller that requires any call-saved registers to be intact.
void __attribute__((__interrupt__, no_auto_psv)) _T1Interrupt(void) // 5 Hz
__attribute__ directive or macro is from GCC but __interrupt__ and no_auto_psv is not , it's specific to a hardware. So, how does GCC Compiler understand __interrupt__ and no_auoto_psv, I searched and didn't find any declaration in anywhere else.
So basically the _T1Interrupt function takes no argument and return nothing but has the above attribute?
In particular, these attributes are platform-specific extensions used in the Microchip XC16 compiler for 16-bit PIC24 and dsPICs.
Attributes are essentially extra information added to the parse tree of a compiler. They exist outside the C language semantics and are there to provide additional information that the compiler uses to act consistently with your expectations. In this case __interrupt__ tells it to treat the function as an ISR (with slightly different function prolog and epilog than a normal function: dsPIC ISRs use the RETFIE return instruction, vs. RETURN for normal functions), and no_auto_psv controls whether the compiler sets the PSVPAG register:
The use of the no_auto_psv attribute omits code that will re-initialize the PSVPAG value to the default for auto psv variables (const or those placed into space auto_psv). If your code does not modify the PSVPAG register either explicitly or using the compiler managed psv or prog qualifiers then the use of no_auto_psv is safe. Also, if your interrupt service routine (or functions called by your interrupt service routine) does not use any const or space auto_psv variables, then it is safe to use no_auto_psv.
(from http://www.microchip.com/forums/m394382.aspx)
The documentation for __attribute__() says:
GCC plugins may provide their own attributes.
So perhaps that's how it's being used in your situation.
What unwind said is true and the attritbutes are defined by the MPLAB extension for gcc. It's been a while since i've worked with microcontrollers so i can't provide more details on this front. However for your specific application (embedded c on pic micro-controller). The above is the proper way of declaring a function that is meant to implement an interrupt subroutine for timer 1. Interrupt subroutines rarely return anything, If you need to capture the value in the register i recommend you use the following structure as a global variable:
typedef struct T1OUT
{
int timer_register_value;
int flag;
} T1InteruptCapture;
The timer_register_value is the value you want out of your subroutine. While the flag value is memory lock that prevents the subroutine from over-writing your previous value. There are different ways of getting values out of your subroutine. I found this to be the easiest and the most time efficient. You can also look into implementing a mini-buffer. I recommend you avoid pointer with embedded C. I don't know if things have changed, in the last couple of years.
edit 1: MPLAB has some of the best documentation i've ever seen. I recommend you have a look at the one for your specific microcontroller. They provide sample code with great explanations.
edit 2: I not sure why you're using gcc. I would recommend you get the pic compiler from MPLAB. I believe it was called C30. and the associated .h file.