Writing Assembly for your Newton

DISCLAMER

I have figured this stuff out by hacking around in the newton. I'm not saying any of it is necessarily correct or will not do damage to your newton. Use this information at your own risk!!! ALWAYS backup your newton before experimenting with anything like this! (I remove the cards while working, too). Playing with assembly is a great way to loose your valuable data, and crash your newton! I will not be responsible for anything which happens (good or bad) as a result of using or misusing this information.

I have only tried this stuff on an upgraded MP2K, but the Modplayer has shown that it works on Emates, and all versions of MP2K/MP2100's. I have NO IDEA if it'll work on other models!

What you'll need

First, I should outline what is needed to write assembly for your newton:
- A StrongArm-110 or compatible assembler (460K) -- added the cygwin1.dll (needed, but previously missing)
- A Linker (400K) -- added the cygwin1.dll (needed, but previously missing)
- A Package stuffing program. This is a program that can take data and make a pkg out of it. I'm working on one which will eventually pack frames, arrays, binary data, anything, but it isn't done yet. For now, it will only put asm-code in a package of type AUTO for you. I'll post updates when they are ready.

And some things that can make life easier but are not necessary are:
- A C preprocessor (handles stuff like #include, #define, etc.) These things are great! You can use a C Preprocessor on any text file to make it more readable, and easier to work with, but you don't have to.
- A package dumping tool. Something that can show you exactly what you have put in your package.
- some .PDF's from somewhere I can't remember - these are very useful! Either the INTEL site, or an ARM site.
-- Arm75001.pdf: ARM Processor Instruction Set
-- ArmQuick.pdf: 3-pages of quick-reference info
-- TechRefm.pdf: Technical Reference Manual #278058-001
What the heck, here they are (840K)...
-- Another pdf which you'll find useful: Apple's Newton Formats book describes a lot of internal stuff, like .pkg formats, what a REF is, bytecode, and lots of useful info! nwtfmt11.zip (390K) *** I Know of one typo in this manual: Page 1-11, the table sais a char ends with '1010', this is not true, a char ends with '0110'.

About the Assembler and Linker

I have (with much pain) finally got the GNU assembler (CYGNUS version, found at http://sourceware.cygnus.com/cygwin/) to compile for the PC as a cross-assembler to the ARM chipset (which includes StrongArm-110). I'm supposed to provide the source with the executable, but since I made no changes to the source whatsoever, and considering a free web-page has little room, I'll just include a link to where the source can be found, rather than including it in the package.

Using the Assembler and Linker

To generate code for the newton, you must use a specific set of options for both the assembler and linker.
To assemble...
AS -EB sourcefile.s -o objectfile.o -a=listingfile.lst
...and to link...
LD -oformat binary objectfile.o -o binaryfile.bin -Map mapfile.map -Ttext 0
Both these programs will return errorlevels, so a batch file can detect errors (eg. on errorlevel 1 goto BadAssembly)
Once you have assembled your source to a .bin file, you need to package it up and send it to the newt.

Making the Assembly code into a .PKG

I use a custom-built called MakePKG which converts the assembly into a .PKG of type AUTO. I don't think you can do this with the NTK. To use this tool, you need to create a script which the tool will process. make a script such as MyAsmPackage.script and put this in it:
# script for making newton packages...
makeSlot [nameOfSlot] asmCode [nParamters] [filename.bin]


Now, run the MakePKG tool and give it the script you just made:
MakePKG filename.pkg PackageSymbol:SIG MyAsmPackage.script

Writing assembly for the Newton

You will need a copy of a few documents regarding SA-110 assembly which can be found on the ARM but I can't remember where I found them!

Some stuff you'll need to know before starting:
Parameters are passed into your function in reverse order, beginning with R1 and going up. Eg. 3 parameters would appear like this: R1 = parm3, R2 = parm2, R3 = parm1. I use only one parameter to keep it simple, and index off of it (it's an array of information, so it's easy to get to your info)
Registers: R0..R12 are free for you to use. R13=SP, R14=return address from subroutines, R15=PC. I reserve R1 for my GlobalData array and never modify its value anywhere in my code.
Make sure you .org 0 at the start of your code!
You have no relocation info (My tool doesn't support it).
You can't WRITE to anywhere except to variables passed in by newtonscript. Don't write to variables stored in the code-space.

Communication between newtonscript and Assembly

Use a single parameter, an array.
Make a constants.txt file for the newtonscript code to use, and make a constant name for each element of the array, such as:
defConst('kGD_HitPoints, 0);
defConst('kGD_MagicPoints, 1);
defConst('kGD_Coins, 2);
defConst('kGD_nSlots, 3);

then create the array: MakeArray(kGD_nSlots,nil);
Now, create a matching set of equates in your assembly code.
.equ kGlobalData, 11
@ an array has a 12 byte header, the pointer to the array is offset by one byte already, that leaves 11 to go.
.equ kGD_HitPoints, (kGlobalData+4*0)
@ write it in a readable way
.equ kGD_MagicPoints, (kGlobalData+4*1)
.equ kGD_Coins, (kGlobalData+4*2)

Now, to look up the second item in your array, go like this:

mov R0,[r1,#kGD_MagicPoints]

Now, you have the 'magicPoints' REF in your register. EVERYTHING is a REF. A REF is a number with the bottom two bits messed with.
xxxxxx00 = INTEGER (30 bits plus two for the REF type -- this is why integers are max 30 bits in newtonscript!)
xxxxxx01 = POINTER (array, frame, binary object pointer)
xxxxxx10 = SPECIAL (nil, true, and others)
xxxxxx11 = Magic pointer (pointer into ROM)
So, to convert your number you got from the kGD_MagicPoints array index, do this:
MOV R0,R0,ASR#2
@ get rid of those two REF type bits!

Now, R0 is the number newtonscript put in the slot.
If it's a pointer you're looking up (to a binary object), add 11 and you're at the first byte of the binary data itself. If it's a pointer to an array, add 11 and you're at the first REF in that array (remember, EVERYTHING's a REF!!) Fortunately, converting things to REF's and back is easy.
A float is actually a binary object containing a standard IEEE format number.
The REF for NIL is 0x00000002 (I .equ it to kNIL)
The REF for TRUE is 0x0000001A (I .equ it to kTRUE)

A Mimimal Function

.org 0
MAIN:
If you're still awake through all that, you must be hard-core. Here's the asm source for my ModPlayer! (13K) This is old code, it won't work with the current release of the ModPlayer Newtonscript package, but it demonstrates the principal.Break it, play with it, learn from it, just please don't re-release it.

Write to me if you're experimenting with this stuff, I want to know! rogermilne@shaw.ca

Back to the Site Contents