107 of 172
ZBasic Language Reference 100 ZX Microcontroller Family Special Attributes Attribute Valid For Description Inline subroutine function Instructs the compiler to “inline” the code for the subroutine/function instead of generating a call. Generally, this yields faster execution, sometimes at the expense of larger program size. NoInline subroutine function Instructs the compiler not to “inline” the code for the subroutine/function and, instead, generate a call to the subroutine or function. Used subroutine function variable Instructs the compiler to include the variable or procedure in the executable even if it appears not to be used. This is useful, for example if external C or assembly code needs to use a ZBasic data item or procedure but it is not otherwise used in the program. Volatile variable Instructs the compiler to not make any assumptions about the content of the variable. This should be used when another task or an ISR may be modifying the variable. Example Dim index as Integer Attribute(Volatile) Sub foo() Attribute(Used,Inline) End Sub 4.6 Considerations for Task Stack Size As of v2.5.6, the ZBasic compiler produces an estimate of the minimum size for a native mode application’s tasks. The estimate is produced by performing a static analysis of the generated native code beginning with the entry point of each task (including the default Main() task). The static analysis determines, if possible, the maximum stack depth assuming that all possible execution paths through the code are followed. Additionally, each ISR (both user-provided and system-provided) is analyzed using the same technique to determine the maximum stack depth it will use. For each task, the required minimum task stack size is the sum of a) the maximum stack depth of the task itself, b) the size of the Task Control Block, c) the stack margin (default or user specified) and d) the largest of 1) the multi-tasking context size and 2) the stack depths of the individual ISRs. At the time of this writing, Task Control block size is 13 bytes, the multi-tasking context size is 37 bytes (38 on ZX models with more than 64K of Flash memory), the maximum stack depth of the system supplied ISRs is less than 20 bytes and the default stack margin is 10 bytes. This leads to a typical task stack size minimum that is the stack depth of the task itself plus 60 bytes (37 + 13 + 10) or 61 bytes (38 + 13 + 10). The compiler outputs a list of the known tasks and the minimum task stack size for each to the .map file that is produced each time a project is compiled (unless it is explicitly requested otherwise). In most cases, the compiler stack depth estimation algorithm can successfully compute the maximum stack depth but there are certain situations where the stack effect cannot be deduced by examining the code. When this situation is encountered, the map file will list “???” as the minimum stack size in the task list contained in the .map file for the related task. In this situation, there are two possible alternative strategies. The first is to allocate a large task stack for the task in question, run the application (ensuring that as many of the executions paths as possible are taken) and then using the System Library function System.TaskHeadRoom() to determine how much unused space remains in that task’s stack. Based on the results of this observation, you may choose to increase or decrease the size of that task’s stack. The second option is to explicitly inform the compiler of the maximum stack depth for the routine or ISR that contains the problematic code. This is done using the #pragma StackUse directive within the particular procedure or ISR, the syntax of which is shown below. #pragma StackUse( <stack-depth> ) An alternate syntax that can be used outside of all procedures, but not for ISRs, is shown below.