A A lebegőpontos regiszterkészlet és az IEEE 754
ábrázolás alfejezetben egy konkrét szám bitmezőin keresztül láttuk,
hogy a float és a double nem kettes komplemens
egész, és nem az Xn regisztereken utazik. Az ott felépített
reprezentáció azonban önmagában passzív: ahhoz, hogy egy mérnöki
feladatot megoldjunk, utasítások kellenek, amelyek
ezeken a bitmintákon aritmetikát végeznek.
Vegyük a tipikus kalibrációs láncot: az ADC egy nyers egész értéket
ad, abból (x - offset) * scale alakú lineáris
transzformációval lesz fizikai mennyiség, majd statisztikához (átlag,
szórás) lebegőpontoson számolunk, végül a megjelenítéshez vagy egy
protokoll-mezőhöz egészre kell visszakonvertálni. Ez a lánc két
határátlépést tartalmaz az egész és a lebegőpontos világ
között, és ezek a határátlépések az assembly szintjén nem automatikusak:
külön utasítás kell rájuk. Ez az alfejezet pontosan ezt a réteget
tanítja: a skaláris lebegőpontos aritmetikát, a bit szintű mozgatást és
a konverziókat.
A hatókör szűk: FADD, FSUB,
FMUL, FDIV, FMOV,
SCVTF/UCVTF,
FCVTZS/FCVTZU, valamint az FCMP
és az abból származó feltételkódok. A vektoros (NEON) párhuzamosítás a
A NEON regiszterkészlet és adatelrendezés és a
Vektorizált összeadás/szorzás: egy skaláris ciklus
NEON-átirata témája; a feltételkódok általános mechanikáját pedig a
Feltételes végrehajtás: CSET/CSEL és
feltételkódok alfejezetben már felépítettük — itt csak azt nézzük
meg, hogyan viselkednek lebegőpontos összehasonlítás után.
Skaláris lebegőpontos utasítás (scalar
floating-point instruction): olyan A64 ISA utasítás, amely egyetlen
lebegőpontos értéken (egy Sn vagy Dn
regiszteren) hajt végre műveletet, szemben a vektorossal, amely
egyszerre több elemet dolgoz fel egy Vn regiszterben.
Az AArch64 sajátossága, hogy a mnemonic nem tartalmaz
pontosság-suffixet. Nincs fadd.f32; a pontosságot
a regiszternév kódolja:
| Regiszternév | Nézet | Pontosság |
|---|---|---|
Sn (pl. S0) |
Vn alsó 32 bitje |
binary32 (float) |
Dn (pl. D0) |
Vn alsó 64 bitje |
binary64 (double) |
Ebből két kemény szabály következik:
FADD Sd, Sn, Sm és FADD Dd, Dn, Dm érvényes, a
FADD S0, S1, D2 viszont assemble-idejű hiba. Nincs implicit
önpontosítás (widening).FADD/FSUB/FMUL/FDIV
egyik formája sem fogad el azonnali konstanst. A konstans
háromféleképpen kerülhet be: az FMOV korlátozott
immediate-készletével, egy egész regiszterből
SCVTF/UCVTF-fal, vagy memóriából
(LDR Sn, [Xn]). Az FMOV immediate-kódolása 8
bites, ezért nem minden konstans írható le vele — ez az
MOV-variánsok és immediate-kódolás korlátjának
lebegőpontos megfelelője.Az utasításcsoportok áttekintése:
| Utasítás | Mit csinál | Regisztertípus |
|---|---|---|
FADD, FSUB, FMUL,
FDIV |
aritmetika | Sn/Dn |
FMOV |
bit szintű másolás (nem konverzió!) | FP ↔︎ egész / FP ↔︎ FP |
SCVTF, UCVTF |
egész → lebegőpontos | Wn/Xn →
Sn/Dn |
FCVTZS, FCVTZU |
lebegőpontos → egész, csonkítva | Sn/Dn →
Wn/Xn |
FCVT |
float ↔︎ double |
Sn ↔︎ Dn |
FCMP, FCMPE |
összehasonlítás, NZCV beállítás | Sn/Dn |
Az alapműveletek szemantikája az IEEE 754-2019 binary32/binary64
szabvány szerint helyesen kerekített (correctly
rounded): az eredmény a pontos matematikai eredmény kerekítése
az aktuális kerekítési mód szerint. A módot az
FPCR (Floating-point Control Register) RMode
mezője választja ki: round-to-nearest-ties-to-even (RN, ez az
alapérték), +∞ felé (RP), −∞ felé (RM) vagy nulla felé (RZ). „A
legközelebbi ábrázolható szomszéd” csak RN módban igaz; a többi módban
az eredmény a pontos érték megfelelő irányú szomszédja. Az
FPCR további bitjei (például a flush-to-zero
FZ és az alapértelmezett NaN DN) szintén
eltéríthetik az eredményt az IEEE-alapviselkedéstől; Linux alatt a
felhasználói programok alapértelmezésben IEEE-módban indulnak. A program
MRS Xt, FPCR / MSR FPCR, Xt utasításokkal
érheti el a regisztert.
Néhány, a C-fejlesztőt ténylegesen érintő tulajdonság:
FADD/FSUB/FMUL/FDIV
nem tesz különbséget előjeles és előjel nélküli között
— a lebegőpontos ábrázolás előjel-nagyság (sign-magnitude) alakú, nincs
kettes komplemens viselkedés. Ez éles ellentét a Egész aritmetika MUL/DIV
világával.x esetén x + (-x)
eredménye RN, RP és RZ módban +0.0, RM módban viszont
-0.0. Nem véges bemenetre a szabály nem érvényes:
Inf + (-Inf) NaN (és IOC-t állít), NaN bemenetre NaN az
eredmény. A nulla előjele nem csak osztásnál számít
(1.0 / -0.0 = -Inf): a C signbit és
copysign függvényei is megkülönböztetik a két nullát, és a
printf is -0-t ír ki.FPSR (Floating-point Status Register)
halmozódó bitjeibe íródnak (IOC – invalid operation,
DZC – divide by zero, OFC – overflow, UFC – underflow, IXC – inexact).
Alapértelmezésben nincs trap. Fontos: ezek a flagek nem
az NZCV-ben vannak, tehát feltételes elágazással nem
olvashatók ki; MRS Xt, FPSR kell hozzájuk.FDIV költsége lényegesen nagyobb, mint a többi
műveleté. Az alábbi nagyságrendek irodalmi/illusztratív értékek,
amelyeket nem mértünk ebben a könyvben, és
mikroarchitektúránként változnak; a pontos latenciát az adott CPU
technikai leírásából kell ellenőrizni.| Művelet | Illusztratív latencia-nagyságrend (ellenőrizendő) | Jelleg |
|---|---|---|
FADD/FSUB |
néhány ciklus | teljesen futószalagosítható |
FMUL |
néhány ciklus | teljesen futószalagosítható |
FDIV |
egy nagyságrenddel több | részben vagy nem futószalagosítható |
Ez az eltérés a Teljesítmény-tudatos
kód mérési szakaszában lesz fontos: egy FDIV csere
FMUL-ra (reciprokkal) gyakran nagyobb nyereséget ad, mint
bármilyen vektorizáció.
Az FMOV a leggyakrabban félreértett utasítás ebben a
csoportban. Az FMOV nem konvertál, hanem a
biteket másolja, és a célregiszter ezeket úgy értelmezi, ahogyan az ő
típusa előírja.
| Forma | Hatás |
|---|---|
FMOV Wd, Sn |
Sn alsó 32 bitje → Wd (a bitminta
egészként olvasva) |
FMOV Sd, Wn |
Wn → Sd alsó 32 bitje (a bitminta
lebegőpontosként értelmezve) |
FMOV Xd, Dn |
Dn → Xd |
FMOV Dd, Xn |
Xn → Dd |
FMOV Sd, Sn / FMOV Dd, Dn |
FP → FP, bitazonos |
FMOV Sd, #imm |
korlátozott, 8 bites kódolású konstanskészlet |
A gyakorlati haszna az irányított olvasás:
FMOV Wd, Sn-nel hozzáférünk az IEEE 754 bitmezőkhöz
(előjel, exponens, mantissza) egész műveletekkel — ez a Logikai alapműveletek és bitmaszkolás eszköztárával
kombinálva adja a bitmanipulációs trükköket. Fordított irányban
FMOV Sd, Wn akkor hasznos, ha egy memóriából olvasott nyers
32 bites szót akarunk float-ként értelmezni (pl.
protokoll-deszerializálás).
A tipikus hiba pontosan itt keletkezik: FMOV-ot
használni konverzióra. Ha W0 = 10, akkor az
FMOV S0, W0 nem 10.0f-et ad, hanem a
0x0000000A bitmintát, ami egy rendkívül kicsi denormális
szám (≈1.4e-44). Egész → lebegőpontos átalakításra az
SCVTF/UCVTF való.
| Utasítás | Irány | Forrás előjelkezelés |
|---|---|---|
SCVTF Sd, Wn / SCVTF Dd, Wn /
SCVTF Sd, Xn / SCVTF Dd, Xn |
egész → FP | előjeles |
UCVTF Sd, Wn / … |
egész → FP | előjel nélküli |
FCVTZS Wd, Sn / FCVTZS Xd, Dn / … |
FP → egész | előjeles, Z = toward zero |
FCVTZU Wd, Sn / … |
FP → egész | előjel nélküli, toward zero |
Az SCVTF a forrásregiszter méretéből és az
S/D célból egyértelműen azonosítja a
konverziót: SCVTF Dd, Xn egy 64 bites előjeles egészt
alakít double-ré. Az egész → FP irányban a kerekítés az
FPCR módja szerint történik, és 64 bites forrásból
Sn-be konvertálva pontosságvesztés lehetséges.
Az FP → egész irányban a Z az FCVTZS
kerekítési módját jelöli: csonkítás nullához (round
toward zero). Ez azért kritikus, mert a C (int)y kasztja is
csonkít nullához. Ha más kerekítés kell, külön utasítás létezik:
FCVTNS (nearest), FCVTPS (plus infinity),
FCVTMS (minus infinity), illetve ezek …U
előjel nélküli párjai, valamint a FRINT* család, ha nem
egészbe, hanem lebegőpontosba kerekítünk.
Két fontos részlet:
FPSR IOC bitje beáll — nem lesz belőle
„körbefordulás”, mint fixpontos környezetben. A specifikáció szerint NaN
bemenetre az eredmény 0. Ez a viselkedés eltér az x86
CVTTSS2SI „integer indefinite” (0x80000000)
mintájától, ezért portoláskor gyakori hibaforrás; a pontos ARM ARM
megfogalmazását lásd az ellenőrzési hiányoknál. Ez az ISA
viselkedése, nem a C-é: C-ben a tartományon kívüli (vagy NaN)
float → egész konverzió ettől még definiálatlan
viselkedés (C17 6.3.1.4). A fordító nem köteles
FCVTZS-t használni, és optimalizáláskor feltételezheti,
hogy ilyen eset nem fordul elő. Aki a telítésre épít, annak a tartományt
a konverzió előtt C-ben kell ellenőriznie, vagy az utasítást assemblyben
(illetve intrinsic-kel) kell kiadnia.NZCV-hatás. A konverzió nem
állítja be az NZCV flageket; aki a konverzió sikerességét
elágazással akarja ellenőrizni, annak előbb MRS-sel ki kell
olvasnia az FPSR-t.Lebegőpontos ↔︎ lebegőpontos átalakításra az FCVT Dd, Sn
és FCVT Sd, Dn szolgál — ez az egyetlen módja a
float és double közötti váltásnak, mert az
aritmetikai utasítások nem keverik a pontosságot.
Az FCMP Sn, Sm, FCMP Dn, Dm és
FCMP Sn, #0.0 formák lebegőpontos összehasonlítást
végeznek, és az eredményt az NZCV-be írják. Innen a Feltételes végrehajtás feltételkódjai használhatók
— de nem ugyanúgy, mint egész összehasonlítás után.
A NaN jelenléte miatt az összehasonlításnak négy
kimenetele van: egyenlő, nagyobb, kisebb és rendezetlen
(unordered). Az ARM az alábbi flag-kiosztást használja:
| Összehasonlítás | N | Z | C | V |
|---|---|---|---|---|
| egyenlő | 0 | 1 | 1 | 0 |
| nagyobb | 0 | 0 | 1 | 0 |
| kisebb | 1 | 0 | 0 | 0 |
| rendezetlen (NaN) | 0 | 0 | 1 | 1 |
Ebből a feltételkódok lebegőpontos jelentése:
| Feltételkód | NZCV-feltétel | Lebegőpontos jelentés | C-beli megfelelő |
|---|---|---|---|
EQ |
Z==1 |
egyenlő | a == b |
NE |
Z==0 |
nem egyenlő vagy rendezetlen | a != b |
MI |
N==1 |
kisebb (rendezett) | a < b |
CC/LO |
C==0 |
kisebb (rendezett) | a < b |
GT |
Z==0 && N==V |
nagyobb (rendezett) | a > b |
GE |
N==V |
nagyobb vagy egyenlő (rendezett) | a >= b |
LS |
C==0 \|\| Z==1 |
kisebb vagy egyenlő (rendezett) | a <= b |
LT |
N!=V |
kisebb vagy rendezetlen | — |
LE |
Z==1 \|\| N!=V |
kisebb vagy egyenlő vagy rendezetlen | — |
HI |
C==1 && Z==0 |
nagyobb vagy rendezetlen | — |
CS/HS |
C==1 |
nagyobb vagy egyenlő vagy rendezetlen | — |
VS |
V==1 |
rendezetlen (NaN) | isnan(a) \|\| isnan(b) |
VC |
V==0 |
rendezett | egyik sem NaN |
A tanulság: a C > operátora
rendezett nagyobb-than, ezért a helyes feltételkód a
GT, nem a HI — HI ugyanis
NaN esetén is igaz lenne. A != viszont
szándékosan NE, mert az IEEE 754 szerint
NaN != x igaz. A FCMPE a jelző (signaling)
változat: csendes NaN esetén is kiváltja az invalid operation kivételt,
FCMP nem.
Munkakönyvtár: ~/arm-labor/a64/a045/ —
az alfejezet minden laborfájlja ide kerül, és minden parancs innen
futtatandó (a könyvtárrendet a Labor-alapkörnyezet alfejezet írja le).
mkdir -p ~/arm-labor/a64/a045
cd ~/arm-labor/a64/a045A példa három egész átlagát számolja float-ként, majd
csonkítva visszaalakítja egésszé, és a kilépési kódban adja vissza.
// lab-a045-avg.s — skaláris lebegőpontos átlag és csonkítás
// target: qemu-aarch64 (user-mode), A64 ISA, little-endian
.text
.global _start
_start:
mov w0, #10
mov w1, #20
mov w2, #13
scvtf s0, w0 // s0 = 10.0f
scvtf s1, w1 // s1 = 20.0f
scvtf s2, w2 // s2 = 13.0f
fadd s3, s0, s1 // s3 = 30.0f
fadd s3, s3, s2 // s3 = 43.0f
mov w3, #3
scvtf s4, w3 // s4 = 3.0f (nincs FP immediate!)
fdiv s5, s3, s4 // s5 = 14.333333f
fcvtzu w0, s5 // w0 = 14 (csonkítás nullához)
mov x8, #93 // __NR_exit
svc #0
.section .note.GNU-stack,"",%progbitsAssemble, link és futtatás:
aarch64-linux-gnu-as -o lab-a045-avg.o lab-a045-avg.s
aarch64-linux-gnu-ld -o lab-a045-avg lab-a045-avg.o
# elvárt: GNU_STACK RW
readelf -lW lab-a045-avg \
| awk '$1=="GNU_STACK"{f=$7} END{print "GNU_STACK", f; exit !(f=="RW")}'
qemu-aarch64 ./lab-a045-avg ; echo $?Várt kimenet: 14. A
43/3 = 14.333… pontos értéke binary32-ban nem
ábrázolható, ezért az FDIV itt IXC-t állít az
FPSR-ben; a csonkítás után mégis 14 lesz. A
kilépési státusz a w0 alsó 8 bitje, ezért a 14
közvetlenül olvasható.
Kiegészítő részlet (nem önálló program), amely a többi műveletet és az összehasonlítást mutatja:
// feltételezés: s0 = a, s1 = b (mindkettő float)
fsub s2, s0, s1 // s2 = a - b
fmul s3, s0, s1 // s3 = a * b
fdiv s4, s0, s1 // s4 = a / b
fcmp s0, s1 // a ? b
cset w5, gt // w5 = 1, ha a > b (rendezett)
// s6 = (a > b) ? a : b; rendezetlen összehasonlításnál b, nem FMAX
fcsel s6, s0, s1, gt
fcvt d7, s0 // d7 = (double)a, pontosságnövelés1. FMOV konverzióra használata. Tünet:
az SCVTF helyett FMOV S0, W0 után az
FCVTZU eredménye 0 lesz, holott a bemenet
10 volt. Hipotézis: a bitminta denormálisként
értelmeződött, és a csonkítás nullát ad. Adatgyűjtés:
aarch64-linux-gnu-objdump -d lab-a045-avg | grep -A3 -B3 fmov
— ha fmov szerepel ott, ahol scvtf-nek
kellene, megvan a hiba. Egy változtatás: cseréld scvtf-re,
majd echo $? ellenőrzés.
2. Precízió-keverés. Az fadd s0, s0, d1
assemble-idejű hibát ad („operand 3 must be a scalar FP register of the
same size”). Ez nem hiba, hanem a szerződés működése: előbb
fcvt s1, d1, utána az összeadás.
3. HI/LS használata
>/<= helyett. Tünet:
NaN bemenetre az elágazás a „nagyobb” ágra fut. Ellenpróba:
futtasd a kódot a = NaN, b = 1.0f bemenettel,
és cseréld a feltételkódot GT-re. Ugyanez a hiba
LS használatakor <= helyett:
LS valójában az ordered <=, ami
C-ben helyes, de ha valaki LE-t használ,
NaN-ra is igazat kap.
4. Negatív érték csonkítása előjel nélküli célba.
FCVTZU -1.5f-re telít a 0-ra (és
IOC-t állít), míg FCVTZS -1-et ad. Tünet: a
negatív mérési értékek 0-ként jelennek meg. Ellenpróba:
futtasd mindkét változatot -1.5f-en, és hasonlítsd
össze.
5. Pontosságra épülő egyenlőségvizsgálat.
0.1f tízszeri összeadása nem lesz pontosan
1.0f, ezért az fcmp s0, s1 NE-t
adhat. Ez nem assembly-hiba, hanem IEEE 754 következmény; a megoldás
epsilon-összehasonlítás (fsub + fabs +
fcmp).
1. feladat (magyarázó, alapszint — cél:
megértés-ellenőrzés). Magyarázd el, miért nincs
FADD-nak előjeles és előjel nélküli változata, miközben
SCVTF-nek és UCVTF-nek van! Add meg
FMOV X0, D1 és SCVTF D0, X1 esetén, mit
tartalmaz a célregiszter, ha X1 = 3. Melyik forma ad
3.0-t double-ként, és melyik ad egy
3 értékű egész bitmintát lebegőpontosnak értelmezve?
2. feladat (implementációs, középszint — cél:
rutinépítés). Írj olyan assembly-sorozatot, amely az
S0-ban lévő x float bemenetből
kiszámítja y = (x - 2.5f) * 0.5f-et, az eredményt
S0-ban hagyja, majd egy W1-be csonkítva
konvertálja! Használj FMOV immediate-ot, ha az assembler
elfogadja a 2.5-öt és a 0.5-öt; ha nem, töltsd
a konstansokat .word direktívával a .rodata
szekcióból. Ellenőrizd x = 5.0f-re, hogy az eredmény
1.25f, W1 = 1 legyen, és indokold, mi történik
x = 1.0f esetén.
3. feladat (hibakeresési/mérési, középszint — cél:
rutinépítés). Adott egy assembly program, amely állítólag
3.0f-et konvertál int-té, de 0-t
ad. Írj fel egy háromlépéses hibakeresési tervet: (a) milyen
objdump-kimenetet keresel, (b) mit vizsgálsz GDB-ben, (c)
milyen egyszeri változtatással ellenőrzöd a hipotézist! Milyen bitmintát
vársz 3.0f esetén W regiszterben, ha
FMOV Wd, Sn-nel olvasod ki? Ugyanezt add meg
1.0f-re is.
1. megoldás — Segítség. Gondold át, mit jelent az,
hogy az IEEE 754 formátum előjel-nagyság alakú, és hogy az
FMOV egy bitminta-másolás, nem egy
érték-konverzió — melyik utasítás végez ténylegesen
konverziót?
1. megoldás — Teljes megoldás. Az IEEE 754
lebegőpontos szám előjel-nagyság (sign-magnitude) alakú: nincs kettes
komplemens, ezért az „előjeles/előjel nélküli” megkülönböztetésnek nincs
értelme az aritmetikában — a negatív szám ábrázolása önmagában
tartalmazza az előjelet. Az egész ↔︎ lebegőpontos átalakításnál viszont a
forrás egész értelmezése kétértelmű: a 0xFFFFFFFF
jelenthet -1-et vagy 4294967295-öt, ezért itt
explicit SCVTF/UCVTF döntés kell.
FMOV X0, D1 az X1 = 3 esetén nem
3-at ad X0-ban, hanem a 3.0
double bitmintáját (0x4008000000000000).
SCVTF D0, X1 viszont valóban 3.0
double-t állít elő. Tehát a 3.0 értéket az
SCVTF adja; az FMOV bitmintát másol.
2. megoldás — Segítség. Építsd fel a kifejezést két
lépésben (FSUB, majd FMUL), és gondold át
x = 1.0f-re, hogy a (x - 2.5f) * 0.5f
eredménye negatív lesz-e, és mit tesz ilyenkor a nullához csonkító
konverzió.
2. megoldás — Teljes megoldás. Egy lehetséges
kódrészlet. Bemenete S0 = x, kimenete S0 = y
és W1 = (int)y; a belépési pont és a hívó nem része a
részletnek:
.section .rodata
.align 3
lab_c25: .word 0x40200000 // 2.5f
lab_c05: .word 0x3F000000 // 0.5f
.text
// Kódrészlet: a hívó előzőleg s0-ba helyezte az x bemenetet.
ldr s1, lab_c25 // s1 = 2.5f
ldr s2, lab_c05 // s2 = 0.5f
// feltételezés: s0 = x
fsub s0, s0, s1 // s0 = x - 2.5f
fmul s0, s0, s2 // s0 = (x - 2.5f) * 0.5f
fcvtzs w1, s0 // w1 = (int)y, csonkítvax = 5.0f esetén 5.0 - 2.5 = 2.5,
2.5 * 0.5 = 1.25, csonkítva 1 — a várt
eredmény teljesül. x = 1.0f esetén
1.0 - 2.5 = -1.5, -1.5 * 0.5 = -0.75, amit a
nullához csonkítás 0-ra visz (nem -1-re): ez
pontosan a Z kerekítési mód következménye, és
FCVTZS-t kellett használni FCVTZU helyett,
hogy negatív értékre is értelmes eredményt kapjunk. Az
FMOV S1, #2.5 és FMOV S2, #0.5 valószínűleg
szintén assemble-elhető (mindkettő a szokásos 8 bites konstanskészletbe
esik), de ez assembler-verziófüggő; a .word +
LDR változat mindig működik, és a Load/store címzési módok anyagát is gyakorolja.
3. megoldás — Segítség. Az objdump-ban
keress olyan mnemonicot, amely bitmintát másol ott, ahol a forrás
konverziót ígér — a kettő bitmintája ugyanarra a kiinduló egészre
egészen más float-ot ad.
3. megoldás — Teljes megoldás. (a) Az
objdump-kimenetben fmov mnemonicot keresünk
ott, ahol scvtf-nek kellene lennie:
aarch64-linux-gnu-objdump -d lab-a045-x | grep -E 'fmov|scvtf|fcvtzu'.
(b) GDB-ben töréspontot teszünk az SCVTF után, és megnézzük
$s0 lebegőpontos nézetét (p $s0, várt:
3), majd egy fmov w9, s0 után
p/x $w9 — a várt bitminta 3.0f-re
0x40400000. Ha itt 0x00000000-t látunk, akkor
a mozgatás nem történt meg vagy hibás forrásból indult. (c) Egyetlen
változtatás: ha az objdump fmov-ot mutat,
cseréljük scvtf-re, újraépítünk, és
echo $?-lel ellenőrizzük a 3-at.
1.0f bitmintája 0x3F800000 — érdemes ezt is
fejben tartani, mert a lebegőpontos konstansok azonosítása
disassembly-ben leggyakrabban ezzel a két értékkel kezdődik.
A skaláris lebegőpontos utasítások pontosságát a regiszternév
(Sn/Dn) kódolja, nem a mnemonic, és a két
pontosság nem keverhető. Az
FADD/FSUB/FMUL/FDIV
helyesen kerekít az IEEE 754 szerint, kivételeiket az FPSR
halmozza, nem az NZCV. Az FMOV bitmintát
másol, nem konvertál; a határátlépésre az
SCVTF/UCVTF és az
FCVTZS/FCVTZU szolgál, utóbbi nullához csonkít
és telít. Az FCMP négy kimenetele közül a rendezetlen (NaN)
eset miatt a >-hez GT, a
<=-hez LS kell, nem
HI/LE.
Továbbhasznált definíciók: skaláris lebegőpontos utasítás; FMOV (bit szintű másolás); FCVTZS/FCVTZU (csonkító, telítő konverzió).
A linkek és a dokumentumverziók közös állapota az Olvasói útmutató forrásállapot-táblájában van; itt csak az alfejezet saját megállapításai szerepelnek.
FADD/FMOV/SCVTF/FCVTZS/FCMP
pontos pszeudokódja és az NZCV FP-kiosztása.
Ellenőrizve: a link él, de a fejezetszám és a
kiadásbetű az Arm-oldalak közös korlátja miatt nem ellenőrzött.FPCR (RMode, FZ,
DN) és az FPSR (IOC,
DZC, OFC, UFC, IXC)
mezőinek szerződése ugyanebben a dokumentumban (DDI0487), az utasítások
pszeudokódjával együtt: ez határozza meg, hogy a „helyesen kerekített”
eredmény melyik kerekítési módra értendő. A C-nyelvi oldalon a
konverziók (C17 6.3.1.4) és az alapértelmezett argumentum-előléptetés
(C17 6.5.2.2) szabálya a mérvadó.qemu-aarch64 user-mode viselkedéséhez.
Ellenőrizve: a master ág dokumentációja
(közös verziókorlát); a hivatalos user-mode fejezet
(docs/master/user/main.html) nem állít semmit a cache- vagy
ciklusszám-modellezésről, ezért az alábbi 3. pont levezetés, nem
QEMU-dokumentált tény.Ellenőrzési hiányok, amelyek a fenti ellenőrzés után is fennmaradnak, és amelyeket a hallgatónak a saját laborjában kell lezárnia:
FCVTZS/FCVTZU NaN- és
túlcsordulás-viselkedésének (NaN → 0, telítés a szélsőértékre, IOC
beállítás) pontos ARM ARM megfogalmazása — itt specifikáció szerinti
viselkedésként áll, de a konkrét szöveghely a fenti JS-renderelési
korlát miatt nem volt automatikusan kinyerhető.FMOV Sd, #imm által ténylegesen elfogadott
konstanskészlet az adott as verzióban — az assembler hibája
a mérvadó.FADD/FDIV latenciák táblázata
illusztratív, nem mért; a QEMU TCG egy funkcionális,
utasításszintű emulátor, nem cikluspontos szimulátor, ezért abszolút
latenciát csak fizikai AArch64 hoston vagy a gyártó technikai leírásából
szabad idézni.qemu-aarch64 és a fizikai AArch64 CPU közötti
esetleges eltérés az FPSR flagjeinek jelentésében és a
NaN-propagációban jelölendő, ha a laborban eltérést tapasztalsz.