8-bit Full Adder: Sčítačka na nepájivom poli

Od stlačenia „rovná sa“ cez tranzistory a NAND hradlá až po LCD. Osobný experiment, ktorým som si na vlastnej koži overil, ako procesor vlastne počíta.
Viete, ako počítač vlastne počíta? Keď napíšeme 21 + 7, počítač nám okamžite ukáže 28. Ale čo sa pri tom sčítaní naozaj deje vo vnútri procesora? V procesore sa nachádza ALU – aritmeticko-logická jednotka, ktorá vykonáva rôzne aritmetické a logické operácie, napríklad ADD, SUB, AND, OR, XOR, NOT, INC, DEC a ďalšie. Na prvý pohľad to vyzerá jednoducho. ALU dostane čísla, spracuje ich a vráti výsledok. Ale ako to vlastne dokáže?
A práve to ma začalo zaujímať. Ešte pred stavbou samotnej sčítačky si zopakujeme binárnu matemtiku, čo je tranzistor, ALU a z čoho sa skladá samotná sčítačka, všetko len okrajovo .A aby nezostalo iba pri teórii, všetko si nakoniec postavíme aj prakticky. Čísla budeme zadávať pomocou DIP switchov, výsledky zobrazíme na LED diódach a celé to nakoniec zobrazíme na displeji.
Takže sa poďme pozrieť, čo sa v skutočnosti skrýva za obyčajným: A+B = C. Pretože cesta od tohto jednoduchého zápisu až k tranzistorom je oveľa zaujímavejšia, než sa môže zdať.

Inšpiráciu som si bral aj z ľudí, ktorí podobné veci stavajú verejne. Napríklad z projektu 8-bitového počítača na breadboarde od Bena Eatera a z kurzu Nand2Tetris, kde sa celý počítač skladá od NAND hradla nahor. Ja som sa však zámerne zastavil pri jednom kúsku: pri sčítaní. Lebo keď pochopíte sčítanie, ste už veľmi blízko k tomu, ako procesor vôbec uvažuje.
Niesom rodený rečník tak v prípade ak sa budete zaujímať hlbšie o niektorú teóriu spomínanú v článku, tak odporúčam odkazy na konci alebo použiť internet ))
2. Ako počítač myslí v binárnej sústave
Keď sa povie „čísla“, väčšina z nás si hneď predstaví desiatkovú sústavu. Máme desať prstov a odmalička nás učia počítať od nuly do deväť. Počítače sú v tomto smere lenivé, alebo ak chcete, maximálne praktické. Nemajú oči, nepoznajú odtiene sivej a už vôbec netušia, čo znamená číslo sedem. Poznajú len to, či niekde je napätie, alebo nie je.
Prečo len nula a jednotka?

Prečo teda počítače používajú len dve úrovne: 0 (vypnuté, blízko 0 V) a 1 (zapnuté, typicky 5 V alebo 3,3 V)? Odpoveď je prekvapivo prozaická: spoľahlivosť a jednoduchosť. Predstavme si, že by som v elektronike chcel rozlíšiť desať rôznych napäťových hladín. Nula voltov pre nulu, 0,5 V pre jednotku, 1 V pre dvojku, až po 5 V pre deviatku. Stačilo by, aby v izbe mierne kolísalo napätie, trochu sa zohriali súčiastky, a zrazu by sa 3,2 V stalo 3,1 V. Obvod by v tej chvíli netušil, či počítam s trojkou alebo so štvorkou. Výsledky by boli katastrofálne.
Ak však pracujem iba s dvoma stavmi, život je hneď jednoduchší:
- 0 (LOW): nízke napätie, blízko 0 voltov. Vypnuté.
- 1 (HIGH): napätie v rozsahu, ktorý konkrétna logická technológia považuje za platnú jednotku. Pri 5 V logike to môže byť približne 5 V, ale nie je to univerzálne pravidlo
Aj keby napätie kvôli záťaži kleslo na 4,2 V alebo stúplo na 4,8 V, elektronika to stále bezpečne vyhodnotí ako jednotku. Žiadne pochybnosti. Presne preto sa v digitálnej technike používajú logické úrovne s rezervou, nie s desiatimi tesne nalepenými hladinami. V tomto projekte budeme používať binárnu matematiku s binárnou logikou.
Sčítanie v binárnom svete: ešte jednoduchšie ako v škole
Keďže máme k dispozícii iba dve číslice, 0 a 1, aj matematika v binárnej sústave vyzerá neuveriteľne minimalisticky. V desiatkovej sústave sa musíme učiť celú tabuľku sčítania spamäti. V binárnej sústave stačia štyri pravidlá:
- 0 + 0 = 0 (žiadne prekvapenie)
- 0 + 1 = 1 (stále v pohode)
- 1 + 0 = 1 (taktiež jasné)
- 1 + 1 = 10 (a tu to začína byť zaujímavé)
Počkajte, 10? V binárnej sústave totiž neexistuje symbol „2“. Ak sčítame jednotku a jednotku, dostávame hodnotu dva, čo sa zapíše ako 0 v stĺpci v pravo a jeden prenos (carry) ide do vyššieho rádu. Presne tak, ako keď v desiatkovej sústave sčítame 5 + 5, napíšeme 0 a jednotku si „podáme“ do stĺpca desiatok, čím vznikne 10.

Skúsim to ukázať na malom príklade, na sčítaní 2 + 1.
- Číslo 2 sa v binárnom kóde píše ako 10.
- Číslo 1 sa v binárnom kóde píše ako 01 (alebo len 1).
Keď ich pod seba sčítam:
10 (teda 2)
+ 01 (teda 1)
—-
11 (teda 2 + 1 = 3)
Funguje to. A presne toto, len natiahnuté na ôsmich bitoch vedľa seba, robí aj môj hardvér. Znie to jednoducho. Lenže kým som to celé prepojil na reálne súčiastky, musel som pochopiť, z čoho sa takýto digitálny mozog vlastne skladá. A hlavne som si musel overiť, že rozumiem prenosu. Bez prenosu nie je sčítačka sčítačkou. Je to len hromada NAND hradiel, ktoré sa tvária, že počítajú.
Keď sa prenos preleje cez celý stĺpec: 21 + 7
Poďme na zaujímavejší príklad, kde sa prenos (carry) naplno prejaví. Sčítam 21 + 7. Bity si napíšem pod seba a sčítavam sprava doľava, od najnižšieho bitu po najvyšší. Aby sedeli dĺžky, obe čísla zarovnám na päť bitov:
Číslo A (21): 1 0 1 0 1
+ Číslo B (7): 0 0 1 1 1
———–
Súčet S (28): 1 1 1 0 0
Teraz ten istý výpočet stĺpec po stĺpci, od najnižšieho bitu 2⁰ smerom doľava.
- Stĺpec 2⁰: sčítavam 1 + 1. V binárnej sústave je to 10, čiže píšem S = 0 a prenos C = 1 posielam doľava.
- Stĺpec 2¹: sčítavam 0 (z A) + 1 (z B) + prenos 1. Celkovo 0 + 1 + 1 = 2, teda znova 10. Píšem S = 0 a prenos C = 1 ide ďalej.
- Stĺpec 2²: sčítavam 1 + 1 + prenos 1. Celkovo 3, v binárnom zápise 11. Píšem S = 1 a prenos C = 1.
- Stĺpec 2³: sčítavam 0 + 0 + prenos 1. Celkovo 1. Píšem S = 1 a prenos C = 0.
- Stĺpec 2⁴: sčítavam 1 + 0 + prenos 0. Celkovo 1. Píšem S = 1 a prenos C = 0.
Po spojení bitov mi teda vyjde 11100, čo je presne 28. Nie 14, nie 1110, nie „skoro to sedí“. Presne 28. Túto kontrolu som si písal na papier viackrát, lebo neskôr, keď na breadboarde svietili zlé LED diódy, som potreboval etalón, ktorému verím viac než vodičom a hromadu meditácie.
Presne takto, len natiahnuté na 8 a viac bitov za sebou, to počítajú aj logické obvody v sčítačke. Každý bit si preberá prenos od svojho suseda vpravo, pripočíta ho k svojim dvom číslam a posúva ďalší prenos zase doľava. V tomto zjednodušenom pohľade však vidíme jednu z najdôležitejších stavebných častí procesora: obvod, ktorý dokáže z bitov vytvoriť aritmetický výsledok. Toľko k čistej matematike na papieri. Jednoduché, nie?
3. Stavebný kameň všetkého: tranzistor

Keď som si ujasnil riadenie a tok dát, prišiel rad na tranzistor. Maličká, nenápadná súčiastka, bez ktorej by neexistoval žiadny počítač, smartfón ani internet. Tranzistor nemá žiadne pohyblivé časti. Je to polovodičová súčiastka, ktorá dokáže fungovať ako elektronický spínač – môže teda riadiť tok elektrického prúdu. A práve z obrovského množstva takýchto malých spínačov sú postavené moderné procesory.
Predstavujem si ho ako vypínač na stene, ktorým zapínam svetlo. Rozdiel je v tom, že:
- klasický vypínač musím stlačiť prstom,
- tranzistor prepína prúd pomocou iného prúdu alebo napätia, a to miliónkrát za sekundu.

Ak do riadiaceho vstupu privediem správne napätie, tranzistor zopne a pustí prúd cez seba. Stav 1. Ak napätie odoberiem, uzavrie sa a prúd netečie. Stav 0. Žiadne opotrebovanie, žiadny hluk, len čistá fyzika na kremíkovom základe. Prvýkrát som si to overil na jednom malom NPN tranzistore, LED dióde a rezistore. Nič slávnostné. Len svetlo, ktoré sa rozsvietilo, keď som na bázu pustil napätie. Aj tak som pri tom chvíľu sedel a pozeral. Presne tento princíp, len v úplne inej mierke a v miliardách navzájom prepojených tranzistorov, používajú moderné procesory.
Pre môj účel budeme potrebovať 18 NPN tranzistorov pre jednu sčítačku takže dokopy pre 8 bitovú sčítačku potrebujeme 144 traknzistorov.
Od analógového sveta k digitálnej logike
Svet okolo nás je od prírody analógový. Teplota vonku neklesá skokovo z 20 °C na 10 °C. Klesá plynulo. Zvuk reči je plynulá vlna. Elektrina v drôtoch sa správa rovnako. Napätie môže byť 1,2 V, 3,7 V, alebo hocičo medzi tým. Keby som s týmito premenlivými hodnotami chcel spoľahlivo počítať, bol by to chaos. Stačilo by, aby sa v izbe trochu zohrial vzduch, a hodnoty by sa posunuli.
Tu prichádza kľúčový trik tranzistorov: prinútili sme ich správať sa digitálne. Prestali nás zaujímať plynulé odtiene napätia. Povedali sme im:

- všetko pod určitou hranicou, napríklad pod 0,8 V pri TTL, berieme ako tvrdú nulu,
- všetko nad hornou hranicou, napríklad nad 2 V pri TTL alebo ešte vyššie pri CMOS, berieme ako tvrdú jednotku.
Tranzistor tak funguje ako filter neistoty. Aj keby prichádzajúci signál bol slabší alebo špinavý od rušenia, obvod ho buď stiahne k nule, alebo ho pustí ako stabilnú jednotku. Vďaka tomuto triku dokážeme milióny týchto malých spínačov pospájať dohromady a vytvoriť z nich stabilnú digitálnu logiku. A práve z tejto logiky som potom staval prvé hradlá.
Historicky to nie je nový nápad. Už Claude Shannon v roku 1938 ukázal, že relé a spínače sa dajú popisovať Boolovou algebrou. Dnešné čipy robia to isté, len namiesto relé majú tranzistory a namiesto rachotu tichý kremík.
4. Logické hradlá a univerzálne hradlo NAND
Keď tranzistor viackrát spojím podľa pravidiel, prestane byť len spínačom a stane sa z neho logické hradlo. Hradlo je dohoda: na vstupe má nuly a jednotky (0V,5V), na výstupe jednu odpoveď (0/1). Nič viac. Celá digitálna elektronika je v podstate obrovská skladba týchto maličkých dohôd.
AND, OR, NOT: tri vety, z ktorých rastie všetko
Základné operácie som si prekladal do ľudštiny, kým som ich začal zapájať:
- AND (a zároveň): výstup je 1 len vtedy, keď sú všetky vstupy 1. Ako dvoje dvere za sebou. Musím otvoriť oboje.



- OR (alebo): výstup je 1, keď je 1 aspoň jeden vstup. Stačí jedny dvere.



- NOT (negácia): výstup je opak vstupu. Z 1 spraví 0, z 0 spraví 1.


- XOR (exkluzívne alebo): výstup je 1, keď sa vstupy líšia. Presne toto je sčítanie bez prenosu.



XOR je sranda lebo 0 + 1 je 1, 1 + 0 je 1, ale 1 + 1 už nie je 1. Je to 0 a prenos. XOR teda počíta súčet. AND počíta prenos. V tej vete je schovaná celá polovičná sčítačka.
Prečo je NAND kráľom logiky
V katalógoch súčiastok nájdete AND, OR, XOR, NOR aj invertor. Ja som sa však najdlhšie zdržal pri NAND. NAND je AND s negáciou na výstupe. Výstup je 0 len vtedy, keď sú oba vstupy 1. Vo všetkých ostatných prípadoch je 1. Znie to ako detail. Nie je.

NAND je funkčne úplný. Z čistých NAND hradiel vieme postaviť akúkoľvek inú logickú funkciu. NOT vznikne tak, že oba vstupy NAND spojím dokopy. AND vznikne tak, že za NAND dám ešte jeden NAND zapojený ako invertor. OR vznikne cez de Morganove zákony: najprv oba vstupy znegujem a potom ich spojím NAND-om. XOR sa dá poskladať zo štyroch NAND hradiel. A keď mám XOR a AND, mám sčítačku.
| A | B | AND | OR | XOR | NAND | NOT A |
| 0 | 0 | 0 | 0 | 0 | 1 | 1 |
| 0 | 1 | 0 | 1 | 1 | 1 | 1 |
| 1 | 0 | 0 | 1 | 1 | 1 | 0 |
| 1 | 1 | 1 | 1 | 0 | 0 | 0 |
Tabuľka 1: Základné logické funkcie. NOT A nezávisí od B; v poslednom stĺpci je len pre porovnanie.
Preto sa v učebniciach aj v projektoch ako Nand2Tetris začína práve tu. Nie preto, že by NAND bol vždy najrýchlejší alebo najúspornejší. Ale preto, že z jednej tehly viem postaviť celý dom. Na breadboarde som preto ako základnú logiku použil práve NAND hradlá.
Dá sa to, samozrejme, poskladať aj inak. Z NOR hradiel, z CMOS párov, z hotových XOR čipov. Logika nie je náboženstvo. NAND je len najšikovnejší spoločný menovateľ.

5. Od hradiel k matematike: polovičná sčítačka
Keď už hradlá nie sú magické krabičky, dá sa z nich poskladať prvá vec, ktorá vyzerá ako matematika. Polovičná sčítačka(half adder) má dva vstupy, A a B, a dva výstupy: súčet S a prenos C. Polovičná je preto, že nevie prijať prenos z predchádzajúceho bitu. Vie sčítať len jeden stĺpec, a to ten úplne vpravo.
Vzorce sú krátke:
S = A XOR B
C = A AND B
Slovami: ak sa bity líšia, výsledok je 1. Ak sú oba 1, výsledok v tomto stĺpci je 0 a jednotku treba poslať o rád vyššie. Ak sú oba 0, nestalo sa nič.
| A | B | Súčet S | Prenos C |
| 0 | 0 | 0 | 0 |
| 0 | 1 | 1 | 0 |
| 1 | 0 | 1 | 0 |
| 1 | 1 | 0 | 1 |
Tabuľka 2: Pravdivostná tabuľka polovičnej sčítačky. Jediný riadok s prenosom je 1 + 1.
Half adder čisto z NAND hradiel
XOR sa z NAND poskladá takto. Najprv z A a B urobím NAND, teda !(A · B). Potom tento medzivýsledok ešte raz „prežujem“ s pôvodným A a s pôvodným B. Nakoniec tie dva výstupy spojím ďalším NAND-om. Štyri hradlá a mám súčet. Prenos je ešte jednoduchší: NAND z A a B, za ním invertor, teda ďalší NAND so spojenými vstupmi. Z !(A · B) spravím znova A · B.
V simulátore Falstad Circuit Simulator som si to isté overil ešte pred tým, než som začal plýtvať vodičmi. Falstad je v tomto milosrdný. Ukázal mi, kde tečie prúd, a ja som si mohol half adder rozbiť a zložiť bez toho, aby som niečo ohol. Na breadboarde už milosrdenstvo končí skôr.


6. Plná sčítačka a reťazenie na 8 bitov
Polovičná sčítačka mi stačila na najnižší bit. Na druhý bit už nie. Tam totiž okrem A a B prichádza aj prenos zprava, Cin. A na to potrebujem plnú sčítačku (full adder). Má tri vstupy: A, B, Cin. A dva výstupy: S a Cout.
Najjednoduchšie je predstaviť si plnú sčítačku ako kombináciu viacerých logických operácií. V mojom prípade som však nepoužil samostatné XOR, AND ani OR hradlá. Celý full adder som postavil iba z NAND hradiel.
Ako už vieme pomocou NAND hradiel sa dajú vytvoriť všetky potrebné logické operácie vrátane XOR, AND a OR. Z nich potom poskladáme samotnú plnú sčítačku, ktorá má tri vstupy A, B a Cin a dva výstupy S a Cout.
Logicky musí výsledok spĺňať:
S = A XOR B XOR Cin
Cout = (A AND B) OR (Cin AND (A XOR B))
Tieto vzorce teda opisujú, čo má full adder robiť. V mojom zapojení sú však všetky tieto operácie realizované výhradne pomocou NAND hradiel.
Cout je v podstate väčšina. Ak aspoň dve z troch jednotiek na vstupe svietia, prenos ide ďalej. Preto sa tejto funkcii niekedy hovorí aj majority. Súčet je zase parita: či je počet jednotiek na vstupe nepárny.
| A | B | Cin | S | Cout | Význam |
| 0 | 0 | 0 | 0 | 0 | 0 + 0 + 0 = 0 |
| 0 | 0 | 1 | 1 | 0 | 0 + 0 + 1 = 1 |
| 0 | 1 | 0 | 1 | 0 | 0 + 1 + 0 = 1 |
| 0 | 1 | 1 | 0 | 1 | 0 + 1 + 1 = 2 |
| 1 | 0 | 0 | 1 | 0 | 1 + 0 + 0 = 1 |
| 1 | 0 | 1 | 0 | 1 | 1 + 0 + 1 = 2 |
| 1 | 1 | 0 | 0 | 1 | 1 + 1 + 0 = 2 |
| 1 | 1 | 1 | 1 | 1 | 1 + 1 + 1 = 3 |
Tabuľka 3: Pravdivostná tabuľka plnej sčítačky. Súčet 2 sa zapisuje ako S = 0, Cout = 1. Súčet 3 ako S = 1, Cout = 1.

1 bitový full adder. V reálnom zapojení nebudem používať odpory na bázach tranzistorov, tam použijem iba na vstupoch sčítačky A, B a na výstupoch NAND hradiel.
Osem full adderov za sebou
Keď mám jednu plnú sčítačku, 8-bitová sčítačka je už „len“ otázka opakovania. Vezmem osem full adderov a zreťazím ich. Výstupný Cout z bitu 0 ide ako Cin do bitu 1. Cout z bitu 1 ide do bitu 2. A tak ďalej až po bit 7. Najnižší Cin nastavím na 0, keď chcem čisté sčítanie. Takéto zapojenie sa volá ripple-carry adder, teda sčítačka s pretekajúcim prenosom.

Tabuľka: 8-bitová sčítačka
Slovo ripple, česky a slovensky „prelievanie“, je presné. Prenos sa doslova preleje zprava doľava. Kým sa ustáli najvyšší bit, musí počkať na všetkých susedov. V reálnom procesore to pri veľkých šírkach vadí, a preto existujú rýchlejšie sčítačky s predvídaním prenosu. Na breadboarde, kde som sčítaval rukou a očami, mi ripple carry vyhovoval. Bol pomalý, ale čitateľný. Videl som, ako sa LED diódy zapaľujú ako dominové kocky.

https://www.falstad.com/s.php?s=GtlCy8
Čo znamená 8 bitov?
Pre 8 bitov to znamená rozsah 0 až 255, ak čísla beriem ako nezáporné. 200 + 100 už do ôsmich bitov nezmestím. Súčet 300 je binárne 1 0010 1100, čiže na ôsmich LED diódach ostane 00101100 (44) a na Cout7 ostane jednotka. Tá jednotka nie je ozdoba. Je to správa: „výsledok je väčší, než sa zmestí.“ V procesore z toho vzniká príznak carry, prípadne overflow. Na mojom stole z toho vznikla ešte jedna LED (dáme jej žltú farbu).
7. Srdce výpočtov: ALU

Keď som si ukázal, ako si počítač v tichosti prehadzuje nuly a jednotky, prišiel čas pozrieť sa na miesto, kde sa táto binárna alchýmia mení na reálnu prácu. Tým miestom je ALU, aritmeticko-logická jednotka (z angl. Arithmetic Logic Unit).
Ak by som procesor prirovnal k celému podniku, ALU je jeho hlavná dielňa. Je to svalová hmota čipu, kde sa odohráva všetka skutočná drevina výpočtov. Kým ostatné časti procesora dáta len prenášajú, ukladajú alebo ťahajú z pamäte, ALU je tá jednotka, ktorá do toho buchne a povie: „Poďme počítať.“
Vo svete moderných procesorov dokáže ALU urobiť obrovské množstvo operácií. Základné sčítanie a odčítanie, posuny, násobenie, delenie, logické AND, OR, XOR aj porovnávanie veľkostí čísel. V mojom projekte som si život zámerne nekomplikoval. Zužil som to na sčítanie a na jeho šikovné rozšírenie na odčítanie. Keď totiž pochopíte, ako ALU dokáže fyzicky sčítať dve čísla pomocou hradiel, pochopili ste základnú filozofiu, na ktorej stojí každý procesor.
Dôležité je aj to, čo ALU nie je. Nie je pamäť. Nie je to program. Nie je to ani ten, kto rozhoduje, či sa má práve sčítať, alebo odčítať. ALU je nástroj. Niekto iný jej musí podstrčiť správne vstupy a povedať, akú operáciu má vykonať. Tým „niekým“ je radič.
8. Kto riadi, čo sa bude počítať? Radič a inštrukčný dekodér
Mať skvelú dielňu je fajn, ale sama o sebe nič nevyrieši. Predstavme si špičkovú kalkulačku, na ktorej nikto nestláča tlačidlá. V procesore je to rovnaké. Hromada súčiastok by bez dozoru len tak stála a nič by nerobila. O to, aby všetko fungovalo v správny čas a na správnom mieste, sa stará radič (control unit) a inštrukčný dekodér.
V mojej 8-bitovej sčítačke som samozrejme nemal celý procesor. Nemal som program v pamäti, ani frontu inštrukcií. Mal som DIP switche, vodiče a neskôr jeden riadiaci signál, ktorým som prepínal sčítanie a odčítanie. Aj to stačilo na to, aby som pochopil deľbu práce. ALU počíta. Radič rozhoduje.
Zbernice a multiplexery
Celý procesor je prepletený sieťou vodičov, ktorej hovoríme zbernica). Je to hlavná cesta, po ktorej prúdia dáta sem a tam. Aby sa mi na vstup sčítačky neprimiešali náhodné čísla z celého systému, používa sa elektronická výhybka: multiplexer (MUX).
Predstavujem si ho ako inteligentnú výhybku na železnici:
- Radič povie: otvor cestu, pusť dáta z klávesnice na vstup A sčítačky.
- V tej istej chvíli prepne druhú výhybku, aby druhé číslo z pamäte RAM dorazilo na vstup B.
- Vďaka týmto prepínačom dáta vždy vedia, kam majú odbočiť.

Ešte raz v skratke: Control Unit načíta inštrukciu z pamäte a preloží ju, aby zistila, že má vykonať sčítanie $a + b$. Riadiaca jednotka pošle do ALU a MUXu špecifické riadiace signály (kontrolné bity) pre operáciu sčítania. Vnútri ALU prejdú vstupy $a$ a $b$ cez sčítačku (adder), ktorá vygeneruje výsledok súčtu. (Multiplexor) na základe signálu z Control Unit prepne svoj vstup na výstup sčítačky, čím ignoruje výsledky iných operácií (napr. odčítania či logických hradiel). Finálna spočítaná hodnota opustí ALU a uloží sa do cieľového registra alebo pamäte.
Na breadboarde som túto úlohu robil rukami. Káblik som prestrčil tam, kam som chcel. V čipe to isté robí napätie na riadiacich vodičoch. Princíp je rovnaký. Len ja som bol pomalší.
Radič a dekodér sú teda mozog, ktorý v reálnom čase hýbe neviditeľnými páčkami vo vnútri procesora. Ja som si neskôr ten istý signál spravil DIP switchom s nápisom ADD/SUB na sčítanie a odčítanie. Nebolo to pekné ako v čipe, ale bolo to čitateľné.
9. Magický trik: ako som tou istou sčítačkou aj odčítal
Odčítanie vyzerá ako druhá operácia. V kremíku často nie je. Je to sčítanie v prestrojení. Trik sa volá dvojkový doplnok (two’s complement). Namiesto A − B počítam:
A − B = A + (!B) + 1
Najprv všetky bity čísla B otočím naruby. Z 0 sa stane 1, z 1 sa stane 0. To je jedničkový doplnok. Potom pripočítam ešte 1. To je dvojkový doplnok. A nakoniec to celé pripočítam k A. Znie to ako obchádzka. Je to obchádzka, ktorá šetrí celú odčítaciu jednotku.
XOR hradlá ako riadená negácia

Na breadboarde som to spravil tak, ako to robia aj skutočné ALU. Pred každý bit vstupu B som dal XOR hradlo. Druhý vstup všetkých tých XOR-ov som zviazal do jedného vodiča SUB a pripojil na Cin nultej sčítačky:
- Keď SUB = 0, XOR nič nemení. B ide do sčítačky ako B. Cin0 nechám 0. Obvod sčíta.
- Keď SUB = 1, XOR každý bit B zneguje. Zároveň Cin0 nastavím na 1, čím pripočítam tú povinnú jednotku. Obvod odčíta.
Jeden DIP switch teda zmenil celú sčítačku na odčítacku. Presne ten signál, o ktorom som písal pri radiči. Len namiesto inštrukčného dekodéra som tam bol ja a palec.
Príklad, ktorý som si púšťal do omrzenia: 21 − 7. Dvadsaťjeden je 00010101, sedem je 00000111. Negácia sedmičky je 11111000, po pripočítaní 1 dostaneme 11111001, čo je −7 v ôsmich bitoch. Keď túto hodnotu pripočítame k 21, vznikne 00001110, teda 14. Keď to na LED diódach sedelo, mal som pocit, že som procesoru nahliadol pod kapotu.

Čo hovorí posledný prenos
LED na Cout7 prestala byť len „deviaty bit“. Pri sčítaní a odčítaní hovorí inú vetu.
- Pri sčítaní nezáporných čísel: Cout = 1 znamená, že súčet je väčší ako 255. Výsledok na ôsmich bitoch je orezaný. Toto je klasický carry / integer overflow v unsigned aritmetike.
- Pri implementácii unsigned odčítania pomocou A + (~B) + 1 možno finálny carry interpretovať ako indikáciu, že nedošlo k borrow. Pri A ≥ B bude výsledný Cout 1; pri A < B bude 0. Cout = 0 znamená, že A bolo menšie ako B a výsledok treba čítať ako záporné číslo v doplnkovom kóde.
Signed overflow, teda pretečenie so znamienkom, je ešte o čosi iné. Nastane napríklad vtedy, keď sčítam dve kladné čísla a výsledok vyjde záporný, lebo preliezol do znamienkového bitu. Deteguje sa XOR-om prenosu do najvyššieho bitu a prenosu z neho von. Na mojej doske som to mal ako samostatnú LED, kým som sa v tom nezamotal. Nakoniec som si nechal viditeľný hlavne Cout7 a znamienkový bit S7. Menej svetiel, viac porozumenia.

Ben Eater vo svojom videu o 8-bitovej ALU ukazuje ten istý trik s XOR a carry-in. Keď som to videl, mal som napoly radosť a napoly smútok. Radosť, že som na to neprišiel náhodou. Smútok, že som na to prichádzal tri večery s vodičmi v zuboch, kým som si to video pustil ešte raz.
Signalizácia pretečenia, sčítačka nevie počítať vyššie ako 255.
10. Fyzická realizácia: breadboard, DIP switche a LED diódy
Teória je trpezlivá. Breadboard nie. Keď som mal na papieri aj v simulátore plnú sčítačku, začal som to stavať nasucho. Najprv jeden bit. Potom štyri. Až potom všetkých osem. Kto začne ôsmimi bitmi naraz, hľadá jednu chybu v stovke vodičov. Ja som to skúsil. Potom som to rozobral a začal znova po jednom bite.
Čo som vlastne zapojil
Hardvérový setup som si držal zámerne jednoduchý, aby som pri pohľade na dosku ešte rozumel, čo vidím:
- Vstupy: dva 8-bitové DIP switche. Jeden pre číslo A, druhý pre číslo B. Páčka dole nula, hore jednotka. Alebo naopak, podľa nálady a podľa toho, ako som si to v daný večer zapojil.
- Výstupy: 9 LED diód. Osem pre výstup, jedna ore Cout7.
- Prenos: to je ta jedna LED na Cout7. Bez nej by som pretečenie prehliadol.
- Napájanie: 5 V, spoločná zem.
- Logika: tranzistory NPN ako základ, doplnené XOR pred vstup B 74HC68
- Vizualizácia: 3x doplnené shift registre 74HC165 (2x pre vstup a 1x pre výstup), LED display 20×4
- arduino uno pre preklad bitov na LCD
- kopu breadboardov a prepojovacích vodičov, milión odporov 220, 1k a 10k



Simulátor vs. realita
Pred fyzickým zapojením som si celý reťazec overoval v simulátore. Používal som Falstad Circuit Simulator. Simulátor je v tomto milosrdný. Ukáže mi, čo sa deje s logickými signálmi, bez toho, aby som musel fyzicky zapojiť stovky vodičov. Keď simulácia ukazovala: 21 + 7 = 28 a breadboard ukazoval niečo iné, vedel som, že matematika pravdepodobne nie je problém. Problém bude niekde v mojom zapojení.
Breadboard však prináša veci, ktoré simulácia často neukáže tak bolestivo:
- zlé kontakty,
- dlhé vodiče,
- napájacie lišty,
- rušenie,
- zaťaženie výstupov,
- floating vstupy,
- chýbajúce rezistory,
- chýbajúce blokovanie napájania.
Falstad mi teda neušetril premýšľanie. Ušetril mi však množstvo zbytočného hľadania.
Pull-down rezistory: vstup nesmie plávať
Pri DIP switchoch som narazil na ďalšiu drobnosť, ktorá vyzerá banálne, ale v reálnom obvode vie narobiť poriadny chaos. Keď je prepínač otvorený, vstup logického obvodu nemôže jednoducho zostať nezapojený. Takýto stav sa nazýva floating input. Vstup potom nemá jednoznačne definovanú logickú úroveň a môže vplyvom rušenia alebo okolitých signálov prechádzať medzi LOW a HIGH. Preto som použil pull-down rezistory.
Jednoduché zapojenie:

Keď je switch zopnutý, vstup dostane HIGH. Keď je otvorený, 10 kΩ rezistor ho stiahne na GND a vstup má definovaný LOW stav. Alternatívou je pull-up rezistor. Vtedy rezistor drží vstup v HIGH a prepínač ho po zopnutí stiahne na GND.
Toto bola jedna z tých vecí, ktoré človek ľahko preskočí, keď kreslí schému na papieri. Na breadboarde už nie. Digitálny obvod pozná iba nulu a jednotku. Musíme mu zabezpečiť, aby naozaj jednu z nich dostal.
Blokovacie kondenzátory: malá súčiastka, veľký pokoj
Na papieri bol obvod správny. V simulátore tiež. Breadboard však prináša ešte jeden svet, na ktorý sa pri kreslení logických hradiel ľahko zabudne:
napájanie, kontakty, rušenie a zem.
Pri 74HC obvodoch som preto ku každému čipu použil 100 nF keramický kondenzátor medzi VCC a GND, umiestnený čo najbližšie k napájacím pinom.
Pri prepínaní logických obvodov vznikajú krátke prúdové impulzy. Kondenzátor pomáha lokálne stabilizovať napájanie a obmedziť rýchle zmeny napätia na napájacej vetve.
Pri väčšom množstve čipov, LED diód, dlhších vodičov a breadboarde sa aj malý problém s napájaním môže prejaviť ako úplne nezmyselná chyba logiky. A potom človek pol hodiny hľadá pokazený XOR, pričom problém je v skutočnosti pár centimetrov ďalej na napájacej lište.
74HC.. + veľa LED + dlhé vodiče + breadboard + odpory = bolesť hlavy
Ako som to testoval
Testovací rituál som si spravil krátky:
- Vynulovať oba switche. Všetky LED na súčte musia zhasnúť. Cout tiež.
- Nastaviť A = 1, B = 0. Musí svietiť len najnižší bit súčtu.
- Nastaviť A = 1, B = 1. Súčet 0, prenos do ďalšieho bitu. Ak nesvieti bit 1, half adder na LSB je zlý.
- Nastaviť 21 a 7, teda A = 00010101 a B = 00000111. Musí vyjsť 00011100.
- Nastaviť 255 + 1. Súčet 00000000, Cout = 1. Ak toto nesedí, reťazenie je zlé.
Najkrajší moment nebol, keď to začalo sedieť. Najkrajší moment bol, keď som prvýkrát videl, ako sa prenos preleje cez tri bity a LED diódy sa rozsvietia v poradí, ktoré som mal na papieri. Matematika prestala byť tabuľka. Stala sa svetlom. A všetky rezistory sú skamarátené s breadboardom….




11. Vizualizácia na 7-segmentových displejoch a náraz do reality
Binárne LED diódy sú úprimné, ale po hodine na ne človek prestane vidieť. Chcel som desiatkové čísla. Také, aké poznám z kalkulačky alebo zobrazené vo formáte HEX. Preto som k súčtu pripojil klasickú kombináciu: BCD dekodér a 7-segmentový displej. Na simulátore to vyzeralo slušne.

Štandardný dekodér typu 74LS47 alebo CD4511 sa mi nepodarilo zohnať tak ma napadlo že sa napichnem na zbernicu a jednotlivé bity si preložim pomocou arduina.
12. Moderné riešenie: posuvné registre, Arduino a LCD

Arduino Uno síce má spolu 20 použiteľných GPIO (14 digitálnych + 6 analógových), ale vyčleniť ich všetky len na čítanie 24 bitov by bolo nepraktické. Potreboval som zúžiť 24 paralelných signálov do niekoľkých vodičov. Na to slúžia posuvné registre.
PISO (parallel-in, serial-out), napríklad 74HC165. Tri takéto čipy mi zoberú 24 bitov naraz, a potom ich po jednom bite pošlú do Arduina po spoločnej dátovej linke. K tomu clock a latch. Z 24 vodičov sú zrazu tri-štyri.



Arduino ako prekladateľ
Arduino v tomto zapojení nesčíta. Sčítanie ostalo na hradlách. Arduino len počúva, preloží bity na desiatkové čísla a vypíše ich. Keby Arduino sčítalo samo, projekt by stratil zmysel. Bola by to skica v C, nie sčítačka.
Firmware som nechal zámerne hlúpy. Načítať 24 bitov, rozsekať ich na A, B a Out, spočítať z nich desiatkovú hodnotu, vypísať na displej. Prípadne k tomu Cout a režim ADD/SUB. Žiadna korekcia, žiadne „ak to nesedí, prepíšem výsledok“. Keď hradlá spravili chybu, displej mal klamstvo ukázať.
LCD, na ktorom to konečne číta človek
Ako výstup som použil alfanumerický LCD, konkrétne panel typu DEM20486, teda 20 znakov na 4 riadky, kompatibilný s klasickým radičom Hitachi HD44780. Štyri riadky sú presne toľko, koľko som potreboval:
A = 21 00010101
B = 7 00000111
Rezim ADD/SUB
Out = 28 00011100
Použitý kód na preklad bitov:
#include <LiquidCrystal.h>
#include <stdio.h>
#include <string.h>
LiquidCrystal lcd(12, A1, 5, 4, 3, 2); // E na A1
const int LATCH_PIN = 8;
const int CLOCK_PIN = 9;
const int DATA_PIN = 7;
const int MODE_PIN = 6;
uint8_t lastA = 0xFF, lastB = 0xFF, lastOut = 0xFF;
bool lastSub = true;
bool lcdReady = false;
uint8_t readCustomShiftIn() {
uint8_t value = 0;
for (int i = 0; i < 8; ++i) {
value |= (uint8_t)(digitalRead(DATA_PIN) << (7 - i));
digitalWrite(CLOCK_PIN, HIGH);
delayMicroseconds(30);
digitalWrite(CLOCK_PIN, LOW);
delayMicroseconds(30);
}
return value;
}
void bin8(uint8_t val, char *out) {
for (int i = 0; i < 8; i++) {
out[i] = (val & (1 << (7 - i))) ? '1' : '0';
}
out[8] = '\0';
}
void printLine(uint8_t row, const char *text) {
char line[21];
memset(line, ' ', 20);
line[20] = '\0';
size_t n = strlen(text);
if (n > 20) n = 20;
memcpy(line, text, n);
lcd.setCursor(0, row);
lcd.print(line);
}
void drawAll(uint8_t a, uint8_t b, uint8_t out, bool isSub) {
char bits[9];
char buf[21];
bin8(a, bits);
snprintf(buf, sizeof(buf), "A:%3u [%s]", a, bits);
printLine(0, buf);
bin8(b, bits);
snprintf(buf, sizeof(buf), "B:%3u [%s]", b, bits);
printLine(1, buf);
printLine(2, isSub ? "REZIM: SUB (-)" : "REZIM: ADD (+)");
bin8(out, bits);
snprintf(buf, sizeof(buf), "OUT:%3u [%s]", out, bits);
printLine(3, buf);
}
void setup() {
pinMode(LATCH_PIN, OUTPUT);
pinMode(CLOCK_PIN, OUTPUT);
pinMode(DATA_PIN, INPUT);
pinMode(MODE_PIN, INPUT);
digitalWrite(CLOCK_PIN, LOW);
digitalWrite(LATCH_PIN, HIGH);
delay(300);
lcd.begin(20, 4);
delay(50);
lcd.begin(20, 4);
lcd.clear();
delay(50);
lcdReady = true;
}
void loop() {
digitalWrite(LATCH_PIN, LOW);
delayMicroseconds(20);
digitalWrite(LATCH_PIN, HIGH);
delayMicroseconds(50);
uint8_t inputA = readCustomShiftIn();
uint8_t inputB = readCustomShiftIn();
uint8_t result = readCustomShiftIn();
bool isSub = digitalRead(MODE_PIN);
delayMicroseconds(100);
bool changed = !lcdReady
|| inputA != lastA
|| inputB != lastB
|| result != lastOut
|| isSub != lastSub;
if (changed) {
drawAll(inputA, inputB, result, isSub);
lastA = inputA;
lastB = inputB;
lastOut = result;
lastSub = isSub;
lcdReady = true;
}
delay(80);
}
Naraz som videl desiatkový význam aj surové bity. Mohol som skontrolovať, či som na DIP switchi naozaj nastavil 21, a zároveň či súčet nie je len zhoda náhod. Keď som prepol SUB, na štvrtom riadku sa z ADD stalo SUB a čísla sa správali podľa dvojkového doplnku. V tej chvíli projekt prestal byť spleťou LED diód a začal byť nástroj, na ktorý sa dá pozerať dlhšie než tri sekundy.
13. Čo som si z toho odniesol
Keď sa dnes pozriem na ten breadboard, nevidím v ňom kalkulačku. Vidím zmenšený model otázky, s ktorou som začínal. Čo sa stane, keď stlačíme rovná sa? Stane sa toto. Dve čísla prídu ako napätia. Radič, v mojom prípade DIP switch, povie, či sa majú sčítať, alebo odčítať. XOR prípadne otočí druhé číslo. Rad full adderov preleje prenos z bitu na bit. Na konci svieti osem výsledkov a jeden prenos navyše. V procesore je toho omnoho viac: cache, predikcia skokov, pipelining, miliardy tranzistorov. Nakoniec sčítanie ADD… nepripomína vám to niečo? Áno, presne tak, je to inštrukcia ADD v assembleri, ktorá sčíta dve hodnoty uložené v registroch. Ale úplne na dne, pod všetkými tými vrstvami, stále sedí niečo veľmi podobné mojej sčítačke.

Rýchly náčrt
Použité odkazy a ďalšie čítanie
Do článku som odkazy vkladal priebežne. Tu ich dávam ešte raz pohromade, v poradí, v akom som sa k nim v projekte vracal. Nie je to akademický zoznam literatúry. Je to zoznam miest, kam som naozaj chodil, keď mi niečo nehralo.
- Binárna sústava (Wikipedia SK)
- Logické úrovne / logic levels (Wikipedia)
- Aritmeticko-logická jednotka (Wikipedia SK)
- Arithmetic logic unit (Wikipedia EN)
- Radič / control unit (Wikipedia)
- Zbernica (Wikipedia SK))
- Multiplexer (Wikipedia SK)
- Tranzistor (Wikipedia SK)
- Claude Shannon: A Symbolic Analysis of Relay and Switching Circuits
- Logické hradlo (Wikipedia SK)
- NAND logic (Wikipedia)
- Adder: half adder, full adder, ripple-carry (Wikipedia))
- Dvojkový doplnok (Wikipedia SK)
- Integer overflow (Wikipedia)
- Seven-segment display (Wikipedia)
- Binary-coded decimal (Wikipedia)
- Double dabble, prevod binárneho čísla na BCD (Wikipedia)
- Shift register (Wikipedia)
- SN74HC165, PISO posuvný register (Texas Instruments)
- Hitachi HD44780 LCD controller (Wikipedia)
- Arduino dokumentácia
- Falstad Circuit Simulator
- Ben Eater: 8-bit breadboard computer
- Ben Eater: ALU video
- Nand2Tetris
Ak by som mal z tohto zoznamu niekomu odporučiť len tri veci, boli by to tieto: Falstad na vyskúšanie jedného full adderu, Ben Eater a jeho náučné videá sú fakt super na pochopenie, a vlastný breadboard na zistenie, že zmysel nestačí, kým nie sú na mieste aj rezistory.
arduino simulácia: https://wokwi.com
Galéria:





