Softools WinIDE Tips

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.

Use a double colon in the _asm names to make them global:

#extern near int asmFunc(void)
#asm
_asmFunc::
....
ret

Note: the above will be visiable as "near asmFunc"
in C a near labels have a '_' prepended. Similarly, far functions
will need a '$' before the name:

#extern int asmFunc(void)
#asm
$asmFunc::
....
ret

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.

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.)