A p2223 CPU-hoz kifejlesztett p2as assembler program alkalmas a processzoron futtatható assembly nyelvű programok lefordítására és a futtatható gépi kódú program létrehozására. Az assembler két menetben fordít és közvetlenül a futtatható kódot készíti el. Mivel nem generál átmeneti áthelyezhető (object) kódot, így nincs szükség szerkesztő (linker) programra.
Az assembler egyaránt képes a CPU 1-es verziójára (p1516), vagy a 2-es verziójára (p2223) készült programot lefordítani, a forrásban használható feltételek, utasítások a választott processzortól (assembly nyelv) függenek. A processzor kiválasztására szolgáló direktívát a forrás fájl elején kell elhelyezni. Ha nem alkalmazzuk, akkor a fordító alapértelmezés szerint a p1516 nyelvet használja.
A program parancssorban futtatható, a következő módon:
php p2as.php [-o kimenet] [-l] [-c] [-k] forrás_file...
A generált kimeneti fájl neve alapértelmezés szerint az elsőként megadott assembly forrás fájl nevével egyezik (a kiterjesztés .p2h-ra cserélésével), vagy megadható a -o kapcsoló paramétereként.
A -l kapcsolóval (list file creation) kérhetjük, hogy a program készítsen lista fájlt, amely a lefordított kódról tartalmaz részletes információkat. A fájl neve az első assembly forrás fájl nevével egyező lesz, .lst kiterjesztéssel.
A -c kapcsoló (compile only) használata esetén a fordító nem ad hibajelzést ha olyan szimbólumot használunk, amely nincs definiálva. Az ilyen módon lefordított kimeneti fájl nem alkalmas a program futtatására, mert az még félkész. Ez megfelel az egyéb fejlesztő rendszerekben használatos un. object fájl típusnak. Ezek a fájlok további fordításokban forrás fájlként adhatók meg, a tartalmuk bekerül a lefordított programba. A kimeneti fájlt ebben az esetben ajánlott .p2o kiterjesztéssel ellátni. Több forrás, vagy object fájl -c kapcsolóval való lefordításával könyvtár fájlt készíthetünk, ezeket a fájlokat javasolt .p2l kiterjesztéssel elnevezni.
A -k kapcsoló (keep segments) használata esetén a fordító nem távolítja el azoknak a szegmenseknek a tartalmát, amelyekre nincsenek hivatkozások, így minden szegmens tartalma bekerül a kimeneti fájlba. Ennek a kapcsolónak csak akkor van hatása, ha a -c kapcsolót nem használtuk.
A program további paraméterei az assembly forrás fájlok, illetve object, vagy könyvtár fájlok nevei lehetnek, ezekből legalább egyet kötelező megadni. A megadott fájlok tartalmát a program összefűzi, és egy programként fordítja le. Ezért, ha a forrás több fájlban szétbontva található, azonos globális címkék nem fordulhatnak elő többször a fájlokban.
A forrás fájlok más assembler-eknél megszokott szintaxisúak lehetnek. Az utasításokat egy sorba írva kell a fájban elhelyezni, a sorok a következő mezőket tartalmazhatják:
[címke:[:]] [feltétel] utasítás paraméterek [;megjegyzés]
A címke: (a szó végén lévő kettőspont jelöli), egy névvel (label) látja el azt a memória helyet, amelyre az utasítás kódszava kerül. Ugrásoknál és szubrutin hívásoknál használható a cím megadására. A címke a sorban egyedül is állhat, ekkor a forrásban ezután következő első utasítás helyét fogja jelölni.
Ha a címke neve után egynél több kettőspontot teszünk, akkor a címke globális lesz, akkor is, ha egy szegmensen belül hoztuk létre. Az így létrehozott szimbólumokat nem kell a .global direktívával exportálni.
Az utasítások feltétellel is elláthatók, ha valódi, CPU utasításokról van szó. Ha a feltételt nem adjuk meg, akkor AL (always) feltételt használja a program, amely a feltétel nélküli végrehajtást jelenti. Ugyanazt a feltételt több névvel is használhatjuk, amivel a program olvashatósága növelhető. A használható elnevezések a fordításhoz választott processzor típustól függnek, részletes felsorolásukat a melléklet tartalmazza.
Az utasítás lehet konkrét CPU utasítás (a választott processzor típustól függően), illetve a fordítónak szóló ún. pszeudó utasítás, direktíva.
A paraméterek az utasítástól függenek, ha több paramétert adunk meg, akkor azokat vesszővel kell elválasztani egymástól. Regiszterek megadásánál az R betűt és a regiszter sorszámát használjuk, pl. R10. Adatok esetében használhatunk címkeként létrehozott szimbólumokat, vagy konstansokat. A konstansoknak számjeggyel kell kezdődniük. A 0-val kezdődő konstansokat a fordító 8-as számrendszerűnek tekinti, a 0b-vel kezdődőeket kettes számrendszerűnek (bináris), míg a 0x-el kezdődőeket 16-osnak (hexadecimális). ASCII kódok megadására használhatjuk a ’b’ formát (az ASCII kód betűje egyszeres idézőjelek között), ún. escape szekvenciát, illetve szóközt azonban ilyen esetben nem használhatunk. A szimbólumok nevében a kis- és nagybetűk különbözőnek számítanak.
Bizonyos utasítások nem a processzor utasításainak a leírására szolgálnak, nem a fordító működését szabályozzák, vagy egyéb eredményük van. A direktívák nevében a kis- és nagybetűk azonosnak számítanak. Azok a direktívák amelyeknek a neve nem ponttal kezdődik, ponttal kezdődően is megadhatók, tehát pl a CPU direktíva .CPU formában is használható.
A használt processzor, és ezáltal az assembly nyelv kiválasztására szolgáló direktíva. P1 paraméter esetén a fordító a forrás fájlt p1516 processzor assembly nyelveként értelmezi, P2 esetén pedig a p2223 nyelvet használja. Ez a beállítás csak a CPU utasításokra vonatkozik, a fordító által felismert direktívák azonosak. A direktíva paramétere kis- és nagybetűvel is írható.
Az ORG utasítás paramétere egy számérték, ez lesz a memória cím számláló értéke. Arra használható, hogy valamilyen tartalmat egy adott memória területen helyezzünk el.
org 0 ; 0-s címen elhelyezve call rutin vege: jmp vege org 50 ; a rutint az 50-es címre tesszük rutin: ldl0 r1,0 ; ....Ezzel az utasítással (amelyet EQU, vagy =, illetve == formában is írhatunk) egy szimbólumnak értéket adhatunk.
porta = 0xff00 ; a kimeneti port címe ldl r0,porta ; a cím betöltése ldh r0,porta ; az R0 regiszterbeHa a == szimbólumot használjuk, akkor a szimbólum globálisként jön létre, vagyis egyúttal exportálódik a szegmensen kívülre, így a .global direktívát már nem kell használni.
Ez a direktíva hely lefoglalására használható, a tartalom megadása nélkül. Paraméterként a hely méretét kell megadni. Ha a memóriában le akarunk foglalni valahány rekeszt adat tárolására, ezzel a direktívával megadhatjuk, hány szó helyre van szükségünk. A direktíva paraméterének 0-nál nagyobb pozitív számnak kell lennie.
org 20 ; ettől a címtő kezdve adatok: ds 5 ; 5 szó helyet foglalunk leEzekkel a direktívákkal a paraméterként megadott értékeket tudjuk elhelyezni a memóriában. A DB az érték alsó 8 bitjét használja fel, a DW 16 bitet, míg a DD 32 bites adatokat használ. Egy direktívánál több paraméter is megadható vesszővel elválasztva, ezek a felsorolás sorrendjében kerülnek a memóriába. A paramétereknek konstansnak, vagy szimbólumnak kell lenniük. A szimbólumok az EQU, = direktívákkal, vagy címkeként hozhatók létre.
Ezeknél a direktíváknál használhatunk sztring konstanst is, amely ”kettős idézőjelek” között megadott szöveg. A szövegen belül használhatók a C nyelvben megszokott escape szekvenciák is. A fordító a sztring konstansokat mindig kiegészíti egy 0 értékű szóval. Ebben az esetben a direktívának nem lehet más paramétere.
start: ldl0 r1,0 ... org 10 adat1: db 123 ; 8 bites adat db 65,’z’,13 ; ASCII konstans dw 0x213 ; 16 bites adat dd -4321 ; negatív számok is megadhatók dd start ; vagy címkék is db ”Hello World!\n” ; sztring konstansSztring elhelyezése a memóriában, “pakolt” formátumban. Négy karakter kódja kerül egy memóriahelyre, little-endian sorrendben, tehát az első karakter az alsó helyen lévő 8 bites helyre kerül. Az utolsó szó fel nem használt bájtjai 0 értékűek lesznek, majd egy 0 értékű szó zárja le a sztringet.
s3: .dp "Hello World!\n" ... 6c6c6548 //C 00087 dd 0x6c6c6548 ; "lleH" 6f57206f //C 00088 dd 0x6f57206f ; "oW o" 21646c72 //C 00089 dd 0x21646c72 ; "!dlr" 0000000a //C 0008a dd 0x0000000a ; "\012" 00000000 //C 0008b dd 0Szegmens kezdetét definiáló direktíva. A szegmensek a szimbólumok láthatóságát a szegmensen belülre korlátozzák, így az egyes szegmensek ugyanazt a szimbólum nevet saját célra használhatják.
Az első paraméter a szegmens neve, ami után opcionális paraméterek következhetnek. A szegmensen belül létrehozott szimbólumok és címkék csak a szegmensen belül láthatóak. Ha a szegmensen kívül is használni szeretnénk egy szimbólumot, akkor azt a GLOBAL direktívával exportálni kell.
A szegmensben újra definiálhatunk globális szimbólumokat. Ezekből egy új példány jön létre, így az értékük a szegmensen belül más lesz, mint a globális területen.
A szegmens végét jelző direktíva. Ez után a program globális területe folytatódik, így a globális szimbólumok válnak láthatóvá.
A szegmensen belül definiált szimbólum globális szimbólummá való konvertálását végző direktíva. Paramétere a szimbólum neve. Csak egy paraméter adható meg. Ha a szimbólum a globális területen már létezik, akkor hibaüzenetet kapunk.
A paraméterként megadott fájl betöltése és fordítása. A fájl nevét nem kell idézőjelbe tenni. A betöltött fájl után az aktuális fájl fordítása folytatódik. A fájlt a program először abban a könyvtárban keresi, ahol az eredeti forrásfájl található. Ha ott nem található, akkor a rendszer fájljai között fogja keresni, ez lehet a felhasználó saját könyvtárának p12tool/include alkönyvtára, vagy a fejlesztőrendszer lib alkönyvtára.
Regiszter alternatív elnevezésének létrehozása. Az alternatív név a fordítás hátralévő részében használható.
A CPU utasításokban használható feltételek a kiválasztott processzor típusától függnek (lásd CPU direktíva). Egyes feltételek több különféle névvel is használhatók.
Feltétel | Használható nevek |
S==0 | S0 |
S==1 | S1 |
C==0 | C0 |
C==1 | C1 |
Z==0 | Z0, NZ |
Z==1 | Z1, Z |
O==0 | O0 |
O==1 | O1 |
Feltétel | Használható nevek |
Z==0 | NE, ZC, Z0, NZ, T |
Z==1 | EQ, ZS, Z1, Z, F |
C==0 (u1<u2) | CC, LO, C0, NC, ULT |
C==1 (u1>=u2) | CS, HS, C1, C, UGE |
S==0 | PL, SC, S0, NS |
S==1 | MI, SS, S1, S |
O==0 | VC, OC, V0, O0, NV, NO |
O==1 | VS, OS, V1, O1, V, O |
C==1 && Z==0 (u1>u2) | HI, UGT |
C==0 || Z==1 (u1<=u2) | LS, ULE |
S==O (s1>=s2) | GE, SGE |
S!=O (s1<s2) | LT, SLT |
Z==0 && S==O (s1>s2) | GT, SGT |
Z==1 || S!=O (s1<=s2) | LE, SLE |
Az utasításokat ismertető táblázatban a következő rövidítéseket használjuk:
A konstansokban a # jelet nem kell használni, elég a számértéket, vagy a szimbólum nevét megadni. A regiszterek közül az R13 helyett használhatjuk az SP, az R14 helyett az LR, míg az R15 helyett a PC elnevezéseket is.
Mnemonic | Paraméterezési módok | Utasítás |
NOP |
Rd,Ra,Rb Rda,Rb Rd - |
No operation |
LD | Rd,Ra | Load from memory |
ST | Rd,Ra | Store to memory |
MOV | Rd,Ra | Move register to register |
LDL0 | Rd,#16 | Load zex(immediate) to low |
LDL | Rd,#16 | Load low of immediate to low |
LDH | Rd,#H16 | Load high of immediate to high |
CALL | #27 | Call subroutine |
ADD |
Rd,Ra,Rb Rda,Rb |
Add without carry |
ADC |
Rd,Ra,Rb Rda,Rb |
Add with carry |
SUB |
Rd,Ra,Rb Rda,Rb |
Subtract without borrow |
SBB |
Rd,Ra,Rb Rda,Rb |
Subtract with borrow |
INC |
Rd,Ra Rda |
Increment |
DEC |
Rd,Ra Rda |
Decrement |
AND |
Rd,Ra,Rb Rda,Rb |
Bitwise AND |
OR |
Rd,Ra,Rb Rda,Rb |
Bitwise OR |
XOR |
Ra,Ra,Rb Rda,Rb |
Bitwise XOR |
SHL |
Rd,Ra Rda |
Shift left |
SHR |
Rd,Ra Rda |
Shift right |
ROL |
Rd,Ra Rda |
Rotate left |
ROR |
Rd,Ra Rda |
Rotate right |
MUL |
Rd,Ra,Rb Rda,Rb |
Multiply |
CMP |
Rd,Ra,Rb Rda,Rb |
Compare |
SHA |
Rd,Ra Rda |
Shift arithmetic right |
SETC | - | Set carry |
CLRC | - | Clear carry |
A következő makrók egyes utasítások alternatív elnevezéseiként használhatók.
Makró név | Paraméterezési módok | Jelentése |
JMP | #16 | LDL0 R15,#16 |
JZ | #16 | Z LDL0 R15,#16 |
JNZ | #16 | NZ LDL0 R15,#16 |
RET | - | MOV R15,R14 |
PUSH | Rd | ST Rd,R13 |
POP | Rd | LD Rd,R13 |
Az utasításokat ismertető táblázatban a következő rövidítéseket használjuk:
A konstansokban a # jelet nem kell használni, elég a számértéket, vagy a szimbólum nevét megadni. A regiszterek közül az R13 helyett használhatjuk az SP, az R14 helyett az LR, míg az R15 helyett a PC elnevezéseket is. A speciális regiszterek azonosítására a következő elnevezések használhatók:
Mnemonic | Paraméterezési módok | Utasítás |
MOV | Rd,Rb | Move register to register |
SED | Rd,Rb | Sex to double |
MVL | Rd,#16 | Load low of immediate to low |
MVH | Rd,#H16 | Load high of immediate to high |
MVZL | Rd,#16 | Load zex(immediate) |
MVS | Rd,#16 | Load sex(immediate) |
GETB |
Rd,Rb,#2 Rd,Rb,Ri |
Get byte |
GETBS |
Rd,Rb,#2 Rd,Rb,Ri |
Get sign extended byte |
GETBZ |
Rd,Rb,#2 Rd,Rb,Ri |
Get zero extended byte |
PUTB |
Rd,Rb,#2 Rd,Rb,Ri |
Put byte |
RDS | Rd,Rs | Read special register |
WRS | Rd,Rs | Write special register |
ADD |
Rd,Rn,Rb Rd,Rb Rd,#16 |
Add without carry |
ADC |
Rd,Rn,Rb Rd,Rb Rd,#16 |
Add with carry |
SUB |
Rd,Rn,Rb Rd,Rb Rd,#16 |
Subtract without borrow |
SBB |
Rd,Rn,Rb Rd,Rb Rd,#16 |
Subtract with borrow |
CMP |
Rd,Rn,Rb Rd,Rb Rd,#16 |
Compare |
MUL |
Rd,Rn,Rb Rd,Rb Rd,#16 |
Multiply |
PLUS |
Rd,Rb Rd,#16 |
Add without carry (do not alter flags) |
BTST |
Rd,Rb Rd,#16 |
Bit test (AND) with write-back |
TEST |
Rd,Rb Rd,#16 |
Bit test (AND) without write-back |
OR |
Rd,Rn,Rb Rd,Rb Rd,#16 |
Bitwise OR |
XOR |
Rd,Rn,Rb Rd,Rb Rd,#16 |
Bitwise XOR |
AND |
Rd,Rn,Rb Rd,Rb Rd,#16 |
Bitwise AND |
ZEB | Rd | Zero extend byte |
ZEW | Rd | Zero extend word |
SEB | Rd | Sign extend byte |
SEW | Rd | Sign extend word |
NOT | Rd | Bitwise NOT |
NEG | Rd | Sign change |
ROR |
Rd,Rn Rd |
Rotate right |
ROL |
Rd,Rn Rd |
Rotate left |
SHL |
Rd,Rn Rd |
Shift left |
SHR |
Rd,Rn Rd |
Shift right |
SHA |
Rd,Rn Rd |
Shift arithmetic right |
SZ | Rd | Sign, zero check |
SEC | - | Set carry |
CLC | - | Clear carry |
GETF | Rd | Get flags |
SETF | Rd | Set flags |
CALL |
Rd,#20 #24 |
Call subroutine |
CES |
Rd,#20 #24 |
Call subroutine with embedded string |
ST |
Rd,Ra,Ri Rd,Ra+,Ri Rd,Ra-,Ri Rd,+Ra,Ri Rd,-Ra,Ri Rd,Ra,#16 Rd,*Ra,#16 Rd,Ra Rd,#16 #16,Rd |
Store to memory |
LD |
Rd,Ra,Ri Rd,Ra+,Ri Rd,Ra-,Ri Rd,+Ra,Ri Rd,-Ra,Ri Rd,Ra,#16 Rd,*Ra,#16 Rd,Ra Rd,#16 #16,Rd |
Load from memory |
A következő makrók egyes utasítások alternatív elnevezéseiként használhatók.
Makró név | Paraméterezési módok | Jelentése |
NOP | - | MOV R0,R0 |
JMP | #16 | MVZL R15,#16 |
JZ | #16 | Z MVZL R15,#16 |
FALSE | #16 | Z MVZL R15,#16 |
JNZ | #16 | NZ MVZL R15,#16 |
TRUE | #16 | NZ MVZL R15,#16 |
JC | #16 | C MVZL R15,#16 |
JNC | #16 | NC MVZL R15,#16 |
JP | Rb | MOV R15,Rb |
RET | - | MOV R15,R14 |
PUSH | Rd | ST Rd,*R13,0 |
POP | Rd | LD Rd,*R13,0 |
INC | Rd | ADD Rd,1 |
DEC | Rd | ADD Rd,-1 |
LDL0 | Rd,#16 | MVZL Rd,#16 |
LDL | Rd,#16 | MVL Rd,#16 |
LDH | Rd,#16 | MVH Rd,#16 |