Pila User's Manual (ver 1.0 Beta 2)

Darrin Massena (darrin@massena.com)
5 Oct 96

Enhancements by Wes Cherry (wesc@ricochet.net)

Table Of Contents

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

AThe Making Of Pila
BPilot.inc And Naming Conventions
CPalmOS API Calling Conventions
D68000 Instruction Set Quick Reference

Chapter 1: Pila

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.

Pila.exePila proper. Pila.exe acts as assembler, resource integrator, and linker
Pilot.incConstants and data structures used by the PalmOS APIs
PilRC.zipA ZIP file containing Wes Cherry's Pilot Resource Compiler
PilDis.zipA ZIP file containing Bill Hunt's Pilot Disassembler
Startup.incStandard startup code that every application should include
Sample.asmA sample application
Sample.rcpSample resources, processed by PilRC to produce Pilot resource binaries
Sample.bmpThe sample application's icon. Pila converts this to a 'tAIB' resource
PilaUM.htmThis documentation
readme.txtLast 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.


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.


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.


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.

Chapter 2: Pila Syntax

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.

lGenerate a listing file. The listing file has same name as the source file suffixed with '.lis'.
cShow full constant expansions for DC directives.
dGenerate a bunch of debug output. This option is of little use to most people.
sGenerate Copilot-compatible symbols.
rDo 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.


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:

.structure.memberStructure member
-- expressionUnary minus
~~ expressionOne's complement
(, )( expression )Parenthesized expression
<<expression << countShift left
>>expression >> countShift right
|expression | expressionLogical OR
&expression & expressionLogical AND
*expression * expressionMultiply
/expression / expressionDivide
\expression \ expressionModulo
+expression + expressionAdd
-expression - expressionSubtract

Chapter 3: Directives

3.1 align


align size


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


appl "applicationname", 'apid'


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



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


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



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



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


[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


[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


[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



The end directive forces Pila to stop assembly immediately. The end directive is optional.

3.11 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


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


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


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


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


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


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


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


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


struct structname

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


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


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

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 *
ADD      ADD binary                        Dn,<ea>     BWL        * * * * *
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        * * * * *
AND      Bit-wise AND                      <ea>,Dn     BWL        - * * 0 0
ANDI     Bit-wise AND with Immediate    #<data>,<ea>   BWL        - * * 0 0
ASL      Arithmetic Shift Left            #<1-8>,Dy    BWL        * * * * *
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        - - * - -
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>
  Bit TeST                          Dn,<ea>     B-L        - - * - -
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 *
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-        - - - - -
OVE     USP to/from Address Register      USP,An      --L        - - - - -
MOVEA    MOVE Address                      <ea>,An     -WL        - - - - -
MOVEM    MOVE Multiple            <register list>,<ea> -WL        - - - - -
                                  <ea>,<register list>
MOVEP    MOVE Peripheral                  Dn,x(An)     -WL        - - - - -
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
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 *
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 *
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        * * * * *
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        * * * * *
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   
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

   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

Back to Pilot Software Development