What is EZAsm? Addressing modes Statement arguments Optimizations Variable declaration Statement Information Additional Information Using EZAsm Statements: Addition Subtraction Multiplication Division And OR Exclusive-OR Shift Left/Right Assignment If Else Syntax Compare Bit Test Errors Contacting the author
What is EZAsm?
EZAsm originally was an assembly language development tool for the Amiga. After I discovered the Palm Computing(R) Platform I ported it over and made many enhancements. EZAsm frees you from most of the user-unfriendliness associated with assembly language programming allowing you to concentrate more on your program. It combines 680X0 assembly language with parts of C. The result is highly optimized code, with a much shorter development time! Here are some of its advantages:
- You don't need to be thinking about what the "best way" to write a particular statement is, because your code is automatically converted into the fastest possible assembly statement(s).
- More structured. Compare and bit test statements can have braces and "else" like C. This lets you use assembly language in a whole new way! No more fooling with branch condition codes!
- C-like function calls! Every available Palm OS 3.5 API function and shared library call is supported. Backward compatible versions of functions are also supported.
- Your code is much more readable, and easier to debug. You can code nearly twice as fast, with fewer syntax errors.
- You can freely mix assembly statements with "EZAsm statements".
Traditionally, assembly language applications have always had the smallest executable size and the highest performance. In the Pilot environment, application size and speed are very important. Small assembly applications are relatively easy to program. Medium sized applications can take a long time to develop, and large ones...?? Using EZAsm, small to medium sized applications should be easy to develop and, after breaking down complex code into simpler pieces, it should make even large application development manageable.You need to be familiar with using Pila.exe, especially how it uses structure references.
Here are some links you might find useful ( sorry, some of these may be broken links ):
What's new for Version 1.37
Local variables are now automatically "mangled" so you don't have to worry about "Symbol value differs between first and second pass" errors from Pila.
Fixed a problem with variable offsets. In function arguments, if you loaded a large variable into a smaller one, under certain conditions, the offset would be off.
New
Fixed an optimization bug that caused problems after a series of variables were cleared.
New for Version 1.34
Now supports HostControl functions: HostTraceInit(), HostTraceClose() & HostTraceOutputTL(), great for debugging when combined with Palm Reporter!
Fixed up code handling function arguments to accommodate HostControl funtions and fixing possible string bug.
Cleaned up output formatting.
New for Version 1.32
Every currently available Palm OS 3.5 API fuction and Library call is supported.
New for version 1.30
Allowed for comments after variable declarations.
Fixed some problems in "funcs" file.
New for version 1.29
- Added support for 3.1 API functions.
New for version 1.1x/.2x
Even better optimizations! :) I've added a few new ones.
More stable programs. I noticed garbage creeping into the upper bytes of some API returns in D0 so in certain key places it now uses "ext.l d0" to clear them out.
Fixed empty Proc bug
Improved the string constants.
Some optimizations stopped working, got them turned back on.
Fixed a Global offset problem, and 'adjusted' one of the optimizations.
Had to cut way back on A0/D0 return substitution optimizations, API functions are clobbering A0 all over the place. You should notice an immediate improvement in the stability of your apps.
Fixed a numeric constant bug and improved them.
Enabled checking for correct number of arguments in API functions. I don't think this ever worked ;)
Squashed potential string bug.
Improved end-write.
Operand Legends
Operand Type
Mode [A] [B] [C] [D] [E] [F]
Dn * * * - * -
An * - * - - -
(An) * * * * * *
(An)+ * * * * * *
-(An) * * * * * *
d16(An) * * * * * *
d8(An,Xn) * * * * * *
16 bit addr * * * * * *
32 bit addr * * * * * *
d16(PC) * - - - * *
d8(PC,Xn) * - - - * *
immediate * - - - * -
bd(An,Xn) * * * * * * 68020/68030
([bd,An],Xn,od) * * * * * * 68020/68030
([bd,An,Xn],od) * * * * * * 68020/68030
bd(PC,Xn) * - - - * * 68020/68030
([bd,PC],Xn,od) * - - - * * 68020/68030
([bd,PC,Xn],od) * - - - * * 68020/68030
Global and local variables = d16(An)
<1-8> 1 - 8
<q> ( quick ) -128 - 127
<n> any byte, word, or long size number
Dn d0 - d7
An a0 - a7
{B} byte data size not allowed for An operands
bd 32 bit displacement
od 32 bit outer displacement
Xn a0 - a7 d0 - d7
Options: Examples:
size: .w .l a2.w a0.l
scale: *1 *2 *4 *8 a1*2 a0.w*4 ( 68020/68030 )
OPERANDS SIZES Addressing modes
Operand Legends
++
--
[C] <op> L,W,{B} *
+=
-=
Dn <op> [A] L,W,B
An <op> [A] L,W *
[D] <op> Dn L,W,B
[B] <op> <n> L,W,B
[C] <op> <1-8> L,W,{B} *
Examples:
Total ++
d1 += 10
Optional Args:
l, w, b
* When appropriate, these are optimized by making the size word
(.w) instead of long (.l) for "An" operands. It uses fewer cycles,
and the upper two bytes are correctly handled.
OPERANDS SIZES Addressing modes
Operand Legends
*=
Dn *= [E] W
Dn *= ## W *
/=
Dn /= [E] W
Examples:
d0 *= d1
d2 /= 2
Optional Args:
w,
s ( signed divs/muls )
* This optimization results in code that's larger then
"mulu" or "muls", but will execute much faster. Not all numbers
can be optimized. If the number doesn't work, "mulu"
or "muls" will be used.
( where ## is a word or byte length number )
OPERANDS SIZES Addressing modes
Operand Legends
&=
|=
Dn <op> [E] L,W,B
[B] <op> <n> L,W,B
[D] <op> Dn L,W,B
^=
[B] <op> Dn L,W,B
[B] <op> <n> L,W,B
Examples:
Mask &= %11010000
Flags |= $f0
Optional Args:
l, w, b
OPERANDS SIZES Addressing modes
Operand Legends
<<
>>
Dn <op> Dn L,W,B
Dn <op> 1-31 L,W,B *
[D] <op> 1 W
Examples:
d2 << d0
d1 >> 4
Optional Args:
l, w, b,
a = Preserves the sign bit by use of "asr" and "ext.l".
Use only with right shifts ( ">>" ).
* Normally you're limited to shifting 1-8, or using a
data register to hold higher shift values. This
optimized version is faster, and saves using a data register!
OPERANDS SIZES Addressing modes
Operand Legends
=
[B] = [A] L,W,{B}
An = [A] L,W
Examples:
temp = Total
(a1)+ = 0 w
Optional Args:
l, w, b
Compare and Bit test statements use this syntax:
operand <op> operand label
operand <op> operand {
.
.
}
operand <op> operand {
.
.
} else {
.
.
}
OPERANDS SIZES Addressing modes
Brace syntax
Operand Legends
>=
<=
!=
>
<
=
Dn <op> [A] L,W,{B}
An <op> [A] L,W
[B] <op> <n> L,W,B
(An)+ <op> (An)+ L,W,B
Examples:
Total >= 100 Over
pBitmapHnd != 0 {
MemHandleUnlock( pBitmapHnd )
}
Optional Args:
l, w, b,
s ( signed )
OPERANDS SIZES Addressing modes
Brace syntax
Operand Legends
=
!=
Dn:0-31 <op> 0-1 L
Dn:Dn <op> 0-1 L
[F]:0-7 <op> 0-1 B
[F]:Dn <op> 0-1 B
Examples:
d1:0 != 1 EvenRtn
($bfe001):6 = 0 LMBDown
d2:d0 = 1 {
rts
}
Optional Args: ( ignored )
Rules:
- No spaces inside first operand.
- Right operand can only be 0 or 1.
b forces operation to be byte
w " " " word
l " " " long
a preserves sign bit ( >> )
s signed ( *=, /=, compares )
( it's OK to use multiple arguments ( "w s" etc. ))
Also, see note in Statement Information
Saves registers you request at the start of a procedure and restores them before exiting. Yet another time saving feature.. :)
Usage: SAVER register list Example: SAVER d2-d4/a1-a3 Use at the top of your procedure or immediately following your variable declarations. Will generate these statements: movem.l d2-d4/a1-a3,-(a7) . . movem.l (a7)+,d2-d4/a1-a3
- Every available Palm OS 3.5 API function and shared library call is supported.
Backward compatible versions of functions, ..V10( ) ..V20( ), are also supported. See "funcs" data file for supported functions.
- Arguments must be separated by a space or tab. Use of additional ',' are ignored.
EvtGetEvent(&evt #evtWaitForever.w) ^ | space required
- Multi-line function arguments are supported.
err = DmDatabaseInfo( 0 CurrDBID &name &attR 0 &crDate 0 0 0 0 0 &typeR &creatorR )
- Address/Data registers, variables and other appropriate operands can be used for returns when convenient.
a3 = FrmInitForm( EventType.data+frmLoad.formID(a0) )Arguments:
- Optional size arguments '.b', '.w', '.l' can be added to function arguments and override the function argument's default size.
- All arguments in procedure declarations must have size arguments.
- EZAsm supports argument strings surrounded by double quotes. Strings are automatically NULL terminated. The following C character constants are supported:
\b backspace \f form feed \n newline \r carriage return \t horizontal tab \v vertical tab \\ backslash \" double quote \' single quote \nnn octal character value \xnn hex character value
Using HostControl Tracing functions and Palm Reporter
EZAsm now supports HostControl Tracing functions, which when used with the Palm Reporter, make debugging a lot nicer. The Palm Reporter is a Trace utility used with the Emulator. These functions send debugging information in real-time to the Reporter window. Reporter is available on Palm's Emulator page:
Palm Reporter
Tips on using Palm Reporter
- Load PalmTrace.dll into the same directory as your Emulator.
- On the Emulator go into Settings -> Tracing Options.. and choose Palm Reporter from the list.
- After you have set everything up, load and run Reporter's TracingApp.prc. This will verify that everything is working properly, and you'll see Reporter in action.
Using the functions
- Add the appErrorClass EQU at the top, and HostTraceInit() and HostTraceClose() at appropriate places in your code.
- * When using HostTraceOutputTL(), if you use data other than registers or declared variables ( that EZAsm knows the size of ) you need to specify a size argument so it came be properly pushed onto the Stack.
- The smallest data size that you can display is WORD "%d" "%x". Normally you could "cast" it to a WORD, or just load it into a WORD variable to display it.
- Be sure to precede appErrorClass with '#', otherwise Pila might have problems.
Example:
appErrorClass equ $8000 HostTraceInit() HostTraceOutputTL(#appErrorClass "Starting...") HostTraceOutputTL(#appErrorClass "(a3): %lx" (a3).l) ^ | size required * HostTraceClose()
Using EZAsm
- Create a .bat file that sets your path to: Pilrc, asdk\bin, asdk\inc and EZAsm
Here's mine: SET PATH=d:\ezasm;e:\asdk\asdk1a1\bin;e:\asdk\asdk1a1\inc;f:\pilrc-2.8;%PATH%- Create your .rcp file with your form definitions and run Pilrc against this file. Be sure to include it's .h file in your includes.
- Add your "res" directives, per Pila's documentation, at the bottom of your source file.
- Run EZAsm against your source file. This should produce a .asm file.
- Run Pila against your .asm file that was created. If no errors were reported you should now have a new .prc file.
Optimizations
EZAsm's output can't beat hand optimized code, but in many cases it will come close.
I've looked at the disassembled output of many 'hand coded' assembly programs and almost every one could benefit from being run through EZAsm, with a little re-coding.. ;) ( EZAsm doesn't try to optimize hard-coded assembly statements ) I've thrown in almost every trick in the book and then some! ;) If you haven't guessed by now, I'm crazy about optimizing, I've tried to squeeze every last cycle and/or use the least amount of bytes. The best part is you don't have to think about it!
Statement Information
- Statements can be indented as you like. Operands, operator, and arguments must be separated by at least one space or tab.
- Comments can begin in ANY column with "*" or ";", or after statements ( separated from last argument or operand ) using ";". Most comments are transferred to the output file.
- Operands supported: @141 (octal), $61 (hex), %1100001 (binary), 'a' (ASCII), 97 (decimal). ASCII strings in operands can contain a maximum of 4 characters ( 'MPEG' ). ( no quotes within quotes permitted )
- To make labels and symbols as compatible as possible, they aren't checked for illegal characters. Typically the first character must be a letter, underscore "_", or a period ".". The rest of the characters can be any of these plus 0-9.
- Use of ":" after labels is optional unless the label begins past column 1.
- Temporary labels of the form n$, where n consists of decimal digit(s), are supported. These labels are only in effect till the next non-temporary label is encountered. ( be careful of "hidden" labels generated by braces )
- D7 is used as a scratch register for many optimizations, so be careful if you use it.
- To reference memory locations ( without getting an error message? ;) ) you can use: ($1001acf) or $1001acf.
- You can also use '&' ( address of ) in statements: An = &var
- Most of the time it knows what size operation to use by the type of operands used. For other times, there are two ways you can force the operation to be a certain size:
d0 != 0 { b Use 'b', 'w' or 'l' as the last argument. d0.b != 0 { Use '.b', '.w' or '.l' immediately after 1st operand.- Labels and constants that are generated are in the range:
"_l0" to "_ln" Program labels "_c0" to "_cn" String constants Try to avoid accidentally using them.
Additional Informationerr equ -24 ... error: Symbol value differs between first and second pass
- This was a hassle before. With local variables now automatically "mangled" this should not be a problem. You do have to watch for local and global variables being the same.
This was the only Pila error message that might occur that I am aware of. This occurs because a local variable with the same name in different procedures is used, but at different offsets.BYTE evt[EventType] evt.eType.w != #appStopEvent ...
- Currently direct access to structure members isn't supported. One way to achieve the same result is to use "evt+EventType.eType(a6).w != ...".
- One thing that I've wanted to do for a long time is add support for both brace styles. EZAsm uses the old "K&R" style, and the "other" brace style ;) seems to be much more popular these days, I use it myself, but adding this to the code would be a really nasty job. It's on my list though.. ;)
- http://www.geocities.com/ezasm always contains the most up-to-date version. Unfortunately, many Pilot site's "local copy" is hopelessly out of date.
Variable DeclarationLONG foo bar WORD DMASave BYTE8 Buf[20] BYTE evt[EventType]
- All variables are aligned on an even boundary by default. You can change the alignment by using "BYTEn", "WORDn" or "LONGn" where 'n' is the boundary size in bytes.
- "var[n]" reserves n consecutive blocks of given size. This is a convenient way of allocating a chunk of the stack frame for structures, register save areas etc..
- "var[struct name]" will look through include files and compute the size of the structure. It looks for include files in the current directory, all directories in the "PILAINC" environment variable, the same directory pila.exe is located and in the "inc" directory on the same level as "...\bin\pila.exe". The search is case sensitive.
- You might find that some structures you need are not defined in "Pilot.inc". You can define your own structures per Pila's documentation.
- Variables must be separated by at least one space, or tab.
- Global variable declarations should occur before any Procedure, and must be surrounded by 'data' and 'code'. Local declarations should be the first statement(s) in any Procedure.
Errors
"Illegal argument""Illegal operand"The argument found was not valid for the operator. See the list of Addressing Modes for the operator. It must be lower case, and be separated from the operands by at least a space or a tab.
"Illegal size"One, or both, of the operands are: not valid for the operator, have an invalid number, or byte size was specified for an "An" operand ( {B} ). In most cases it's looking for "Dn" or "An" as an operand. ( look under Addressing Modes for a valid combination )
"Needs size argument"The size argument you specified is not valid for the operator.
"Label not found"It doesn't have enough size information about the operands to calculate an instruction size. You need to add an l, w, or b size argument.
"Brace mismatch"No matching label was found.
"Function not found"Checks are made when a closing brace ( "}" ) is hit, and when the end of source is reached. If the brace stack is "messed up" at that time, an error is given.
No API function or procedure matching your function name was found. Check case and spelling of function name. Check the "funcs" data file for supported function names.
Contacting the authorTry using EZAsm, I don't think you'll want to go back to "ordinary" assembly language programming. ;)
Your feedback is very important, if you have any suggestions for improvements, found bugs, or just want to say "Hey!", please send a message, I'd like to hear from you! Really! ;)
Enjoy!
Joe Siebenmann 2204 Pimmit Run Lane #1 Falls Church, VA 22043 ( USA )