| SHDesigns: Embedded Systems Design, Consulting and Developer Resources | Page hits: |
1. Lables with #asm blocks are not visible by the current C file even if they are declared global. The only way around this is to use a separate asm file.
2. Use bare functions to define #asm functions, they are better that #asm blocks as they provide a prototype, i.e.
void my_asmfunc(void)
{
#asm
... code ...
#endasm
}
The only thing the 'C' function adds is a lret at the end. Also, the my_asmfunc will be visible to 'C' programs.
Use near for code that needs to be in root memory:
near void my_near_asmfunc(void)
{
#asm
........
#endasm
}
This will only add the return after the asm code and a .cseg at the start.
Using 'C' function definitions to wrap asm code handles the name mangling between C and asm code. C code will have a '$' prepended to far functions and an '_' prepended to near functions.
3. Accessing local variables and parameters.
Use the #pragma offset_labels on
Then you will be able to access local and parameters via ix+.name
(you will need to preserve the IX register):
#pragma offset_labels on
int near asmfunc(int param1, long param2) // near will have asm name of _asmfunc
{
int lvar;
#asm
ld hl,(ix+.param1) ; you could also use _HL=param1 before the asm block
ld de,(ix+.lvar) ; access local varaiable
add hl,de
#endasm
return _HL; // return what the asm block left in hl
}
4. Global vars:
Lobal variables will need an underscore before the name:
int globvar; #asm ld hl,(_globvar) #endasm
5. Static Variables
Static variables can not be used in inline ASM code as the compiler uses an internal name that is unknown to the ASM blocks. You can get around this somewhat by using the register aliases shown in section 6.
6. Passing Regs to ASM code
The compiler can be used to pass regs to Inline ASM code. The variables _HL, _DE, _BC are aliases for the registers.
Example:
unsigned offset;
void add_index_offset()
{
// example of a static that will not be visible to ASM code
static int index;
_DE=offset;
_HL=index; // do _HL last as it is likely used to load others
#asm
xor a ; clear carry
adc hl,de
; HL is now index+offset
#endasm
return _HL;
}
If you write a function with an ASM block, you can use "return _HL" to return what the ASM code leaves in HL. This will actually not generate any code, but it will get rid of the warning of "function must return a value".
7. Getting rid of "variable not used" and "Function must return a value" warnings.
int my_asm_func(int param1, int param2)
{
#asm
ld hl,(ix+.param1)
ld de,(ix+.param2)
...........
#endasm
}
The above will generate 3 warnings. The compiler will warn about param1 and param2 not being used within the function and will complain about no return value.
You can turn off the warnings by surrounding the function with "#pragma warn" statements. But there is a better way:
int my_asm_func(int param1_notused, int param2_notused)
{
#asm
ld hl,(ix+.param1_notused)
ld de,(ix+.param2_notused)
...........
#endasm
return _HL;
}
Including "notused" in a parameter name will get rid of the warnings. The "return _HL;" will tell the compiler to return what the ASM block left in HL (no code is generated as functions normally return int's in HL.)