Darrin Massena (darrin@massena.com)
5 Oct 96
Enhancements by Wes Cherry (wesc@ricochet.net)
1 | Pila | |
---|---|---|
1.1 | Introduction | |
1.2 | The Pila Package | |
1.3 | Pila | |
1.4 | PilRC | |
1.5 | Copilot | |
1.6 | PilDis | |
1.7 | Other Tools | |
1.8 | Creating A Minimal Pilot Application With Pila |
2 | Pila Syntax | |
---|---|---|
2.1 | Pila Command-Line Syntax | |
2.2 | Statement Format | |
2.3 | Radix Specifiers | |
2.4 | Operators | |
2.5 | Directives |
3 | Pila Directives | |
---|---|---|
3.1 | align | |
3.2 | appl | |
3.3 | beginproc | |
3.4 | call | |
3.5 | code | |
3.6 | data | |
3.7 | dc | |
3.8 | dcb | |
3.9 | ds | |
3.10 | end | |
3.11 | endproc | |
3.12 | equ | |
3.13 | global | |
3.14 | include | |
3.15 | list | |
3.16 | local | |
3.17 | proc | |
3.18 | reg | |
3.19 | res | |
3.20 | set | |
3.21 | struct, endstruct | |
3.22 | systrap | |
3.23 | syslibtrap |
Appendix | |
A | The Making Of Pila |
B | Pilot.inc And Naming Conventions |
C | PalmOS API Calling Conventions |
D | 68000 Instruction Set Quick Reference |
1.1 Introduction
Pila is tool for developing applications written in 68000 Assembly Language for the USRobotics Pilot handheld computer. Pila combines the operations of assembling, resource compiling, and linking into a single program that takes a 68000 assembler source file with embedded or external resources as input and produces a Pilot executable (PRC) file as output. Pila is a 'Win32' console application and runs under Windows NT or Windows 95.
"An assembler? Who cares about assembly language any more?" While assembly language has fallen out of favor for creating the kind of big, slow, bloated, er, I mean feature laden, applications we run on our desktop computers today it is exactly what is needed for maximizing performance on a constrained device like the Pilot. Smaller programs leave more space for our data and other programs. Faster programs are not only more responsive but by spending more time idle they increase the Pilot's battery life. Have you looked at the quality of the code MetroWerks' compiler for Pilot produces? Let's just say there's room for improvement and leave it at that.
This document details Pila's features and syntax and provides a walkthrough demonstration of using Pila to create a minimal Pilot application. To create your own applications you'll need an understanding of 68000 assembly language programming as well as documentation on the PalmOS and its APIs. You might also be interested in the architecture and details of Motorola's 68328 microprocessor, the 68000 variant inside your Pilot.
The classic and most essential 68000 programming book in my library is Motorola's M68000 16/32-bit Microprocessor Programmer's Reference Manual (a.k.a. M68000UM). An online (PDF) version that also includes information on the rest of the 680x0 family of processors can be found at http://ticalc.org/pub/92/fargo/68kpm.zip. This book is a great reference but will not teach you assembly language. To learn more you'll definitely want to check out Robert Boys' M68K FAQ (http://www.sentex.net/~rboys/m68kfaq.html). I'm also told that the tutorial/reference that can be found at http://www.cs.cornell.edu/Info/Courses/Spring-95/CS314/toc.html is useful. Keep in mind that the assembler and environment used for that course is somewhat different from Pila and the Pilot.
The USRobotics FTP site (ftp://ftp.netcom.com/pub/pa/palm) has all the documentation they ship with their Pilot SDK. The documentation covers most of what you'll want to know about the PalmOS and its APIs. You'll need Adobe Acrobat to read them.
Motorola makes the MC68328 "DragonBall" integrated processor that is the heart of the Pilot and they have some great documentation online in PDF form. I highly recommend downloading and digesting the MC68328 (DragonBall) Integrated Processor User's Manual. You'll need Adobe Acrobat to read it.
Lastly, you should definitely check out the great Pilot Software Development site (http://www.massena.com/darrin/pilot/index.html) hosted by me for the latest dirt on Pila and for other Pilot programming tools, tips and tidbits, etc. Pila has its own page too (http://www.massena.com/darrin/pilot/pila.htm).
See Appendix A if you would like to know more about the making of Pila. Appendix B describes the conventions used in the Pilot.inc header file. For the curious, Appendix C describes what I know about the PalmOS API calling convention. Appendix D provides a quick reference card for the 68000 instruction set.
1.2 The Pila Package
The Pila package (Pila.zip) has all the tools you need to create a Pilot application on your Windows NT or Windows 95 PC. It may not include all the tools you want but it's a start anyway.
Files | Description |
---|---|
Pila.exe | Pila proper. Pila.exe acts as assembler, resource integrator, and linker |
Pilot.inc | Constants and data structures used by the PalmOS APIs |
PilRC.zip | A ZIP file containing Wes Cherry's Pilot Resource Compiler |
PilDis.zip | A ZIP file containing Bill Hunt's Pilot Disassembler |
Startup.inc | Standard startup code that every application should include |
Sample.asm | A sample application |
Sample.rcp | Sample resources, processed by PilRC to produce Pilot resource binaries |
Sample.bmp | The sample application's icon. Pila converts this to a 'tAIB' resource |
PilaUM.htm | This documentation |
readme.txt | Last minute notes you'll definitely want to read |
1.3 Pila
<.>
1.4 PilRC
PalmOS user interface elements like menus, forms, and icons are instantiated by means of PalmOS "resources". Wes Cherry has written a resource compiler, PilRC, to make the task of creating resources easier. PilRC takes as input a textual description of an application's user interface elements and compiles them down to PalmOS binary resources. In turn, Pila can incorporate these resources into an application by means of the res directive.
The included sample program, Sample.asm, illustrates how this is done. Unzip PilRC.zip and read PilRC.txt for an explanation of PilRC's syntax.
The PilRC package also comes with a handy form resource previewer, PilRCUI, which cuts the form editing cycle from edit, assemble, download, launch, preview, repeat to the much quicker edit, preview, repeat. Assemble and download when you know you've got it right.
1.5 Copilot
After you create your program there's a good chance you'll be wanting to debug it. Greg Hewgill has written an excellent Pilot Emulator that runs beautifully on Windows 95/NT PCs and includes a symbolic debugger. Set a command-line switch and Pila will incorporate Copilot-compatible symbols in your Pilot application, ready to debug. Although Copilot is an essential tool for any PC-hosted Pilot development effort it is updated often so I don't include it in the Pila package. Download the latest Copilot from Greg's Copilot Page (http://userzweb.lightspeed.net/~gregh/pilot/copilot).
1.6 PilDis
There is much to be learned by examining the code of available Pilot applications. Bill Hunt has created a tool, PilDis, that will disassemble code binaries. As of this writing I have not spent much time using PilDis but since a disassembler is a tool no hacker can be without so I've included it. Unzip PilDis.zip and read the PilDis.txt for details on its usage. Note that Copilot can be also disassemble Pilot applications. Its primary advantage is that it understands application symbols so its output is more readable. The primary disadvantage of Copilot is that you have to hotsync your application into it before disassembling.
1.7 Other Tools
I'm helping coordinate the development of more Pilot development tools. The status and availability of these tools change often so check Pilot Software Development for the latest information. If you are working on, or interested in working on Pilot development tools please send me mail.
1.8 Creating A Minimal Pilot Application With Pila
The purpose of this walkthrough is to demonstrate the Pila-specific aspects of writing a Pilot program, not to illustrate Pilot programming in general. I've kept the example as simple as possible and have even eliminated features that almost every Pilot application will contain (e.g., a main form, an event handling loop, an icon). The Pila Package includes a more complete application, Sample.asm, that illustrates form creation, event handling, and the like.
Start things off by opening your text editor with the new file "Hello.asm". You guessed it, we're going to recreate the classic "Hello world" application for the Pilot. The actual code will be kept very simple (just enough to invoke a dialog) because it's everything around the code that's important for you to know in order to use Pila. Enter or cut/paste the following lines of code as you see them and when you're done you'll have a ready-to-assemble application.
; Hello.asm -- a minimal Pilot application to be assembled by Pila
This is just a comment line. I've heard that all good programs should have at least one comment.
appl "Hello", 'hllo'
The appl
directive sets the application's name and id. The name
will show up under its icon and the type must be unique amongst all Pilot
applications. USRobotics maintains a registry to ensure app ids are unique.
According to the USRobotics document Cookbook.PDF, "Ask Palm Developer
Support for a unique creator ID for your application and use that ID to avoid
overwriting other applications' databases (email: devsupp@palm.com)."
include "Pilot.inc"
The Pilot.inc header file is a huge list of structures and equates defining symbols for everything you need to call PalmOS APIs. Hello uses several of these symbols (e.g., sysTrapFrmAlert, sysAppLaunchFlagNewStack). See Appendix B for details on Pilot.inc and how to convert between the names you'll see in USRobotics' documentation and the names in Pilot.inc. The include directive allows us to incorporate other files in our assembly.
include "Startup.inc"
A special startup sequence is needed to fully initialize your Pilot application after loading. This sequence is common to all applications so I precreated it for your convenience. IMPORTANT: the startup function must be the very first function in your program. Always include Startup.inc before any of your own code or data.
kidrHelloAlert equ 1000 kidrHelpString equ 1001 kidrPREF equ 1 kidrTVER equ 1
These equates define symbolic names for the various resources in the Hello apps. Symbolic names are easier to change later, if necessary.
code
After a code directive all code and data bytes are placed in the code section of the Pilot executable. Similarly, the data directive (not used in our Hello app) causes subsequent code and data to be placed in the data section of the application. The res directive causes subsequent code and data to be placed in the specified resource.
PilotMain(cmd.w, cmdPBP.l, launchFlags.w)
The startup code in Startup.inc calls the function PilotMain after it is done initializing the app. Three arguments are passed to PilotMain (cmd, cmdPBP, and launchFlags). Pila takes these arguments and generates suitable offsets from the base pointer (a6) for them. Note that the type of the argument is specified after the period. Allowable types are .b, .w and .l
local err.w ; neither of these locals are used in this example local evt.EventType
This defines the local variables for PilotMain. Locals are also accessed via offsets from a6. Note that types can be structures defined in pilot.inc.
beginproc
This marks the beginning of the procedure. Pila will automatically insert a link a6,#nnnn instruction where nnnn is the total size of all locals. This saves the old base pointer and sets up a new one for this function. Buy a book on 68000 assembly language programming if this doesn't mean anything to you.
tst.w cmd(a6) ;sysAppLaunchCmdNormalLaunch is 0 bne PmReturn ;not a normal launch, bag out
As covered in USRobotics' documentation, PilotMain is called under many circumstances -- including at HotSync time! This test ensures "Hello world!" only pops up when we want it to (e.g., not during hotsync, not during 'find' operations).
systrap FrmAlert(#kidrHelloAlert.w)
systrap is a special pila directive which emits the code to push the arguments on the stack, call the trap and then clean up the stack. It will emit code equivalent to:
move.w #kidrHelloAlert,-(a7) ;push alert id on stack trap #15 ;PalmOS API call dc.w sysTrapFrmAlert ;invoke the alert dialog! addq.l #2,a7 ;pop alert id off stack
This is the assembly language equivalent to 'FrmAlert(kidrHelloAlert);' in 'C' and illustrates how to call PalmOS APIs. See Appendix C for more information on PalmOS API calling conventions. The symbol for sysTrapFrmAlert is defined in Pilot.inc. In the end, all the PalmOS APIs are called through the 'trap' mechanism, similar to the Macintosh mechanism for calling Toolbox routines.
PmReturn endproc
endproc emits the unlk and rts instructions for you. It is required if you use beginproc.
This completes the PilotMain function. That's the entire program code for Hello.
Next we move on to the resource section that most applications will have. Typically PilRC would be used to create these resources but they can also be defined inline as demonstrated here:
res 'Talt', kidrHelloAlert ;Alert resource dc.w informationAlert ;alertType dc.w kidrHelpString ;helpRscID dc.w 1 ;numButtons dc.w 0 ;defaultButton dc.b 'Red Alert', 0 ;title text dc.b 'Hello world!', 0 ;message text dc.b 'Most excellent!', 0 ;button text
The res directive is used here to define an Alert ('Talt') resource that is read by the FrmAlert API and used to build the dialog box you'll see. This is the complete data definition of the resource.
res 'tSTR', kidrHelpString dc.b 'I am a Pilot programming stud!', 0
You may have noticed that the Alert resource references a help resource. This shows up when the user clicks on the little info symbol in the upper-right corner of the dialog box. We use the res directive again to define the help string (not very helpful in this case).
res 'tver', kidrTVER dc.b '1.0', 0
All applications should have a version resource. I'm not sure this is enforced anywhere but it's a good idea anyway.
res 'pref', kidrPREF dc.w sysAppLaunchFlagNewStack|sysAppLaunchFlagNewGlobals|sysAppLaunchFlagUIApp|sysAppLaunchFlagSubCall dc.l $1000 ; stack size dc.l $1000 ; heap size
The 'pref' resource defines the application launch flags, stack size, and heap size. USRobotics' documentation indicates that it isn't actually used yet but applications are required to include it to pave the way for future PalmOS enhancements.
Well, that's all there is to it. Save Hello.asm and assemble it with the command "Pila Hello.asm". If you got it right, out pops Hello.prc. Use instapp.exe ("instapp Hello.prc") and HotSync to download Hello to your Pilot. Press the applications button on your Pilot and you'll see Hello there, without an icon. It is valid but not very interesting to have an icon-less program. Hello was done this way to keep this example short. Follow the proper example in Sample.asm to define icons for your own apps.
Select Hello from the applications dialog and, baring data entry errors, you'll see "Hello world!". Try the info/tip icon. Sooner or later your curiosity or boredom will lead you to press the "Most excellent!" button. As you can see from the code, when FrmAlert returns PilotMain simply exits. When you try this you'll find that the program doesn't disappear. Why not? Pilot applications are executed by the 'Shell' and the rule is that one of them must be running at all times. If it terminates and returns to the Shell, the Shell just launches it again! Leave Hello by pressing one of the other application buttons.
Note that this fine piece of software engineering is only ~400 bytes long. The Pilot Memory application only reports application sizes rounded up to the nearest 'K' so most users won't fully appreciate your studliness at producing such a micronic application. In the face of this ignorance I recommend the time proven software development practice known as "bragging". The important thing is that the memory savings are real.
2.1 Pila Command-Line Syntax
Pila [options] sourcefile
Options specify options that modify assembler actions. Precede each option with a '-'. Separate options with spaces.
Option | Description |
l | Generate a listing file. The listing file has same name as the source file suffixed with '.lis'. |
c | Show full constant expansions for DC directives. |
d | Generate a bunch of debug output. This option is of little use to most people. |
s | Generate Copilot-compatible symbols. |
r | Do not generate 'code' and 'data' resources. |
Pila assembles the sourcefile, integrates any resources, and outputs a Pilot resource database (PRC) file with the same name as the source file suffixed with '.prc'. The application's name as it appears on the Pilot is defined by the appl directive or a 'tAIN' resource, not its DOS/Windows file name.
Listing files show the expansion of any directives that generate code or additional symbols (beginproc, endproc, call, systrap, syslibtrap, global). Listing output can be enabled and disabled from within a program by using the list directive. Pilot.inc is a very large include file and is bracketed by listing disable/enable directives.
Pila generated code symbols are produced inline in the code section directly following each procedure. The symbol format follows that of MacsBug and is compatible with Copilot's debugger. As of this version, only code symbol are supported, no data symbols.
With the '-r' option Pila becomes more of a PRC builder than an assembler. It collects all the resources specified with res directives and bundles them into a valid Resource Database (PRC) that can be downloaded to the Pilot. In this mode Pila has two main uses. First, an experimenter could deconstruct an existing PRC file with prc2bin, modify any of its resources, and reconstruct the PRC file (unaltered aside from the intentional changes) with Pila. Second, Pila can be used as a backend for any language or tool that can generate the appropriate 'code' and 'data' (or other) resources. Used this way, the language/tool would generate binary files containing code and/or preinitialized data and a small assembly stub, basically just a list of res directives, would be used to include those resources along with any other resources, say, forms and menus created with PilRC, that were desired for the final PRC.
2.2 Statement Format
Pila follows the Motorola syntax for the 68000 microprocessor. The general format of a statement is:
[Name] [Operation] [Operands] [;Comment]
Name defines a label that can be accessed from elsewhere in the program. If the statement has a data directive (e.g., dc, ds), this field is a variable name. If the statement has an instruction, this field is a code label. Names must start with a letter or one of the characters '_', '?', '$', '@' and may contain letters, numbers and the characters '_', '?', '$', '@'. Names are case-sensitive and significant to fifty-two characters. Code labels may be followed by a ':' which is ignored.
Operation states the action of the statement. This field is either a 68000 instruction or a directive and is case-insensitive. The Motorola syntax has instructions suffixed by the size of data they operate on (e.g., clr.b, add.w, move.l). When the data size is unspecified, Pila assumes it's a word (same as a '.w' suffix). Pila does not support the MIT syntax which allows the period to be omitted from the data length suffix. A program that converts from MIT to Motorola format can be found at ftp://nyquist.ee.ualberta.ca/pub/motorola/portable/mit2mot.tar.gz.
Operands list the item(s) to be operated on. Operands are separated by commas.
Comment provides a comment for the user. This field is for documentation purposes only and is ignored by the assembler. Comments may begin with a semicolon or an asterisk.
2.3 Radix Specifiers
To indicate the radix of a constant, place the specifier at the beginning of the number.
Specifier | Radix |
none | Decimal |
$ | Hexadecimal |
% | Binary |
@ | Octal |
Hexadecimal digits can be upper or lower case. Floating-point constants are not supported.
2.4 Operators
Sorted by order of precedence from highest to lowest:
Operator | Syntax | Description |
. | structure.member | Structure member |
- | - expression | Unary minus |
~ | ~ expression | One's complement |
(, ) | ( expression ) | Parenthesized expression |
<< | expression << count | Shift left |
>> | expression >> count | Shift right |
| | expression | expression | Logical OR |
& | expression & expression | Logical AND |
* | expression * expression | Multiply |
/ | expression / expression | Divide |
\ | expression \ expression | Modulo |
+ | expression + expression | Add |
- | expression - expression | Subtract |
3.1 align
Syntax:
align size
Description:
The align directive forces emitted code and data to be aligned on the next multiple of size. The beginproc directive automatically emits an align 2 directive because all code must be aligned on two-byte boundaries.
3.2 appl
Syntax:
appl "applicationname", 'apid'
Description:
The appl directive defines the application's name and unique four character identifier. The application name must be 31 characters or less and shows up under its icon in the Pilot application launcher if it is not overridden by a 'tAIN' resource. The application's identifier is supposed to be registered with USRobotics to guarantee that no other application uses the same identifier. If this identifier collides with that of another application on the same Pilot then all manner of nasty problems will ensue (e.g., hotsyncing of those applications and their data records won't work properly).
If the appl directive is omitted Pila will default the application name to its file name (e.g., "Sample.asm" becomes "Sample") and the four character id will be 'temp'. [NOTE: because of the problems that can occur if one forgets to add an appl directive and releases their app to the public I'll probably introduce an assembly-time error if the appl directive is not present]
3.3 beginproc
Syntax:
beginproc
The beginproc directive marks the beginning of a procedure. It instructs Pila to emit the proper link a6,#nnn instruction where nnn is the negative sum of the sizes of all locals.
3.4 call
Syntax:
call procname([argument.size][,argument.size]...)
The call directive emits code to push the arguments on the stack, invoke the procedure and then clean up the stack. Argument size must be specified via .b, .w or .l. When passing pointers to locals or globals, prefix the argument with the & character. Constants must be prefixed with the # character and must also specify the size via .b, .w., and .l.
3.5 code
Syntax:
code
The code directive places the assembler in code generation mode. Pila is always considered to be in one of three modes: code generation, data generation, or resource generation. The mode dictates where any assembler output will reside. For example, a dc.b directive while in code generation mode places the constant data in the code section, not the data section. The directives code, data, and res set the compiler in the respective generation mode. The default mode is code generation.
You change generation scope as many times as you want, interspersing code and data.
In general, read-only variables (e.g., constant strings) should be defined within the code scope to save runtime memory. Code is accessed in-place in Storage memory while data is duplicated in Dynamic memory at application load time. Note, if you embed data within your code, use the align directive before any subsequent code to ensure it is placed on a two-byte boundary.
3.6 data
Syntax:
data
The data directive places the assembler in data generation mode. Pila is always considered to be in one of three modes: code generation, data generation, or resource generation. The mode dictates where any assembler output will reside. For example, a dc.b directive while in code generation mode places the constant data in the code section, not the data section. The directives code, data, and res set the compiler in the respective generation mode. The default mode is code generation.
As this implies, code can be assembled into the data section. Doing so is ill-advised because code in the data section is duplicated in Dynamic memory at load time, whereas code in the code section is executed in-place in Storage memory. But if you want to do some sort of wicked self-modifying hack you can.
Be sure to include a data directive before defining any writable global variables. Failing to do so will result in a memory error when your code attempts to write to the variable (stored in read-only Storage memory!).
3.7 dc
Syntax:
[name] dc.b initializer [, initializer]... [name] dc.w initializer [, initializer]... [name] dc.l initializer [, initializer]...
The dc (data constant) directive defines a list of constant data bytes, words, or longs. Initializers may be a numerical value, an expression, or a string. Strings are surrounded by single quotes and are not automatically null-terminated. The dc.w and dc.l directives force their data to begin on a word boundary.
3.8 dcb
Syntax:
[name] dcb.b blocksize, initializer [name] dcb.w blocksize, initializer [name] dcb.l blocksize, initializer
The dcb (data constant block) directive defines a constant block of bytes, words, or longs. The size (in bytes) of the constant block is the blocksize times the size of the block type (byte, word, long). The initializer is repeated blocksize times. Initializers may be a numerical value or an expression. The dcb.w and dcb.l directives force their data to begin on a word boundary.
3.9 ds
Syntax:
[name] ds.b blocksize [name] ds.w blocksize [name] ds.l blocksize
The ds (data storage) directive defines an uninitialized (initialized to zero at run time) block of bytes, words, or longs. The size (in bytes) of the memory block is the blocksize times the size of the block type (byte, word, long). The advantage of ds over dcb is that the space for the data is only allocated when the application loads. The ds.w and ds.l directives force their data to begin on a word boundary. [NOTE: currently Pila doesn't separate initialized from uninitialized data. This means that ds blocks still take space in the PRC file's stored data section (same as dcb blocks). This will be fixed.]
3.10 end
Syntax:
end
The end directive forces Pila to stop assembly immediately. The end directive is optional.
3.11 endproc
Syntax:
endproc
The endproc directive marks the end of a procedure. It instructs Pila to emit an unlk and rts instruction. If the '-s' (symbols) switch is specified on the command line then endproc also emits a Copilot-compatible symbol at the end of the procedure.
3.12 equ
Syntax:
name equ expression name equ 'string'
The equ directive evaluates expression and assigns its value to name. After definition, all uses of name are replaced by its value. Unlike set, equ does not allow equates to be redefined.
3.13 global
Syntax:
global globalname.size
The global directive declares procedure global variables. The global directive must occur after a data directive. The size may be specified by .b, .w or .l or by the name of a structure defined with the struct directive. Pilot structures are defined in pilot.inc. .size may also be a constant integer specifying the size in bytes.
3.14 include
Syntax:
include "includefile"
The include directive inserts source code from includefile into the current source file during assembly. If the path to includefile is not fully specified Pila looks for the include file in the following places, in order:
1. the same directory as the source file
2. the current directory
3.
each of the semicolon-separated directories specified by the environment
variable PILAINC (e.g., set PILAINC=c:\common\include;c:\pila\inc)
4. the
directory Pila.exe is located in
5. the 'inc' directory that is a sibling of
the directory Pila.exe is located in. For example, if Pila.exe is in c:\ASDK\bin
its sibling inc directory would be c:\ASDK\inc.
3.15 list
The list directive disables and enables output to the listing file. It only takes effect if the '-l' switch was specified on the Pila command line.
3.16 local
Syntax:
local localname.size
The local directive declares procedure local variables. The local directive must occur after a proc directive and before a beginproc directive. The size may be specified by .b, .w or .l or by the name of a structure defined with the struct directive. Pilot structures are defined in pilot.inc. .size may also be a constant integer specifying the size in bytes.
3.17 proc
Syntax:
proc procname([argument][,argument]...)
The proc directive declares a procedure. Procedures may have zero or more arguments. Arguments must have a size sepecified via .b, .w or .l.
3.18 reg
Syntax:
name reg registerlist
The reg directive defines a named list of registers as accepted by the movem instruction. The Motorola convention for register lists is used. Registers are separated by '/' and register ranges are denoted by '-'. For example, d0/d1/d4-d7/a0-a3/a6 is a register list that includes the registers d0, d1, d4, d5, d6, d7, a0, a1, a2, a3, and a6. It is invalid to a declare a range across data and address registers (e.g., d5-a3).
3.19 res
Syntax:
res 'type', id res 'type', id, "datafile"
The res directive places the assembler in resource generation mode. Pila is always considered to be in one of three modes: code generation, data generation, or resource generation.. The mode dictates where any assembler output will reside. For example, a dc.b directive while in code generation mode places the constant data in the code section, not the data section. The directives code, data, and res set the compiler in the respective generation mode. The default mode is code generation.
The second form of the res directive allows the resource data to be read from a binary data file rather than defined inline. Use the second form to include resources generated by Wes Cherry's Pilot Resource Compiler (PilRC).
3.20 set
Syntax:
name set expression name set 'string'
The set directive evaluates expression and assigns its value to name. After definition, all uses of name are replaced by its value. Unlike equ, set equates can be redefined any number of times.
3.21 struct, endstruct
Syntax:
struct structname member.size [member.size]... endstruct
The struct directive declares a structure named structname. The members of the structure are specified next where the .size may be specified via .b, .w or .l or by the name of a previously defined structure. Additionally .size may be a constant integer n which declares a member of n bytes.
3.22 systrap
Syntax:
systrap systrap([argument][,argument]...)
The systrap directive emits code to push the arguments on the stack, invoke the trap and then clean up the stack. Argument size must be specified via .b, .w or .l. When passing pointers to locals or globals, prefix the argument with the & character. Constants must be prefixed with the # character and must also specify the size via .b, .w., and .l.
3.23 syslibtrap
Syntax:
syslibtrap libtrap([argument][,argument]...)
The syslibtrap directive emits code to push the arguments on the stack, invoke the library trap and then clean up the stack. Argument size must be specified via .b, .w or .l. When passing pointers to locals or globals, prefix the argument with the & character. Constants must be prefixed with the # character and must also specify the size via .b, .w., and .l.
Appendix A: The Making Of Pila
The first time I saw a Pilot I was struck by all kinds of software ideas -- programs I could create to make this device more useful and entertaining for me and for others. If only I had the tools to do so. First, I needed a Pilot. Pay out the cash, no problem. Then I needed software development documentation. After a while, USRobotics released SDK documentation on their FTP site. Great! Now all I needed was a set of PC-based cross-development tools for creating Pilot applications. USRobotics' SDK? Mac only. Hmm...
I tired of hoping for a PC-based SDK and started building my own tools. My first set of tools leveraged the IDE and 68000 C Compiler of Microsoft's Visual C++ Cross-Development Edition for Macintosh. This is swell but has two drawbacks. First, Visual C++ Mac edition can be quite expensive (I don't want to create all the Pilot apps myself!) and second, it doesn't come with a 68000 assembler. Perhaps I could do something about this.
To my surprise (before I realized that anything can be found on the Net if one looks long enough) there are several public domain assemblers for the 68000. A few are available in source form and one of them, an assembler written by Paul McKee at North Carolina State University in 1986, looked like a good match for the job. I decided to build my Pilot assembler on this base. You can find Paul McKee's original assembler and a partially working 68000 emulator (68asmsim.zip) where I did on a backup site for Motorola's BBS (ftp://nyquist.ee.ualberta.ca/pub/motorola). There's lots of other great stuff there.
With many thanks to Paul McKee I started hacking his assembler to meet my needs. I wanted the assembler to produce fully formed Pilot executables without the need for an external linker or resource compiler. The lack of a linker may make creating extremely large applications more difficult (good!) but it saves time now and I can write one later if needed. A resource compiler would certainly be nice but I'd rather spend my time creating high level GUI tools for resource creation and editing. In the meantime, a tweak or two to the assembler would let it do the job of integrating resources into the final executable.
So I modified the assembler to build a list of resources as it assembled. With the help from some new directives, code becomes one resource, data becomes another, and additional Pilot-specific resources can be defined in-line or included. I borrowed some PRC-building code from exe2prc, a tool I created for converting Win32 EXEs into Pilot PRCs, and bolted it to the end of the assembler to convert the final collection of resources into something the Pilot could recognize.
Wes Cherry had some great ideas for some new directives and syntax for Pila to make many common operations (procedure parameter definition, procedure calling, structure definition, API calling, local and global variable definition) as easy as they are in high level languages like 'C'. Wes took a copy of the Pila sources, implemented his (now indispensable) extensions, fixed a couple Pila bugs, and even updated the documentation!
Other tools have arrived on the scene to help complete the set of Pilot development tools. Wes Cherry's PilRC is a resource compiler that saves hours of time and makes things possible that wouldn't be practical without it. Greg Hewgill's Copilot Pilot Emulator includes a Pila-compatible symbolic debugger. Bill Hunt's PilDis is a disassembler that can provide a peek into the innards of existing Pilot applications.
Appendix B: Pilot.inc And Naming Conventions
Pilot.inc is the assembly language equivalent to USRobotics' Pilot.h and all the other header files it includes. Here's a guide for translating between the types and names you'll find in 'C' programs and USRobotics' documentation and the ones found in Pilot.inc.
B.1 Structures
A 'C' structure like this:
typedef struct FormLabelType { Word id; PointType pos; FormObjAttrType attr; FontID fontID; Char *text; } FormLabelType;
Becomes this struct definition:
struct FormLabelType id.w pos.PointType attr.w fontID.w text.l endstruct
Members nested inside of structures containing structures can be reached by using the . operator. For pointers to structures the type of the pointer is declared by the structure name. For example, after loading a pointer to a FormLabelType structure into A0 one can use FormLabelType.pos.x(A0) to perform the equivalent to the 'C' operation formLabel->pos.x. For a local declared as local formLabel.FormLabelType one would use formLabel.pos.x(a6). A similar global would be formLabel.pos.x(a5).
B.2 Unions
Unions aren't currently handled very well by pila. To deal with them use something like this: EventType.data+ctlEnter.controlId(a0) where ctlEnter is a struct defined in pilot.inc which specifies the ctlEnter union of the data member of EventType.
B.3 Bitfields
A bitfield is an interesting construct combining two properties: a count of bits and a bit offset within a number. An operation often performed with bitfields, especially single-bit fields, is a masking operation. I wanted to make both properties of bitfields available to assembly language programmers and to make masking operations convenient as well. So a set of bitfields like this:
typedef struct ControlAttrType { Byte usable :1; // set if part of ui Byte enabled :1; // set if interactable (not grayed out) Byte visible :1; // set if drawn (set internally) Byte on :1; // set if on (checked) Byte leftAnchor :1; // set if bounds expand to the right // clear if bounds expand to the left Byte frame :3; } ControlAttrType;
Becomes a set of equates like this:
ControlAttrType_usable_shift equ 0 ControlAttrType_usable_count equ 1 ControlAttrType_usable_mask equ $00000001 ControlAttrType_enabled_shift equ 1 ControlAttrType_enabled_count equ 1 ControlAttrType_enabled_mask equ $00000002 ControlAttrType_visible_shift equ 2 ControlAttrType_visible_count equ 1 ControlAttrType_visible_mask equ $00000004 ControlAttrType_on_shift equ 3 ControlAttrType_on_count equ 1 ControlAttrType_on_mask equ $00000008 ControlAttrType_leftAnchor_shift equ 4 ControlAttrType_leftAnchor_count equ 1 ControlAttrType_leftAnchor_mask equ $00000010 ControlAttrType_frame_shift equ 5 ControlAttrType_frame_count equ 3 ControlAttrType_frame_mask equ $000000e0 ControlAttrType_sizeof equ 1
The structure name is prepended to the member names and three symbols are generated for each field. The symbols are suffixed with _shift, _count, and _mask respectively to indicate their use. Note that although the masks look 32-bit (8 digits long) they don't have any inherent size. Like all other operands, the amount of the mask used is specified by the operation/instruction.
B.4 APIs
APIs are called by executing a trap #15 followed by a two-byte API index. The PalmOS trap handler uses the API index to look up the API's address and calls it. API indexes are named the same as the APIs proceeded by 'sysTrap'. So, 'EvtGetEvent' becomes 'sysTrapEvtGetEvent'. The systrap directive makes it easy to call APIs. When using systrap specify the trap name without the sysTrap prefix, i.e., systrap EvtGetEvent(&evt(a6), #evtWaitForever.w)
Appendix C: PalmOS API Calling Conventions
All I know about the PalmOS API calling conventions I've discovered by examining MetroWerks-compiled PRC files, the Pilot ROM, and quite a bit of trial and error. I think this information is correct but stay alert as you write your code.
The PalmOS uses the 'C' (aka cdecl) calling convention. The caller pushes the arguments on the stack last to first (right to left) and is responsible for popping them off after the API returns. APIs preserve all registers except D0 and A0. [I'm not sure about D1]. APIs that return pointers return them in the A0 register. All other APIs return their values in the D0 register.
All arguments are word-aligned on the stack as per Motorola conventions. That is, a byte pushed on to the stack actually consumes a word with the byte value in the upper half of the word.
Several registers have special purposes. As mentioned above, D0 and A0 are used to return values from APIs. A7 is the stack pointer. A6 is used as a local frame base pointer. A5 points to a location within the application's data section. All global variable accesses are performed relative to A5.
Appendix D: 68000 Instruction Set Quick Reference
I found this at http://www.freeflight.com/fms/comp/CPUs/68000.txt and will save you some time by reprinting it here.
Motorola 68000 Instruction Set. ------------------------------- Condition Codes --------------- Assembler Data Instruction Description Syntax Size X N Z V C ----------------------- --------- ---- --------- ABCD Add BCD with extend Dx,Dy B-- * U * U * -(Ax),-(Ay) ADD ADD binary Dn,<ea> BWL * * * * * <ea>,Dn ADDA ADD binary to An <ea>,An -WL - - - - - ADDI ADD Immediate #x,<ea> BWL * * * * * ADDQ ADD 3-bit immediate #<1-8>,<ea> BWL * * * * * ADDX ADD eXtended Dy,Dx BWL * * * * * -(Ay),-(Ax) AND Bit-wise AND <ea>,Dn BWL - * * 0 0 Dn,<ea> ANDI Bit-wise AND with Immediate #<data>,<ea> BWL - * * 0 0 ASL Arithmetic Shift Left #<1-8>,Dy BWL * * * * * Dx,Dy <ea> ASR Arithmetic Shift Right ... BWL * * * * * Bcc Conditional Branch Bcc.S <label> BW- - - - - - Bcc.W <label> BCHG Test a Bit and CHanGe Dn,<ea> B-L - - * - - #<data>,<ea> BCLR Test a Bit and CLeaR ... B-L - - * - - BSET Test a Bit and SET ... B-L - - * - - BSR Branch to SubRoutine BSR.S <label> BW- - - - - - BSR.W <label> BTST Bit TeST Dn,<ea> B-L - - * - - #<data>,<ea> CHK CHecK Dn Against Bounds <ea>,Dn -W- - * U U U CLR CLeaR <ea> BWL - 0 1 0 0 CMP CoMPare <ea>,Dn BWL - * * * * CMPA CoMPare Address <ea>,An -WL - * * * * CMPI CoMPare Immediate #<data>,<ea> BWL - * * * * CMPM CoMPare Memory (Ay)+,(Ax)+ BWL - * * * * DBcc Looping Instruction DBcc Dn,<label> -W- - - - - - DIVS DIVide Signed <ea>,Dn -W- - * * * 0 DIVU DIVide Unsigned <ea>,Dn -W- - * * * 0 EOR Exclusive OR Dn,<ea> BWL - * * 0 0 EORI Exclusive OR Immediate #<data>,<ea> BWL - * * 0 0 EXG Exchange any two registers Rx,Ry --L - - - - - EXT Sign EXTend Dn -WL - * * 0 0 ILLEGAL ILLEGAL-Instruction Exception ILLEGAL - - - - - JMP JuMP to Affective Address <ea> - - - - - JSR Jump to SubRoutine <ea> - - - - - LEA Load Effective Address <ea>,An --L - - - - - LINK Allocate Stack Frame An,#<displacement> - - - - - LSL Logical Shift Left Dx,Dy BWL * * * 0 * #<1-8>,Dy <ea> LSR Logical Shift Right ... BWL * * * 0 * MOVE Between Effective Addresses <ea>,<ea> BWL - * * 0 0 MOVE To CCR <ea>,CCR -W- I I I I I MOVE To SR <ea>,SR -W- I I I I I MOVE From SR SR,<ea> -W- - - - - - M OVE USP to/from Address Register USP,An --L - - - - - An,USP MOVEA MOVE Address <ea>,An -WL - - - - - MOVEM MOVE Multiple <register list>,<ea> -WL - - - - - <ea>,<register list> MOVEP MOVE Peripheral Dn,x(An) -WL - - - - - x(An),Dn MOVEQ MOVE 8-bit immediate #<-128.+127>,Dn --L - * * 0 0 MULS MULtiply Signed <ea>,Dn -W- - * * 0 0 MULU MULtiply Unsigned <ea>,Dn -W- - * * 0 0 NBCD Negate BCD <ea> B-- * U * U * NEG NEGate <ea> BWL * * * * * NEGX NEGate with eXtend <ea> BWL * * * * * NOP No OPeration NOP - - - - - NOT Form one's complement <ea> BWL - * * 0 0 OR Bit-wise OR <ea>,Dn BWL - * * 0 0 Dn,<ea> ORI Bit-wise OR with Immediate #<data>,<ea> BWL - * * 0 0 PEA Push Effective Address <ea> --L - - - - - RESET RESET all external devices RESET - - - - - ROL ROtate Left #<1-8>,Dy BWL - * * 0 * Dx,Dy <ea> ROR ROtate Right ... BWL - * * 0 * ROXL ROtate Left with eXtend ... BWL * * * 0 * ROXR ROtate Right with eXtend ... BWL * * * 0 * RTE ReTurn from Exception RTE I I I I I RTR ReTurn and Restore RTR I I I I I RTS ReTurn from Subroutine RTS - - - - - SBCD Subtract BCD with eXtend Dx,Dy B-- * U * U * -(Ax),-(Ay) Scc Set to -1 if True, 0 if False <ea> B-- - - - - - STOP Enable & wait for interrupts #<data> I I I I I SUB SUBtract binary Dn,<ea> BWL * * * * * <ea>,Dn SUBA SUBtract binary from An <ea>,An -WL - - - - - SUBI SUBtract Immediate #x,<ea> BWL * * * * * SUBQ SUBtract 3-bit immediate #<data>,<ea> BWL * * * * * SUBX SUBtract eXtended Dy,Dx BWL * * * * * -(Ay),-(Ax) SWAP SWAP words of Dn Dn -W- - * * 0 0 TAS Test & Set MSB & Set N/Z-bits <ea> B-- - * * 0 0 TRAP Execute TRAP Exception #<vector> - - - - - TRAPV TRAPV Exception if V-bit Set TRAPV - - - - - TST TeST for negative or zero <ea> BWL - * * 0 0 UNLK Deallocate Stack Frame An - - - - - -------------------------- Symbol Meaning ------ ------- * Set according to result of operation - Not affected 0 Cleared 1 Set U Outcome (state after operation) undefined I Set by immediate data <ea> Effective Address Operand <data> Immediate data <label> Assembler label <vector> TRAP instruction Exception vector (0-15) <rg.lst> MOVEM instruction register specification list <displ.> LINK instruction negative displacement ... Same as previous instruction -------------------------- Addressing Modes Syntax ---------------- ------ Data Register Direct Dn Address Register Direct An Address Register Indirect (An) Address Register Indirect with Post-Increment (An)+ Address Register Indirect with Pre-Decrement -(An) Address Register Indirect with Displacement w(An) Address Register Indirect with Index b(An,Rx) Absolute Short w Absolute Long l Program Counter with Displacement w(PC) Program Counter with Index b(PC,Rx) Immediate #x Status Register SR Condition Code Register CCR Legend ------ Dn Data Register (n is 0-7) An Address Register (n is 0-7) b 08-bit constant w 16-bit constant l 32-bit constant x 8-, 16-, 32-bit constant Rx Index Register Specification, one of: Dn.W Low 16 bits of Data Register Dn.L All 32 bits of Data Register An.W Low 16 bits of Address Register An.L All 32 bits of Address Register -------------------------- Condition Codes for Bcc, DBcc and Scc Instructions. --------------------------------------------------- Condition Codes set after CMP D0,D1 Instruction. Relationship Unsigned Signed ------------ -------- ------ D1 < D0 CS - Carry Bit Set LT - Less Than D1 <= D0 LS - Lower or Same LE - Less than or Equal D1 = D0 EQ - Equal (Z-bit Set) EQ - Equal (Z-bit Set) D1 != D0 NE - Not Equal (Z-bit Clear) NE - Not Equal (Z-bit Clear) D1 > D0 HI - HIgher than GT - Greater Than D1 >= D0 CC - Carry Bit Clear GE - Greater than or Equal PL - PLus (N-bit Clear) MI - Minus (N-bit Set) VC - V-bit Clear (No Overflow) VS - V-bit Set (Overflow) RA - BRanch Always DBcc Only - F - Never Terminate (DBRA is an alternate to DBF) T - Always Terminate Scc Only - SF - Never Set ST - Always Set -------------------------- Parts from "Programming the 68000" by Steve Williams. (c) 1985 Sybex Inc. Parts from BYTE Magazine article. Compiled by Diego Barros. e-mail : alien@zikzak.apana.org.au Revision 2.1 22 May, 1994