Unterprogrammaufrufe in Maschinensprache werden durch die Art der Parameterübergabe und die Art des Rücksprunges charakterisiert. Der PALM-Prozessor besitzt keine speziellen Opcodes für UP-Aufrufe, so daß bei einem Programmierer die Kreativität gefordert ist. Die Realisierung eines Unterprogramms und die Parameterübergabe sind voneinander unabhängig, daher werden die zwei Punkte separat beschrieben.
Der Aufruf eines Unterprogramms besteht darin, den aktuellen Befehlszähler zu merken und
per Sprung an eine andere Stelle der Programms zu verzweigen. Am Ende des UP erfolgt ein
Sprung zurück, wofür der alte Befehlszählerstand benutzt wird.
Als Sprungbefehle können alle Opcodes dienen, die das Register R0 modifizieren. In der Regel
wird jedoch ADD/SUB R0,#xx für relative, LWI R0,#xxxx für absolute und
MOVE R0,xx bzw. MOVE R0,(Rx) für indirekte Sprünge benutzt.
Die Rückkehradresse wird dabei immer in einem Register übergeben, oftmals in R2. Man kann diese
Adresse natürlich errechnen oder auf einen anderen Punkt innerhalb des Programms zeigen lassen,
wenn woandershin zurückgesprungen werden soll. Meistens ist aber ein Rücksprung zum Befehl
hinter dem Sprungbefehl beabsichtigt, wofür der INC2-Befehl benutzt wird.
Das ganze sieht dann z.B. folgendermaßen aus:
Adresse Opcode Mnemonic ----------------------------------------------------------- 2000 0203 INC2 R2, R0 ; R2 <- $2004 2002 A00B ADD R0, #12 ; R0 <- $2010 2004 0000 HALT ... 2010 A500 ADD R5, #1 2012 0024 MOVE R0, R2 ; R0 <- $2004
Der Nachteil der Übergabe der Rückkehradresse in einem Register besteht darin, daß die
Verschachtelungstiefe der UP-Aufrufe begrenzt ist; wenn alle anderen Register belegt sind
sogar auf 1. Zum anderen sind rekursive Aufrufe nicht möglich. Es empfiehlt sich deshalb,
einen eigenen Stack z.B. über Register R15 anzulegen, in dem die Rückkehradressen (und
wahlweise anderes) gespeichert werden.
Beispiel:
Adresse Opcode Mnemonic ----------------------------------------------------------- 2000 D401 ABCD LWI R4, #$ABCD 2004 0203 D021 7654 CALL $7654, R2 (bzw. INC2 R2, R0; LWI R0, #$7654) 200A 0000 HALT ... 7654 52F1 MOVE (R15)+, R2 ; R2 auf Stack "pushen" 7656 D301 0014 LWI R3, #20 7658 0203 0044 CALL (R4), R2 ; Sprung nach $ABCD 765C FF01 SUB R15, #2 ; SP erniedrigen 765E D0F8 MOVE R0, (R15) ; Rücksprung
Die am häufigsten anzutreffende Form der Parameterübergabe erfolgt über freie Register, einem gemeinsamen Speicherbereich oder einem Stack (z.B. über R15, siehe oben). Die Implementierung ist dementsprechend einfach. Oftmals findet man aber auch eine Parameterliste direkt hinter dem UP-Aufruf. Auf dem PALM-Prozessor wird dies wie folgt realisiert:
Adresse Opcode Mnemonic ----------------------------------------------------------- 2000 0203 D021 3000 CALL $3000, R2 2006 0200 0400 0040 dw $0200, $0400, ' ' 200C 0000 HALT ... 3000 D321 MOVE R3, (R2)+ ; R3 <- $0200 3002 D421 MOVE R4, (R2)+ ; R4 <- $0400 3004 D521 MOVE R5, (R2)+ ; R5 <- ' ' 3006 014C MHL R1, R4 3008 0146 OR R1, R4 300A C10B SNZ R1 ; Teste R4 auf $0000 300C 0024 RET R2 ; MOVE R0, R2 300E F400 SUB R4, #1 3010 7530 MOVB (R3)+, R5 3012 F00D BRA $3006
Das UP beschreibt einen Speicherbereich mit einem bestimmten Wert. In diesem Beispiel wird der Bereich ab $0200 der Länge $0400 mit Leerzeichen gefüllt, also der Schirm gelöscht. Zu bemerken ist, daß es sich hierbei eigentlich um einen "Mini-Stack" handelt, der direkt hinter dem UP-Aufruf liegt. Die Rückkehradresse ist der "Stackpointer", nachdem alle Parameter gelesen wurden.