V již dvacáté první části seriálu o použití assembleru v Linuxu dokončíme téma, kterému jsme se začali věnovat minule. Jedná se o způsob použití podmínek (resp. přesněji řečeno instrukcí s podmínkami) při zpracování dat na moderní 64bitové mikroprocesorové architektuře AArch64. Procesory s touto architekturou totiž kromě podmíněných skoků podporují i některé další instrukce s podmínkou, které byly navrženy a implementovány na základě výsledků studie reálných aplikací.

Obsah

1. Použití assembleru v Linuxu: podmínky při zpracování dat na architektuře AArch64

2. Již známé instrukce: podmíněné skoky

3. Nové instrukce

4. Instrukce CSET – Conditional Set

5. Instrukce CSETM – Conditional Set Mask

6. Instrukce CSEL – Conditional Select

7. Instrukce CSINV – Conditional Select Invert

8. Instrukce CSINC – Conditional Select Increment

9. Instrukce CSNEG – Conditional Select Negate

10. Instrukce CINC – Conditional Increment

11. Instrukce CINV – Conditional Invert

12. Instrukce CNEG – Conditional Negate

13. Instrukce TBZ a TBNZ (Test and Branch…)

14. Odkazy na Internetu

1. Použití assembleru v Linuxu: podmínky při zpracování dat na architektuře AArch64

V dnešní části seriálu o použití assembleru v Linuxu se zaměříme na poměrně zajímavou a prozatím relativně novou oblast. Jedná se o speciální instrukce implementované na moderní mikroprocesorové architektuře AArch64, které prování specifikovanou činnost pouze za předpokladu, že je splněna nějaká zadaná podmínka (kód podmínky je přitom součástí instrukčního slova). Připomeňme si, že na rozdíl od původní 32bitové architektury ARM (dnes označované ARM32) nemají všechny instrukce na AArch64 rezervovány čtyři nejvyšší bity pro specifikaci podmínky. Tato vlastnost byla na základě analýzy existujících programových strojových kódů zrušena a podmínky je tak možné použít jen u vybrané množiny instrukcí. Do této množiny byly zahrnuty i zcela nové instrukce, které na ARM32 nenalezneme, což je opět důsledek analýzy stávajících strojových kódů, ale i studia funkce překladačů.

Poznámka: podle některých vývojářů může mít extenzivní použití příznakových bitů negativní vliv na výkonnost procesoru, což je však téma, které je řešeno nejenom na AArch64, ale i na x86-64.

Připomeňme si, že na procesorové architektuře AArch64 je použito celkem čtrnáct různých podmínek, k nimž se někdy přidává i pseudopodmínka AL neboli Any/Always. V tomto případě se samozřejmě o žádnou skutečnou podmínku nejedná, neboť je instrukce provedena v každém případě.

Prvních šest podmínek testuje hodnotu pouze jediného bitového příznaku, a to N (negative), Z (zero) či V (overflow):

Kód Přípona Význam Testovaná podmínka
0000 EQ Z = 1 rovnost po porovnání (či nulový výsledek)
0001 NE Z = 0 nerovnost po porovnání (či nenulový výsledek)
0100 MI N = 1 výsledek je záporný
0101 PL N = 0 výsledek je kladný či nulový
0110 VS V = 1 nastalo přetečení (overflow)
0111 VC V = 0 nenastalo přetečení (overflow)
1110 AL Any/Always většinou se nezapisuje, implicitní podmínka

Další čtyři podmínkové kódy se většinou používají při porovnávání dvou hodnot bez znaménka (unsigned). V těchto případech se testují stavy příznakových bitů C (carry) a Z (zero), přesněji řečeno kombinace těchto bitů:

Kód Přípona Význam Testovaná podmínka
0010 CS/HS C = 1
0011 CC/LO C = 0 <
1000 HI C = 1 & Z = 0 >
1001 LS C = 0 | Z = 1

Poslední čtyři podmínkové kódy se používají pro porovnávání hodnot se znaménkem (signed). V těchto případech se namísto příznakových bitů (C) carry a (Z) zero testují kombinace bitů (N) negative, (V) overflow a (Z) zero:

Kód Přípona Význam Testovaná podmínka
1010 GE N == V
1011 LT N ≠ V <
1100 GT Z = 0, N = V >
1101 LE Z = 1, N ≠ V

Důležité je, že všechny dále popsané instrukce podporují všechny podmínky. Výjimku tvoří minule popsané instrukce CBZ a CBNZ, které pouze testovaly nulovost či naopak nenulovost vybraného pracovního registru.

2. Již známé instrukce: podmíněné skoky

Již minule jsme se zmínili o některých instrukcích provedených či naopak neprovedených na základě nějaké podmínky. Jednalo se o tyto instrukce:

Instrukce Stručný popis
B.podmínka návěští podmíněný skok po splnění podmínky na zadané návěští (kódy podmínek byly uvedeny výše)
CBZ Wn, návěští pokud platí Wn=0, skok na zadané návěští
CBZ Xn, návěští pokud platí Xn=0, skok na zadané návěští
CBNZ Wn, návěští pokud platí Wn≠0, skok na zadané návěští
CBNZ Xn, návěští pokud platí Xn≠0, skok na zadané návěští

Tyto instrukce jsou (ve své variantě s 32bitovými registry) zpětně kompatibilní s instrukcemi známými z 32bitové architektury ARM32.

3. Nové instrukce

Mezi nové instrukce s podmínkou, které lze použít na architektuře AArch64, patří především:

Instrukce Význam mnemotechnického kódu Kapitola
CSET Conditional Set 4
CSETM Conditional Set Mask 5
CSEL Conditional Select 6
CSINV Conditional Select Invert 7
CSINC Conditional Select Increment 8
CSNEG Conditional Select Negate 9
CINC Conditional Increment 10
CINV Conditional Invert 11
CNEG Conditional Negate 12
TBZ Test and Branch if Zero 13
TBNZ Test and Branch if not zero 13

4. Instrukce CSET – Conditional Set

První novou instrukcí, s níž se dnes seznámíme, je instrukce nazvaná CSET neboli Conditional Set. Tato instrukce vlastně přímo odpovídá požadavkům kladeným na datový typ boolean v mnoha programovacích jazycích, v nichž je hodnota true interně reprezentována jedničkou a hodnota false nulou. Tato instrukce existuje ve dvou variantách, přičemž první varianta pracuje s 32bitovým a druhá varianta s 64bitovým operandem):

CSET Wd, condition
CSET Xd, condition

Například:

CSET W3, EQ
CSET W4, MI
CSET X5, HI

Tato instrukce pracuje následujícím způsobem – v případě, že je podmínka zapsaná ve druhém operandu cond splněna, uloží se do cílového registru Wd či do registru Xd hodnota 1. Pokud podmínka naopak splněna není, uloží se do registru Wd či Xd hodnota 0:

cíl = condition ? 1 : 0;

Ve skutečnosti se v případě CSET jedná o alias pro instrukci CSINC popsanou dále (podmínka ovšem musí být v tomto případě negována):

CSINC Wd, WZR, WZR, invert(condition)
CSINC Xd, XZR, XZR, invert(condition)

neboli:

cíl = invert(condition) ? 0 : 0+1;

5. Instrukce CSETM – Conditional Set Mask

V některých případech je nutné ukládat pravdivostní hodnoty odlišným způsobem – true bude reprezentováno hodnotou, v níž jsou všechny bity nastaveny na jedničku (v případě celých čísel se znaménkem to odpovídá hodnotě -1), false naopak hodnotou, v níž jsou všechny bity nulové. V tomto případě lze pro nastavení použít instrukci CSETM:

CSETM Wd, condition
CSETM Xd, condition

Ve vyšším programovacím jazyce by bylo možné napsat:

cíl = condition ? -1 : 0;

Poznámka: u 32bitového registru odpovídá -1 hodnotě 0xffff ffff, u 64bitového registru pak hodnotě 0xffff ffff ffff ffff.

Opět se jedná o aliasy, tentokrát ovšem na instrukci CSINV:

CSINV Wd, WZR, WZR, invert(condition)
CSINV Xd, XZR, XZR, invert(condition)

Poznámka: slovo „mask“ v názvu instrukce skutečně poměrně přesně odpovídá jednomu způsobu použití, protože pokud platí true=-1 a false=0, lze s těmito hodnotami provádět logický součin a součet bit po bitu, a to i v případě, kdy je druhým operandem odlišná hodnota.

6. Instrukce CSEL – Conditional Select

Další užitečnou instrukcí s podmínkou je instrukce zapisovaná mnemotechnickým kódem CSEL neboli Conditional Select. I tato instrukce existuje ve dvou variantách – 32bitové a 64bitové:

CSEL Wd, Wn, Wm, condition
CSEL Xd, Xn, Xm, condition

Tato instrukce pracuje následovně: pokud je podmínka splněna, uloží se do cílového registru Wd či Xd hodnota z prvního zdrojového registru Wn nebo Xn. Pokud podmínka splněna není, je do cílového registru Wd/Xd uložena hodnota z druhého zdrojového registru Wm/Xm.

Instrukce CSEL tedy nahrazuje programovou konstrukci typu:

cíl = condition ? zdroj1 : zdroj2;

7. Instrukce CSINV – Conditional Select Invert

Alternativní formou instrukce CSEL je instrukce CSINV neboli Conditional Select Invert:

CSINV Wd, Wn, Wm, condition
CSINV Xd, Xn, Xm, condition

Tato instrukce pracuje následovně: pokud je podmínka splněna, uloží se do cílového registru Wd či Xd hodnota z prvního zdrojového registru Wn nebo Xn. Pokud podmínka splněna není, je do cílového registru Wd/Xd uložena negovaná hodnota přečtená z druhého zdrojového registru Wm/Xm.

Instrukce CSINV tedy nahrazuje programovou konstrukci typu:

cíl = condition ? zdroj1 : ~zdroj2;

Poznámka: znak ~ je používán v programovacím jazyku C a od něj odvozených jazycích pro zápis unárního operátoru negace všech bitů (jedničkový doplněk).

8. Instrukce CSINC – Conditional Select Increment

Zajímavá je instrukce CSINC, která kombinuje možnosti instrukce CINC a CSEL:

CSINC Wd, Wn, Wm, condition
CSINC Xd, Xn, Xm, condition

Tato instrukce provádí následující činnost:

Wd = condition ? Wn : Wm+1;
Xd = condition ? Xn : Xm+1;

Jak jsme si již řekli ve čtvrté kapitole, je touto instrukcí realizována i pseudoinstrukce CSET, a to tehdy, pokud jsou oba zdrojové registry nulové (WZR a XZR). V tomto případě se do cílového registru dosadí 0 či 0+1=1:

CSINC Wd, WZR, WZR, invert(condition)
CSINC Xd, XZR, XZR, invert(condition)

9. Instrukce CSNEG – Conditional Select Negate

Instrukce nazvaná CSNEG se do jisté míry podobá instrukci CSINV, ovšem s tím rozdílem, že se namísto jedničkového doplňku (negace) používá při nesplnění podmínky dvojkový doplněk:

CSNEG Wd, Wn, Wm, condition
CSNEG Xd, Xn, Xm, condition

Tato instrukce pracuje následovně: pokud je podmínka splněna, uloží se do cílového registru Wd či Xd hodnota z prvního zdrojového registru Wn nebo Xn. Pokud podmínka splněna není, je do cílového registru Wd/Xd uložena hodnota přečtená z druhého zdrojového registru Wm/Xm, u které se nejdříve změní znaménko (onen zmíněný dvojkový doplněk).

Tato instrukce tedy nahrazuje programovou konstrukci typu:

cíl = condition ? zdroj1 : -zdroj2;

10. Instrukce CINC – Conditional Increment

Instrukce CINC je aliasem pro instrukci CSINC, ovšem s převrácenou podmínkou a shodnými zdrojovými registry:

CINC Wd, Wn, condition
CINC Xd, Xn, condition

Tato instrukce provádí následující činnost (je zde jen jediný zdrojový registr):

Wd = condition ? Wn+1 : Wn;
Xd = condition ? Xn+1 : Xn;

Použití této instrukce je různé, může se například použít pro realizaci příkazu continue v programovacím jazyku C.

11. Instrukce CINV – Conditional Invert

Podobná instrukce taktéž s jedním zdrojovým registrem se jmenuje CINV:

CINV Wd, Wn, condition
CINV Xd, Xn, condition

Prováděná činnost je následující (tilda znamená negaci bit po bitu):

Wd = condition ? ~Wn : Wn;
Xd = condition ? ~Xn : Xn;

Ve skutečnosti se opět jedná o instrukční alias rozpoznávaný assemblery. V tomto případě lze CINV nahradit instrukcí CSINV s oběma zdrojovými registry totožnými:

CSINV Wd, Wn, Wn, invert(condition)
CSINV Xd, Xn, Xn, invert(condition)

12. Instrukce CNEG – Conditional Negate

Poslední instrukce, přesněji řečeno (opět) instrukční alias se jmenuje CNEG:

CNEG Wd, Wn, condition
CNEG Xd, Xn, condition

Prováděná činnost:

Wd = condition ? -Wn : Wn;
Xd = condition ? -Xn : Xn;

Tento alias lze nahradit za CSNEG s totožnými zdrojovými registry a opačně zapsanou podmínkou:

CSNEG Wd, Wn, Wn, invert(condition)
CSNEG Xd, Xn, Xn, invert(condition)

13. Instrukce TBZ a TBNZ (Test and Branch…)

Poslední dvě instrukce, které si dnes popíšeme, spadají do kategorie podmíněných skoků. Tyto instrukce se jmenují TBZ (Test and Branch if Zero) a TBNZ (Test and Branch if Not Zero). Způsob zápisu těchto instrukcí je následující:

TBZ  Xn, #konstanta, návěští
TBZ  Wn, #konstanta, návěští
TBNZ Xn, #konstanta, návěští
TBNZ Wn, #konstanta, návěští

Konstanta má šířku pouze šest bitů, protože je v ní uložen index bitu pracovního registru, který se testuje na nulu či jedničku (u registrů Wn by stačilo jen pět bitů). V případě instrukce TBZ – pokud je n-tý bit registru Xn/Wn nastavený na nulu, provede se skok, v opačném případě se řízení přenese na další instrukci. V případě instrukce TBNZ je bit testován na nulu. Vzhledem k tomu, že v instrukčním slovu je nutné kromě adresy cíle (návěští) specifikovat i číslo pracovního registru a index bitu, je tento typ skoku omezen na rozsah ±32kB, což by ovšem v praxi mělo být více než dostačující (v opačném případě lze TBZ/TBNZ zkombinovat s absolutním skokem B).

14. Odkazy na Internetu

  1. Cortex-A35
    https://www.arm.com/products/processors/cortex-a/cortex-a35-processor.php
  2. Cortex-A53
    https://www.arm.com/products/processors/cortex-a/cortex-a53-processor.php
  3. Cortex-A57
    https://www.arm.com/products/processors/cortex-a/cortex-a57-processor.php
  4. Cortex-A72
    https://www.arm.com/products/processors/cortex-a/cortex-a72-processor.php
  5. Cortex-A73
    https://www.arm.com/products/processors/cortex-a/cortex-a73-processor.php
  6. System cally pro AArch64 na Linuxu
    https://github.com/torvalds/linux/blob/master/include/uapi/asm-generic/unistd.h
  7. Architectures/AArch64 (FedoraProject.org)
    https://fedoraproject.org/wiki/Architectures/AArch64
  8. SIG pro AArch64 (CentOS)
    https://wiki.centos.org/SpecialInterestGroup/AltArch/AArch64
  9. The ARMv8 instruction sets
    http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.den0024a/ch05s01.html
  10. A64 Instruction Set
    https://developer.arm.com/products/architecture/instruction-sets/a64-instruction-set
  11. Switching between the instruction sets
    http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.den0024a/ch05s01.html
  12. The A64 instruction set
    http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.den0024a/ch05s01.html
  13. Introduction to ARMv8 64-bit Architecture
    https://quequero.org/2014/04/introduction-to-arm-architecture/
  14. MCU market turns to 32-bits and ARM
    http://www.eetimes.com/document.asp?doc_id=1280803
  15. Cortex-M0 Processor (ARM Holdings)
    http://www.arm.com/products/processors/cortex-m/cortex-m0.php
  16. Cortex-M0+ Processor (ARM Holdings)
    http://www.arm.com/products/processors/cortex-m/cortex-m0plus.php
  17. ARM Processors in a Mixed Signal World
    http://www.eeweb.com/blog/arm/arm-processors-in-a-mixed-signal-world
  18. ARM Architecture (Wikipedia)
    https://en.wikipedia.org/wiki/ARM_architecture
  19. ARM Documentation: B, BL, BX, BLX, and BXJ
    http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0204j/Cihfddaf.html
  20. Branch and Call Sequences Explained
    https://community.arm.com/groups/processors/blog/2013/09/25/branch-and-call-sequences-explained
  21. Improving ARM Code Density and Performance
    New Thumb Extensions to the ARM Architecture Richard Phelan
  22. Aarch64 Register and Instruction Quick Start
    https://wiki.cdot.senecacollege.ca/wiki/Aarch64_Register_and_Instruction_Quick_Start
  23. Exploring AArch64 assembler – Chapter 1
    http://thinkingeek.com/2016/10/08/exploring-aarch64-assembler-chapter1/
  24. Exploring AArch64 assembler – Chapter 2
    http://thinkingeek.com/2016/10/08/exploring-aarch64-assembler-chapter-2/
  25. The ARM Processor Architecture
    http://www.arm.com/products/processors/technologies/instruction-set-architectures.php
  26. Thumb-2 instruction set
    http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0344c/Beiiegaf.html
  27. Introduction to ARM thumb
    http://www.eetimes.com/discussion/other/4024632/Introduction-to-ARM-thumb
  28. ARM, Thumb, and ThumbEE instruction sets
    http://www.keil.com/support/man/docs/armasm/armasm_CEGBEIJB.htm
  29. An Introduction to ARM Assembly Language
    http://dev.emcelettronica.com/introduction-to-arm-assembly-language
  30. Processors – ARM
    http://www.arm.com/products/processors/index.php
  31. The ARM Instruction Set
    http://simplemachines.it/doc/arm_inst.pdf
  32. ARM Architecture (Wikipedia)
    http://en.wikipedia.org/wiki/ARM_architecture
  33. C Functions Without Arguments
    https://eklitzke.org/c-functions-without-arguments
  34. GNU Assembler Examples
    http://cs.lmu.edu/~ray/notes/gasexamples/
  35. Simply FPU
    http://www.website.masmforum.com/tutorials/fptute/
  36. Art of Assembly language programming: The 80×87 Floating Point Coprocessors
    https://courses.engr.illinois.edu/ece390/books/artofasm/CH14/CH14-3.html
  37. Art of Assembly language programming: The FPU Instruction Set
    https://courses.engr.illinois.edu/ece390/books/artofasm/CH14/CH14-4.html
  38. INTEL 80387 PROGRAMMER’S REFERENCE MANUAL
    http://www.ragestorm.net/downloads/387intel.txt
  39. x86 Instruction Set Reference: FLD
    http://x86.renejeschke.de/html/file_module_x86_id_100.html
  40. x86 Instruction Set Reference: FLD1/FLDL2T/FLDL2E/FLDPI/FLDLG2/FLDLN2/FLDZ
    http://x86.renejeschke.de/html/file_module_x86_id_101.html
  41. x86 Instruction Set Reference: FLD
    http://x86.renejeschke.de/html/file_module_x86_id_100.html
  42. x86 Instruction Set Reference: FST/FSTP
    http://x86.renejeschke.de/html/file_module_x86_id_117.html
  43. x86 Instruction Set Reference: BTC
    http://x86.renejeschke.de/html/file_module_x86_id_23.html
  44. x86 Instruction Set Reference: BTR
    http://x86.renejeschke.de/html/file_module_x86_id_24.html
  45. x86 Instruction Set Reference: BTS
    http://x86.renejeschke.de/html/file_module_x86_id_25.html
  46. x86 Instruction Set Reference: BSF
    http://x86.renejeschke.de/html/file_module_x86_id_19.html
  47. x86 Instruction Set Reference: BSR
    http://x86.renejeschke.de/html/file_module_x86_id_20.html
  48. x86 Instruction Set Reference: BSWAP
    http://x86.renejeschke.de/html/file_module_x86_id_21.html
  49. x86 Instruction Set Reference: XCHG
    http://x86.renejeschke.de/html/file_module_x86_id_328.html
  50. x86 Instruction Set Reference: SETcc
    http://x86.renejeschke.de/html/file_module_x86_id_288.html
  51. X86 Assembly/Arithmetic
    https://en.wikibooks.org/wiki/X86_Assembly/Arithmetic
  52. Art of Assembly – Arithmetic Instructions
    http://oopweb.com/Assembly/Documents/ArtOfAssembly/Volume/Chapter_6/CH06-2.html
  53. The GNU Assembler Tutorial
    http://tigcc.ticalc.org/doc/gnuasm.html
  54. The GNU Assembler – macros
    http://tigcc.ticalc.org/doc/gnuasm.html#SEC109
  55. ARM subroutines & program stack
    http://www.toves.org/books/armsub/
  56. Generating Mixed Source and Assembly List using GCC
    http://www.systutorials.com/240/generate-a-mixed-source-and-assembly-listing-using-gcc/
  57. Calling subroutines
    http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.kui0100a/armasm_cihcfigg.htm
  58. ARM Assembly Language Programming
    http://peter-cockerell.net/aalp/html/frames.html
  59. ASM Flags
    http://www.cavestory.org/guides/csasm/guide/asm_flags.html
  60. Status Register
    https://en.wikipedia.org/wiki/Status_register
  61. Intel x86 JUMP quick reference
    http://unixwiz.net/techtips/x86-jumps.html
  62. Linux assemblers: A comparison of GAS and NASM
    http://www.ibm.com/developerworks/library/l-gas-nasm/index.html
  63. Programovani v assembleru na OS Linux
    http://www.cs.vsb.cz/grygarek/asm/asmlinux.html
  64. Is it worthwhile to learn x86 assembly language today?
    https://www.quora.com/Is-it-worthwhile-to-learn-x86-assembly-language-today?share=1
  65. Why Learn Assembly Language?
    http://www.codeproject.com/Articles/89460/Why-Learn-Assembly-Language
  66. Is Assembly still relevant?
    http://programmers.stackexchange.com/questions/95836/is-assembly-still-relevant
  67. Why Learning Assembly Language Is Still a Good Idea
    http://www.onlamp.com/pub/a/onlamp/2004/05/06/writegreatcode.html
  68. Assembly language today
    http://beust.com/weblog/2004/06/23/assembly-language-today/
  69. Assembler: Význam assembleru dnes
    http://www.builder.cz/rubriky/assembler/vyznam-assembleru-dnes-155960cz
  70. Assembler pod Linuxem
    http://phoenix.inf.upol.cz/linux/prog/asm.html
  71. AT&T Syntax versus Intel Syntax
    https://www.sourceware.org/binutils/docs-2.12/as.info/i386-Syntax.html
  72. Linux Assembly website
    http://asm.sourceforge.net/
  73. Using Assembly Language in Linux
    http://asm.sourceforge.net/articles/linasm.html
  74. vasm
    http://sun.hasenbraten.de/vasm/
  75. vasm – dokumentace
    http://sun.hasenbraten.de/vasm/release/vasm.html
  76. The Yasm Modular Assembler Project
    http://yasm.tortall.net/
  77. 680×0:AsmOne
    http://www.amigacoding.com/index.php/680×0:AsmOne
  78. ASM-One Macro Assembler
    http://en.wikipedia.org/wiki/ASM-One_Macro_Assembler
  79. ASM-One pages
    http://www.theflamearrows.info/documents/asmone.html
  80. Základní informace o ASM-One
    http://www.theflamearrows.info/documents/asminfo.html
  81. Linux Syscall Reference
    http://syscalls.kernelgrok.com/
  82. Programming from the Ground Up Book – Summary
    http://savannah.nongnu.org/projects/pgubook/
  83. IBM System 360/370 Compiler and Historical Documentation
    http://www.edelweb.fr/Simula/
  84. IBM 700/7000 series
    http://en.wikipedia.org/wiki/IBM_700/7000_series
  85. IBM System/360
    http://en.wikipedia.org/wiki/IBM_System/360
  86. IBM System/370
    http://en.wikipedia.org/wiki/IBM_System/370
  87. Mainframe family tree and chronology
    http://www-03.ibm.com/ibm/history/exhibits/mainframe/mainframe_FT1.html
  88. 704 Data Processing System
    http://www-03.ibm.com/ibm/history/exhibits/mainframe/mainframe_PP704.html
  89. 705 Data Processing System
    http://www-03.ibm.com/ibm/history/exhibits/mainframe/mainframe_PP705.html
  90. The IBM 704
    http://www.columbia.edu/acis/history/704.html
  91. IBM Mainframe album
    http://www-03.ibm.com/ibm/history/exhibits/mainframe/mainframe_album.html
  92. Osmibitové muzeum
    http://osmi.tarbik.com/
  93. Tesla PMI-80
    http://osmi.tarbik.com/cssr/pmi80.html
  94. PMI-80
    http://en.wikipedia.org/wiki/PMI-80
  95. PMI-80
    http://www.old-computers.com/museum/computer.asp?st=1&c=1016
  96. The 6502 overflow flag explained mathematically
    http://www.righto.com/2012/12/the-6502-overflow-flag-explained.html
  97. X86 Opcode and Instruction Reference
    http://ref.x86asm.net/coder32.html