# Principy počítačů - https://slama.dev/poznamky/principy-pocitacu/ - písemná zkouška, 10 otázek, každá za jeden bod, potřebujeme polovinu na úspěšné složení zkoušky, časový limit 4 hodiny, zkouší se s toho, co se probere na přednáškách, dostaneme ukázku (loňskou písemku) - self-assessment úlohy – dostaneme ke každé přednášce sadu - za nějaké odevzdané úlohy můžeme dostat desetinu bodu ke zkoušce, až něco přes dva body budeme moci získat, týdenní deadliny - hodnocení úloh bude až dodatečně, pokud bychom ty body potřebovali - zadávání a odevzdávání úloh do MS Teams - videozáznamy nám pošle - důležité je pochopit, proč věci fungují tak, jak fungují – nemusíme se učit všechno nazpaměť, ale musíme umět termíny - nemusíme se hlásit, když se na něco budeme chtít zeptat ## 1. přednáška - Harvardská architektura počítače - CPU – procesor, vykonává příkazy - kódová paměť (code memory) – uložení informací o příkazech - komunikační linka – umožňuje, aby procesor četl data z paměti - v základním počítači CPU nemusí zapisovat do kódové paměti, do ní se zapisuje nějak z venku - datová paměť (data memory) – CPU z ní čte a zapisuje do ní data - data se ukládají do proměnných - k procesoru jsou dále připojena vstupně-výstupní zařízení – I/O, periferie - matematik Charles Babbage vymyslel koncept mechanického počítače – Analytical Engine (v roce 1837), byl plně programovatelný, Turing complete - jeho přítelkyně Ada Lovelace napsala manuál k tomuto počítači - vydala publikaci, kde vyslovila myšlenku kódování libovolných dat (textů a multimédií) pomocí čísel - budeme se zabývat tím, jak v počítači reprezentovat čísla (všechna ostatní data na ně můžeme převést) - informace (data) → čísla → celá čísla → nezáporná celá čísla - zaznamenáme libovolné číslo od nuly do milionu - nula je 0 V, miliion je 5 V, všechno ostatní mezi tím - problém je při vysílání, každý vodič má odpor - změna odporu při teplotě - kvůli vlastnostem vodičů vzniká elektromagnetický šum - analogový přenos - posledním zjednodušením je přenášení čísel nula/jedna - této číslici budeme říkat bit (binary digit), b - stanovíme hranici napětí, všechny hodnoty nad ní budeme interpretovat jako jedničku, hodnoty pod ní jako nulu - digitální přenos – přenos číslic ![timing-diagram](přílohy/timing%20diagram.png) - sériový digitální přenos - záleží na pořadí číslic – přijímající a vysílající se musí dohodnout - označíme si bit s nejnižší váhou – Least Significant bit (LSb) - bitu s nejvyšší váhou budeme říkat Most Significant bit (MSb) - stanovíme bit order – MSb-first nebo LSb-first - mocniny dvojky - 16 = 2^4 - 256 = 2^8 - 1024 = 2^10 - 4096 = 2^12 - 65536 = 2^16 - cca 10^6 = 2^20 - cca 16 000 000 = 2^24 - cca 4 200 000 000 = 2^32 ![](přílohy/obvod.png) ![](přílohy/diferenciální%20přenos.png) - diferenciální přenos - data 1 – data 2 - \>0 = 1 - \<0 = 0 - řešení problému se dvěma jedničkama / dlouhou jedničkou - pevná délka bitu - definuje se přenosová rychlost - v bitech za sekundu (bits per second, bps) - jednotka baud \[bód\] (symbol za sekundu) – obvykle budeme uvažovat x baud = x bps, ale jeden symbol může obsahovat více bitů ## 2. přednáška - vodiče - klasický způsob přenosu (není diferenciální) – data a GND - diferenciální – data+, data– - přijímač se na signál kouká přibližně v polovině bitů - přenosová rychlost zajišťuje intervaly čtení, je ale nutné zajistit začátek čtení (synchronizaci hodin, "tikání") - musíme si odlišit stav, kdy se nic nepřenáší, od začátku přenosu - **idle stav** – nic nepřenášíme - floating stav / stav s vysokou impedancí / Hi-Z = stav, kdy je obvod rozpojený, ale vodič indukuje náhodnou hodnotu - 3-stavová logika – funguje na lince, kde umíme rozlišit floating stav, nulu a jedničku - floating stav bychom mohli požadovat za idle stav - my ale chceme fungovat na 2-stavové logice (lince) - můžeme definovat idle stav jako nulu - začátek přenosu označíme pomocí start condition – rising edge (rostoucí hrana) - definujeme si, že na začátku přenosu bude start bit (nebo nějaký určitý počet start bitů) - potom začíná přenos užitečných bitů (datových bitů / data bits) - data bits se do obrázku značí podobně jako diferenciální přenos, ale znamenají něco jiného (jde o obecné značení bitů, jaké je možné posílat) - může se stát, že se nám vysílání a příjem bitů posune - proto definujeme maximální délku přenosu – max X → const X (definujeme konstatní maximální délku) - N bitů celkem rozdělíme po X bitech - N/X = Y přenosů - výrobci se shodli, že se přenos bude uskutečňovat po 8 bitech - 8 bitů = 1 byte (B) - 8 bitů = 1 octet (existuje několik málo zařízení, která mají jinou velikost bytu, proto je obecně správnější používat označení octet) - po X bitech (obvykle osmi, ale může být i více bytů) – stop condition (falling edge, klesající hrana), stop bity, idle stav, start condition, start bity, ... - takhle navržená linka přenáší 20 % času technická data (8 data bits, 1 start bit, 1 stop bit) – 20% overhead - přenosová rychlost bps (bits per second) – počítají se data bits - synchronizaci je možné řešit i pomocí hodinového signálu (clock) – linka vysílající střídavě nuly a jedničky, jednička značí čas čtení (zajišťuje synchronizaci přijímače a vysílače) - vodiče - data, GND, clock - diferenciální – data1, data2, clock, GND, (clock1, clock2) (?) - přenosová rychlost by mohla být definovaná rychlostí tikání hodinového signálu - hodinový signál může generovat vysílající – určité nevýhody - hodinový signál může generovat centrální oscilátor - cyklus (cycle/takt) hodinového signálu definuje přenosovou rychlost - lépe se detekují hrany signálu – můžeme si definovat, že rostoucí hrany hodinového signálu definují momenty čtení - abychom zrychlili přenos, můžeme používat obě hrany hodinového signálu (rostoucí i klesající) – označení DDR (double data rate) - co když je hodinový vodič kratší než datový vodič? - můžeme se vykašlat na hodiny a synchronizovat se jiným způsobem – vždy jen v určitých (delších) intervalech - mohli bychom se synchronizovat pomocí hran, ale museli bychom mít jistotu, že se v datech dostatečně často střídají jedničky a nuly – to ale nemusí vždy platit - na každých osm bitů bychom mohli poslat 10 bitů - ke každé kombinaci osmi bitů bychom mohli namapovat kombinaci 10 bitů, které jsou dostatečně "hezké" – dostatečně často se tam střídají jedničky a nuly - přijímač i vysílač má mapovací tabulku - tento způsob synchronizace se nazývá clock recovery, používá se např. v USB - vodiče v USB: 5 V, GND (tyto dva slouží k napájení připojeného zařízení), data+, data– (tyto dva zajišťují přenos dat) - zbylé dva způsoby synchronizace přenosu používají linky I²C (pomocí hodinového signálu) a RS-232 (pomocí start a stop bitů) - linky simplex a duplex - přenos jedním směrem – simplex - přenos oběma směry – duplex - half-duplex – strany se musejí domlouvat, kdo zrovna posílá - full-duplex – nezávisle data přenášíme oběma směry → řešení pomocí dvou zcela nezávislých simplexních linek - např. RS-232 - Rx – přijímající vodič (receiver) - Tx – vysílající vodič (transmitter) - dále se definují out-of-band signály - přenášejí se tam informace nezávisle - obvykle přenášejí konstatní nulu nebo jedničku – signál platí/neplatí - běžné kódování – 0 = nepravda, 1 = pravda - power-out signál - někdy dává smysl to definovat obráceně – 0 = platí, 1 = neplatí → inverzní logika - obvyklá značení inverzní logiky na signálu SIG: SIG (s čárou nad textem), \#SIG, /SIG, !SIG, SIG (bílé písmo na černém pozadí) - hodiny reálného času – RTC - chceme, aby nám zařízení poslalo tři informace – den, měsíc a rok - třeba 9 bitů na den, 5 bitů na měsíc, 7 bitů na rok - musíme si definovat, jak bude která informace dlouhá - komunikační protokol/formát - jeden logický blok dat = packet (tento packet by měl 21 bitů) - musíme se dohodnout na MSb-first / LSb-first - délka packetu nemusí být pevná, délka packetu může být definovaná uvnitř packetu - řadič (controller) – zařízení, které zajišťuje ovládání linky (procesor → linka → řadič → linka → myš) - uvnitř je registr daného zařízení – data register - komunikace s řadičem z programu – musím mu říct, jak má interpretovat změny na datovém vodiči, který jde z myši - pomocí pyserial → serial → Serial - nastavení řadiče (config register) - status register – ukládá informaci, v jakém stavu je datový registr (např. 0 = no change, 1 = new byte in data register) - operace přečtení data registru zaznamená do status registru nulu - funkce, které komunikují se zařízeními, mají často nějaký timeout, aby čekání na data nebylo nekonečné ## 3. přednáška - řadič řeší komunikaci programu s myší a překlad ze sedmibitových na osmibitové bajty - sériovou myš také potřebujeme nějak napájet - běžně v USB konektoru jsou 4 piny, z toho dvoje data, zem a napájení - kvůli kompatibilitě se sériová myš připojovala pomocí RS-232 linky - RS-232 nemá napájecí konektor, ale pouze out of band signály - sériová myš je tedy napájená pomocí out of band signálů RTS a DTR nastavených na hodnotu 1 - v řadiči je control register (modem control register) – pro každý out of band signál je tam jeden bit, který má hodnotu 0 (false) nebo 1 (true) - jak resetovat myš? stačí nastavit signály RTS a DTR na nulu → myš se po chvíli vypne → můžeme myš opět zapnout - (nemusíme si pamatovat, že to jsou zrovna RTS a DTR) - po zapnutí myš pošle inicializační packet (init packet) – není přesně definován - po zapnutí myši tedy čekáme na X (třeba 1024) bajtů - čekáme pomocí funkce .read(n), tato funkce je ale blokující - ideální by byla neblokující funkce - řešením je nastavení timeoutu - potřebujeme být schopni stisknout klávesu na klávesnici a začít dělat něco jiného - input() – blokující funkce - keyboard.is_pressed('\') → True/False – neblokující funkce - přijímání dat z myši - bity jsou zprava doleva seřazeny 0–7 (podle zápisu čísla ve dvojkové soustavě) - myš posílá 7 bitů, takže MSb je pro ni bit č. 7 - stisknutí levého tlačítka → packet 96 0 0 0 - 96 = 64 + 32 = 2^6 + 2^5 → 01 10 00 00 (01 LR YY XX) - co dělat s informací 738201600 - šestnáctková/hexadecimální/hexa/hex soustava - značení čísla v šestnáctkové soustavě: $23, 23h, 0x23, $23_{16}$, $23_{hex}$ - značení čísla v desítkové soustavě: $23_{10}, 23_{dec}$ - pro uložení jedné číslice v šestnáctkové soustavě využijeme 4 bity - 1 bajt zaberou dvě šestnáctkové číslice - nuly na začátku čísla = leading zeros - $738201600_{10} =$ $2C001000 → 2C 00 10 00 → nenulové bity jsou pouze na některých místech - bity 29, 27, 26 a 12 jsou jedna - čísla zadané v Pythonu v desítkové soustavě se ukládají ve dvojkové soustavě - proměnou lze uložit v šestnáctkové soustavě, Python ji opět uloží ve dvojkové soustavě → není rozdíl mezi 35 a 0x23 - funkce print(a) vezme dvojkovou proměnnou a převede ji na string - znaky stringu jsou uloženy pomocí osmibitových čísel - funkce hex(a) vrací zápis čísla v šestnáctkové soustavě - funkce format(a, '04X') doplní číslo o leading zeros na 4 číslice - modifikovaný kód - packet 60 00 00 00 → první byte 01 10 00 00 - proč má první byte v 6. bitu jedničku? - abychom ho poznali od ostatních tří bytů a nedošlo ke špatné synchronizaci snímání komunikace myši - bitové operace – obvykle dva argumenty (binární operace) - n-bitová operace (např. osmibitová – podle délky každého ze dvou vstupů a délky výstupu) - 8-bit operace – na vstupu dvě osmibitová čísla, na výstupu jedno osmibitové číslo - operace vždy vezme dva bity na stejné pozici, nějakým mechanismem je zkombinuje a výsledek uloží do bitu na téže pozici - operace or: 1010 | 1100 = 1110 - můžeme kombinovat hodnotu a příkaz – jednička v příkazu znamená natvrdo nastavit výsledek na jedna, nula v příkazu znamená zkopírovat hodnotu do výsledku - nastavení bitu (na jedna) se označuje jako set - operace and: 1010 & 1100 = 1000 - když je příkaz nula → nastav natvrdo nulu - když je příkaz jedna → zachovej hodnotu - vymazání bitu – clear (to 0) - bitová negace not ~ - ~ 1010 = 0101 - v Pythonu funguje jinak - operace xor (eor) - exkluzivní or - 1010 ^ 1100 = 0110 - selektivní flip (not) - když je jednička, převrať hodnotu - když je nula, zkopíruj hodnotu - jak zjistit, jestli je levé tlačítko stisknuté - použijeme bitovou masku - na ?? L? ?? ?? použijeme masku 00 10 00 00 a operaci and - dostaneme buď 00 00 00 00 → tlačítko není stisknuté, nebo 00 10 00 00 → tlačítko je stisknuté - B1 (byte 1) & 0x20 = 0x20 → levé tlačítko je stisknuté - pohyb myši - kvůli přesnosti chceme použít 8 bitů, v jednom bytu je ale jenom 6 volných míst (máme 7bitový byte a bit č. 6 určuje pořadí bytu) - informaci tedy rozdělíme 1. a 2. bytu - B1 & 0x03 - B2 & 0x3F - chceme ze dvou čísel 000000XX a 00XXXXXX dostat XXXXXXXX - použijeme magii a převedeme 000000XX → XX000000 - XX000000 | 00XXXXXX = XXXXXXXX ## 4. přednáška - potřebujeme magickou operaci, která nám umožní posunout bity - = bitové posuny (bitwise shifts) - posun doleva (shift left) – SHL (<<) - a << x → b - a – hodnota, se kterou chceme pracovat (n-bitové číslo) - b – výsledek operace (n-bitové číslo) - x – o kolik bitů se má posunout (celé číslo) - **posun k MSb!** - příklad - 4-bit 1101 (vlevo MSb, vpravo LSb) - SHL 1 → výsledek: 1010 - o jedničku úplně vlevo jsme přišli, vpravo přibyla nula - SHL 3 → výsledek: 1000 - SHL n → výsledek: 0000 - posun doprava (shift right) – SHR (>>) - a >> x → b - funguje podobně jako SHL, akorát opačně - posun k LSb - rotace doleva (rotate left) – ROL - 1101 ROL 3 → 1110 (vysunuté bity nerušíme, ale ve stejném pořadí zasuneme z druhé strany) - výsledkem ROL n je identita - rotace doprava – ROR - 1101 ROR 2 → 0111 - rotace Python nepodporuje - potřebujeme rozlišit posun myši nahoru a doleva → záporná čísla ve formě jedniček a nul - bezznaménková čísla (unsigned) - znaménková čísla (singed) - signed magnitude – 1 bit určuje znaménko, ostatní bity hodnotu čísla - z hlediska kompatibility je výhodné umístit znaménkový bit na místo MSb, přičemž 1 určuje záporné číslo, 0 kladné - při počítání pouze s nezápornými čísly ztrácíme polovinu rozsahu, takže se v takovém případě může hodit použít bezznaménková čísla - každý procesor podporuje operace pro bezznaménková čísla - můžeme libovolně přecházet mezi interpretací čísla jako znaménkového a bezznaménkového - nefunguje nám bezznaménkové porovnání na porovnávání záporných čísel (ani sčítání apod.) - jedničkový doplněk (ones' complement) - kladná čísla jsou zaznamenaná stejně jako unsigned - záporná jsou zaznamenaná znegovaně - jak udělat z kladného čísla záporné? - u signed magnitude pomocí operace XOR - u jedničkového doplňku negací - problém s nulou - máme dvě nuly – kladnou a zápornou - u jedničkového doplňku můžeme negovat a přičíst jedničku → dostaneme zpátky nulu - dvojkový doplněk (two's complement) - kladná čísla jako unsigned - záporná čísla jsou negace absolutní hodnoty plus 1 - rozsah –128 až 127 - nefunguje porovnání mezi kladnými a zápornými čísly – procesor musí podporovat znaménkové porovnání - MSb určuje znaménko - nejběžněji používaná implementace záporných čísel - Python ke každému číslu ukládá počet platných bitů, ukládá je jako znaménková čísla - jejich rozsah je prakticky neomezený - při posunech (<< a >>) nikdy nepřijdu o číslice – Python si čísla před operací zvětší odpovídajícím způsobem - funkce bit_length() vrací bitovou délku čísla (bez znaménkového bitu) - knihovna numpy nám umožní vyrábět proměnné pevně daných typů (uint8, uint16, int8, …) - čísla intX jsou znaménková, takže tam mj. funguje porovnání - funkce type(x) nám vrátí typ čísla - převod 8-bit čísla na 4-bit - operace truncation, přebytečné bity se zahodí – v podstatě $x \mod 2^n$ - u čísel blízko nuly funguje dobře, u vzdálenějších čísel získáváme modulo - převod 4-bit čísla na 8-bit - bezznaménkové rozšíření (zero extension) – na začátek se přidají čtyři nuly, nefunguje pro znaménková čísla - znaménkové rozšíření (signed extension) – rozkopíruje znaménkovou číslici do nových bitů, nefunguje pro bezznaménková čísla - v Pythonu se bezznaménkové rozšíření používá jenom při převodu mezi dvěma bezznaménkovými čísly, jinak se používá znaménkové rozšíření ## 5. přednáška - Harvardská architektura – CPU čte z kódové paměti, čte z datové paměti a zapisuje do datové paměti - datové paměti můžeme říkat operační paměť (operating memory) - periferie komunikují s CPU jednosměrně nebo oběma směry (monitor posílá informace o rozlišení, klávesnice přijímá informace o rozsvícení diod) - zařízení - master – řídí přenos (řídící – řídí komunikaci) - slave – poslouchá (řízený) - při komunikaci procesoru s pamětí je procesor master, paměť je slave - když data proudí směrem master → slave, tak jde o zápis, opačným směrem je to čtení - typický procesor funguje jenom jako master – abychom toto pravidlo neporušili, používáme řadič - řadič je potřeba u myši, u klávesnice tato potřeba obvykle není, protože se chová jako slave (uvnitř má vlastní registr) - komunikační linka point-to-point – z procesoru by muselo vést mnoho vstupů/výstupů - chceme komunikační linku, která umožňuje více vstupů/výstupů – multidrop/bus/sběrnice (linka se sběrnicovou topologií) - nákres – z CPU vedou dvě sběrnice, na jedné jsou připojené paměti, na druhé perfiferie (myš za řadičem), CPU je master, všechno ostatní slave - adresa (address) zařízení na sběrnici (typicky 0 až n) - v příkazu v programu pro procesor budou dvě informace – chci komunikovat se zařízením X na sběrnici Y - adresy zařízení musí být unikátní v rámci jedné sběrnice - rozsah adres (address space) - máme X bitový adresový prostor → platné adresy jsou $0$ až $2^x-1$ - někdy i master musí mít vlastní adresu? - zařízení je připojené na sběrnici - má Rx a Tx – může přijímat i vysílat data - je tam víc zařízení, zkusíme se obejít bez floating stavu - k lince připojíme 5 voltů přes rezistor s velkým odporem (pull-up rezistor, kdyby tam byla nula voltů, tak by to bylo pull-down rezistor) - když není žádné zařízení připojené k lince, tak je stav linky 1 (protože je tam těch pět voltů za rezistorem) - zařízení je připojené, ale nedělá nic → nepřipojí se ke sběrnici´→ stav linky je 1 - zařízení je připojené a vysílá jedničku → nepřipojí se ke sběrnici → stav linky je 1 - zařízení je připojené a vysílá nulu → připojí se (na malém rezistoru v zařízení na Tx je 0 V) → stav linky je 0 | D1 | D2 | bus | |---|---|---| | x | x | 1 | | x | 1 | 1 | | x | 0 | 0 | | 1 | 1 | 1 | | 1 | 0 | 0 | | 0 | 1 | 0 | | 0 | 0 | 0 | - spodní čtyři řádky implementují AND - $I^2C$ – Inter Integrated Circuit - vodič SDA – sériová data - vodič SCL – sériové hodiny - oba vodiče posílají digitální signál - oba vodiče jsou připojené na pull-up rezistor - napájecí napětí se označuje jako $V_{DD}$ nebo $V_{CC}$ - pod 30 % $V_{DD}$ se považuje za nulu, nad 70 % za jedničku - multimaster – různá zařízení můžou být master - existují i singlemaster sběrnice – např. USB - musíme rozeznat idle stav od přenosu - SCL tiká jenom během přenosu, generuje ho master - dvě jedničky (na SDA i SCL) znamenají idle stav - na lince existují nepovolené stavy – např. změna stavu na SDA při jedničce na SCL – toho využijeme jako START a STOP condition - START condition = sestupná hrana na SDA při jedničce na SCL - STOP condition = vzestupná hrana na SDA při jedničce na SCL - sběrnice má 9-bitové byty: 8 data bit + 1 control bit - kontrolní bit (acknowledgement/potvrzovací/ACK bit) - (acknowledgement = ACK × negative acknowledgement = NACK/NAK) - první byte vždycky posílá master, slave ho potvrzuje kontrolním bitem - další byty posílá vysílající a přijímající potvrzuje (pokud přijímající přestane potvrzovat, vyhodnotí se to jako NAK) | | B1 | a1 | B2 | a2 | B3 | a3 | | |---|---|---|---|---|---|---|---| | write | M | S | M | S | M | S | NAK | | read | M | S | S | M | S | M | NAK | - MSb-first komunikace - série bytů tvoří packet, ten se dělí na overhead ($I^2C$ control) a payload (device specific – požadovaná data) - $I^2C$ sestává ze slave address (7-bit) a bitu určujícího směr přenosu $R/\bar W$ - read = 1, write = 0 - devátý control bit má obrácenou logiku – 0 = ACK, 1 = NAK (typicky pokud tam slave není) - když slave nestíhá, tak může v hodinovém signálu generovat nulu → master ví, že nemůže posílat další data – tomu se říká clock stretching / hold clock low ### Ambient Light Sensor (ALS) - ve smartphonu určuje intenzitu okolního světla a podle toho se určuje intenzita podsvícení - v datasheetu najdeme informace o fungování - zařízení má čtyři piny – VDD (napájení), GND (zem), SDA (data), SCL (hodiny) - v zařízení bude senzor a logika - součástí logiky je counter register – zajišťuje počítání intenzity světla - měření v intervalech (na začátku měření se counter vynuluje) - příkazy start integration a stop integration - command register (cmd reg) - při extrémních hodnotách lze softwarově prodloužit/zkrátit dobu měření, abychom vůbec něco naměřili (to zajišťuje procesor zařízení) - counter register = ADC register (analog digital converter) - existuje také DAC (digital analog converter) – opačný proces, z digitálního signálu se generuje např. analogová intenzita světla - v ALS má 2 byty – z toho 15 datových bitů a jeden valid bit - připojení na sběrnici zajišťuje bus interface – skrze něj máme jako programátoři přístup k registrům - write-only register (W/O) - read-only register (R/O) - read-write register (R/W) – v ALS nenajdeme - v případě ALS bude „zápis“ znamenat zápis do W/O cmd registru a „čtení“ bude znamenat čtení z R/O counter registru - adresa zařízení na sběrnici je pevně daná výrobcem – hardwired/zadrátovaná, v tomto případě je to $29 – na jednu sběrnici tedy nemůžu připojit dvě stejná zařízení, protože by měla stejnou adresu - u vícebytových čísel se rozlišuje LSB (byte s LSb) a MSB (byte s MSb) - kromě bit order se určuje byte order ## 6. přednáška - nechceme pokaždé přenášet celý obsah paměti - každému bytu přiřadíme adresu (n-bit unsigned), definujeme si paměťový adresový prostor - u 256 bytové paměti budeme mít 8-bitový adresový prostor (0 až 255 $\dots 2^8-1$) - můžeme mít 200 bytovou paměť s 8-bitovým adresovým prostorem (podobně můžeme mít 256 bytovou paměť s 16-bitovým adresovým prostorem) - použití většího prostoru znamená možnost budoucího rozšiřování paměti - nechceme pracovat s velkými čísly – místo bajtů použijeme kilobajty - 1 kB = 1024 B, 1 MB = 1024 kB, … (pro přehlednost se používají zkratky KiB, MiB, GiB → kibibyte, …) - výrobci disků používají 1 kB = 1 000 B - pro uložení adresy bytu v KiB potřebujeme 10-bitovou adresu, pro adresování KiB v MiB také 10-bit, takže u GiB adresujeme konkrétní byte pomocí 30-bitové adresy - u adres bytů v KiB potřebujeme 10-bitovou adresu, ale binárně to vychází na 16-bit, takže takto můžeme adresovat 64kB médium - u 24-bitového prostoru 16 MB - u 32-bitového prostoru 4 GB - bity v registru řadiče: 1 bit → 1 latch (4–6 tranzistorů) - nejrychlejší způsob uložení do paměti - SRAM (Random Access Memory) - charakteristické vlastnosti 1. umožňuje volbu adresy 2. jednotná rychlost (uniform speed) - dnešní paměti RAM tohle většinou nemají - nejrychlejší přístup – sekvenční (postupný přístup k rostoucím adresám) - nejpomalejší – random (nelze předvídat, kam budeme přistupovat) - sekvenční přístup ke klesajícím adresám – záleží na konkrétní paměti - další vlastnost tohoto typu paměti je schopnost čtení a zápisu - typická vlastnost pamětí RAM – jsou volatile (po vypnutí napájení se ztrácí obsah) - kódová paměť počítače by tedy měla být non-volatile - kapacita – v jednotkách B, kB, MB - nevýhody – cena, rozměry - paměti DRAM - základní vlastnosti odpovídají SRAM - bit se ukládá pomocí 1 tranzistoru a 1 kondenzátoru - D v názvu znamená dynamic - nabité kondenzátory se postupně vybíjejí do vybitých - cca po milisekundě se náboje vyrovnávají - refresh paměti – součástka se podívá na náboje a obnovuje jejich původní hodnoty (v tuto chvíli do paměti nemůže nikdo přistupovat) - DRAM je tedy pomalejší než SRAM - přenosová rychlost – nejvíce ovlivňuje sekvenční přenosy, u SRAM 10 až 100 GB/s, u DRAM 1 až 10 GB/s - access time – u SRAM jednotky ns, u DRAM desítky ns - u naší 256 bytové paměti kódujeme adresu na I2C pomocí tří proměnlivých bitů - pevný začátek adresy, za něj se přidávají hodnoty tří bitů - 1 slovo (1 word) – jednotka přenosu/zpracování - je pro nás důležitá velikost slova - čím větší slovo, tím rychlejší přenos - n-bit device (paměť) - n-bit CPU (procesor umí pracovat s n-bitovými čísly) - adresa z pohledu CPU – adresa bajtu - u 16-bitové paměti tvoří dva bajty jedno slovo – používá adresy slov - podobně u 32-bitové paměti - adresy tedy musíme překládat - nesprávný význam slova: slovo = 16 bitů - dvojslovo (double word / DWORD / DW) – dvojnásobek slova (často 32 bitů) - čtyřslovo (quad word / QWORD / QW) – čtyřnásobek slova (v praxi často 64 bitů) - obsah naší paměti - bus interface – I2C sběrnice, tři připojené vodiče určují adresu paměti - adresový registr – velikost odpovídá velikosti adresového prostoru - ovládá logiku paměti - datový registr – velikost odpovídá velikosti slova - na I2C: 100 kHz → 100 000 b/s → 12 500 B/s - na jeden bajt se přenese 3×9 bitů - → 3 708 B/s - můžeme předpokládat, že po zapsání bytu budeme chtít zapsat na ten za ním, tedy adresový registr inkrementujeme o 1 - takhle dostaneme (u nekonečného přenosu) rychlost 11 109 B/s - 1 write tx (transakce) = 1 I2C tx - 1 read tx = 2 I2C tx (1 write do addr reg + 1 read z data reg) - obecně jsou ale typické paměti RAM rychlejší na čtení než zápis - registrový adresový prostor zařízení – když má zařízení více registrů, ke kterým chceme přistupovat ## 7. přednáška - Harvardská architektura - CPU - data memory – implementujeme pomocí RAM (y-bit) - code memory – sice problém s volatilitou, ale taky implemementujeme pomocí RAM (x-bit) - sběrnice s připojenými řadiči a zařízeními - packety pro komunikaci s paměťmi generuje procesor - instrukce procesoru - každý procesor má od výroby definovanou instrukční sadu (instruction set), kterou podporuje - jedna instrukce je posloupnost N bajtů v kódové paměti (délky se můžou, ale nemusí lišit – podle procesoru) - v paměti jsou uloženy za sebou, procesor je vykonává směrem k vyšším adresám - procesor si musí pamatovat, kterou instrukci právě vykonává - k tomu slouží registry procesoru - nejzákladnější registr obsahuje adresu instrukce, která se právě vykonává – obvykle se mu říká program counter (PC) nebo instruction pointer (IP; přičemž pointer = ukazatel = adresa) - vícebytová instrukce - instruction pointer ukazuje na base address (nejnižší adresa z toho rozsahu bytů) - dává smysl určovat u bajtů, jak jsou daleko od base address – říká se tomu offset (0 u bytu s base address, u dalších bytů 1, 2, 3, …) - po vykonání instrukce se k IP přičte délka instrukce - instrukce se obvykle skládá z několika částí - jednoznačný identifikátor instrukce – opcode (operační kód) - např. 105 = ADD (+), 106 = SUB (–) - zbytek tvoří argumenty instrukce - argumenty můžou být implicitní – např. přičti jedničku, je to napevno dané typem instrukce - IP je x-bitový, ukazuje do kódové paměti - proměnné (argumenty) u instrukcí jsou y-bitové, ukazují do datové paměti - posloupnosti instrukcí se říká strojový kód (machine code) - program v Pythonu - uložený jako text – posloupnost bytů (1 byte = 1 znak) - můžeme mít program – překladač (compiler), který jako vstup přijímá text pythonového programu a jako výstup generuje posloupnost bytů (strojový kód) - magicky přesuneme výsledek z data memory do code memory a zařídíme, aby ho procesor začal vykonávat - vytvořit překladač je těžké - může existovat také interpret (interpreter) - prochází text programu a zpracovává ho podle sady podmínek ve strojovém kódu - interpret se píše snáz než překladač - v programovacím jazyce je proměnná identifikovaná jménem, kdežto ve strojovém kódu adresou - překladač musí zařídit, aby proměnné alokoval na volných pozicích - jak do paměti uložit vícebytovou hodnotu - endianita (endianness) - viz Gulliverovy cesty - little endian (LE) – na nejnižší adresu ukládám LSB - pravidlo LLL (least significant byte, lowest address, little endian) - big endien (BE) – na nejnižší adresu ukládám MSB - je důležité ujasnit si endianitu – má ji danou procesor, dnes je nejběžnější LE (některé mobilní procesory jsou BE) - problém nastává, když použijeme externí zdroj dat – tam musíme endianitu řešit a případně přeházet pořadí bytů - po síti se data většinou posílají v BE pořadí - code memory by měla být non-volatile - nevýhody non-volatile pamětí - jsou pomalejší - mají omezený počet zápisů (opotřebovávají se) - → proto nemůžeme non-volatile paměť použít pro data memory - je těžké zařídit přemístění programu z data memory do code memory, interpretovat veškerý kód by bylo zase neoptimální → řešením je jiná architektura - von Neumannova architektura - operační paměť, kde je obojí – v jedné části kód programu, v jiné části data programu - zajistíme, aby IP obsahoval adresy z určitého rozsahu a aby adresy proměnných byly zase z jiného rozsahu - je to hardwarově komplikovanější na implementaci, ale přináší to spoustu výhod - lze zařídit, aby IP ukazoval na začátek přeloženého programu - potenciální zranitelnost, pokud útočník do dat určených ke čtení uloží spustitelné byty a zařídí jejich spuštění - operační paměť bude volatile – RAM - potřebujeme jiné magické zařízení, které do RAM zkopíruje počáteční program z non-volatile paměti - historie počítačů (prezentace) – všechny architektury jsou von Neumannovské - UNIVAC – drahý, pro velké firmy na počítání mezd (byl to sálový počítač, prodalo se jich cca 100) - Altair 8800 – první malý počítač, pro „matfyzáky“ - Bill Gates a Paul Allen napsali překladač Microsoft BASICu, aby Altair mohla používat širší veřejnost - Apple I – Steve Wozniak, skvělá architektura - Steve Jobs mu pomohl marketingově - někdo vytvořil aplikaci VisiCalc (počítání daní) – killer app - Atari – hraní her, připojovalo se k televizi, tyto počítače se dostaly do tehdejšího Československa přes železnou oponu - procesor 6502 (díky ukradení plánů na výrobu procesoru vznikaly československé kopie počítačů) - všechny procesory do té doby měly von Neumannovu architekturu, byly 8bitové a používaly 16bitový adresový prostor - 8bitový procesor umožňuje pracovat s 8bitovými čísly - IBM PC – procesor 8088 - procesor typu x86-16 - 16bitový procesor (uměl zpracovat dvě 16bitová čísla najednou) - 20bitový adresový prostor – zvládl adresovat 1 MB - 64 kB RAM - při zvýšení paměti (koupi nového počítače) se daly používat původní programy – díky tomuto triku se počítače ujaly - Intel – architektura x86 / IA-32 - 32-bit procesor, 32-bit adresový prostor → až 4 GB - 2 instrukční sady – jedna 16-bit, druhá 32-bit, dá se mezi nimi přepínat - AMD – architektura Intel 64 / x64 - 64-bit, 64-bit - 3 instrukční sady - základní instrukce – srovnání 6502 a x86 - instrukce skoku – nastavím IP na konkrétní hodnotu (nepodmíněný skok – unconditional jump) - podmíněný skok (conditional jump) – potřebujeme u *if* - řídící struktury (podmínky a cykly) se dají implementovat pomocí těchto dvou skoků - je těžké pamatovat si instrukce procesoru a psát přímo strojový kód → pro každý procesor se vymyslí tzv. assembler (assembly code) - je důležité chápat rozdíl mezi textovým zápisem assembleru a samotným strojovým kódem - při překladu je potřeba složité příkazy rozdělit do jednoduchých - procesory typicky vyžadují, aby maximálně jeden argument instrukce byl adresa, ostatní argumenty tedy musíme uložit do registru - registry procesoru - speciální registr (PC/IP) - obecné registry – tam uložíme proměnné, abychom je mohli použít jako argumenty instrukce - a = b + c - LOAD addr(b) → R1 - ADD R1 + addr(c) → R2 - STORE R2 → addr(a) - procesory s load/store architekturou jsou omezené tak, že všechny argumenty musí být v registrech (např. architektura MIPS) - dva typy LOAD - nahrání konstanty (immediate) – přímá hodnota jako součást instrukce - nahrání pomocí adresy - např. pro registr A jsou to instrukce LDA, STA - instrukce kopírování mezi registry (transfer) - např. kopírování X → A by se zapsalo jako TXA - kopírování hodnot mezi bajty v paměti – postupně LDA, STA (pro každý bajt dané hodnoty) ## 8. přednáška - registry - A, X, Y – pomocné registry pro účely programu (u 8-bit procesoru budou 8-bit) - PC – u 16-bit adresového prostoru bude 16-bit - P – příznakový registr (flags register) - příznak (flag) = 1 bit informace - typické příznaky - zero – byl výsledek poslední operace roven nule? (1 = ano, byla nula; 0 = ne, nebyla nula) - sign/negative – označuje znaménko výsledku poslední operace (1 = –, 0 = +), čísla se typicky zaznamenávají ve dvojkovém doplňku - carry – pokud potřebujeme u nějaké operace uložit jeden bit navíc - instrukce CLC (nastavuje na 0), SEC/STC (nastavuje na 1) - instrukce můžou mít side-effect – mění určité příznaky - ke čtení příznaků se typicky používají podmíněné skoky - dva typy registrové architektury - obecná registrová architektura … x86 - akumulátorová architektura … 6502 - akumulátor A, většina instrukcí umí pracovat jenom s tím akumulátorem - místo instrukce NOT se dá použít XOR \#\$FF (respektive EOR \#\$FF) - 8bitové sčítání - 8-bit vstup A - 8-bit vstup B - 1-bit vstup Cin (carry in) - 8-bit výstup R - 1-bit výstup Cout (carry out) - instrukce ADC (add with carry) - ke carry vstupu a výstupu používá carry příznak - před začátkem výpočtu je potřeba vynulovat carry příznak - odčítání - v 7-bit přesnosti pomocí negace a přičtení jedničky (viz dvojkový doplněk) - 8-bit rozdíl/subtract – subtract with borrow (SBB) – na x86 - subtract with carry (SBC) – na 6502 - chceme A – X – B - trik: A – X – B + 256 - borrow je negace carry - A – X – (1 – C) + 256 - A – X – 1 + C + 256 - A – X + C + 255 - A + (255 – X) + C - A + NOT(X) + C - $\alpha$ = NOT X - A + $\alpha$ + C - ADC $\alpha$ - registry x86 - 32-bit: EAX, EBX, ECX, EDX, ESI, EDI, EBP - 8bitové/16bitové „virtuální“ registry – např. AX, AH, AL - instrukce x86 - MOV na přesouvání - ADD (nepřičítá hodnotu carry, jako CLC + ADC) - SUB - výpočet $r=a+b+e-(c+d)$ - na 6502 můžu používat pouze akumulátor, k tomu musím ukládat mezi výpočty do paměti - na x86 si vystačím s registry ## 9. přednáška - taktovací frekvence (clock rate) – dnes v řádu GHz - 1 takt/cycle - nejrychlejší instrukce (fast) – procesor je stihne za jeden takt, všechny tyto operace pracují s hodnotami v registrech - bitové operace (AND, SHL, …) - ADC/SBB - pomalé operace (slow) – práce s pamětí - LOAD/STORE - operace s implicit load (např. ADC počítající s číslem z paměti) - pozn.: pokud sčítám 64-bit čísla na 8-bit procesoru, musím provést 8 operací sčítání + nějaké operace load a store - 6502 má cca 1 MHz - x86 cca 33 MHz - procesor má cache, která urychluje přístup k paměti - sign extension – při rozšíření čísla na víc bytů zachováváme jeho znaménko – u záporných čísel přidáváme jedničky, u kladných nuly - v Pythonu každé číslo zabírá 4 byty, protože počítače bývají 32-bit (a více) - v Pythonu ukládám pointer (ukazatel/reference) na objekt s hodnotou, typem, garbage collector ref countem, délkou… - garbage collector – udržuje si informaci o počtu odkazů na daný objekt, pokud je nula, tak objekt smaže - v jazycích C/C# může nastat aritmetické přetečení (arithmetic overflow) - uint8: 255 + 1 = 0 - int8: 127 + 1 = –128 - podtečení … při odčítání - procesory x86 a x64 mají operace násobení a dělení - násobení: 1–10 taktů - dělení: cca 50–100 taktů - u 6502 je potřeba SW implementace - shift left funguje jako násobení mocninou dvojky - $x\text{ SHL } n = (x \cdot 2^n) \mod 2^z$ - shift right funguje jako celočíselné dělení mocninou dvojky - arithmetic shift right – u záporných čísel doplňuje jedničky místo nul - programovací jazyky implementují různě, v Pythonu SHL + SAR, v C# SHL + SHR (uint) / SAR (int), v Javě SHL (<<) + SAR (>>) + SHR (>>>) - reprezentace reálných čísel - 20,625 - fixed-point 8bit - 20 + 0,625 - 10100,101 - 5.3 nebo 5+3 - není problém s aritmetickými operacemi - problém u velkých a malých čísel - reálné číslo reprezentované jako fixed-point na float převedu vydělením n-tou mocninou dvojky ## 10. přednáška - floating-point - normalizovaná - 1 číslice před desetinnou čárkou - žádné leading zeros - bez nuly - uložíme mantisu (significand) a exponent - exponent uložíme na stranu MSb, mantisu na stranu LSb - floating-point se skrytou jedna – využijeme toho, že každé číslo začíná jedničkou (zakázali jsme leading zeros), takže ukládáme až číslice za desetinnou čárkou - celá signed čísla: reprezentace s posunem (bias) - např. 8-bit → rozsah 0 až 255 - 255 = nejvyšší kladná hodnota (128) - 127 = 0 - 0 = nejnižší záporná hodnota (–127) - ale pokud bychom chtěli víc kladných a míň záporných hodnot, tak se to dá posunout - pomocí posunu se vyjadřuje znaménko exponentu - znaménko mantisy se vyjadřuje pomocí znaménkového bitu (MSb) - taková čísla se nedají sčítat (ale dají se porovnávat) → je potřeba SW nebo HW implementace - některé procesory mají speciální registry a operace s floating-point čísly - x86/x64 a dražší ARMy mají podporu, levnější ARMy, 6502 nemají - standard pro floatová čísla IEEE 754 - single 32-bit – v numpy float32, v C# float - double 64-bit – v Pythonu float, v numpy float64, v C# double - během aritmetiky musí dojít k denormalizaci - 0.1 se nedá zapsat s ukončeným desetinným rozvojem - nula = samé nuly (až na znaménko) – standard definuje, že se kladná nula rovná záporné nule - samé jedničky v exponentu a nulová mantisa → kladné/záporné nekonečno - funguje dělení nulou - samé jedničky v exponentu a nenulová mantisa → not a number (NaN) - $\infty/\infty =$ NaN - jsou dva typy NaN ## 11. přednáška - jednočip/microcontroller/$\micro$C/MCU - SRAM data memory – 256 B, volatile - CPU + registry - code memory – non-volatile - ROM (Read Only Memory) - PROM (Programmable ROM) – jeden zápis, nekonečno čtení; funguje na základě spálení diod - EPROM (Erasable PROM) – nekonečno zápisů, nekonečno čtení - maže se UV zářením, je potřeba nechat to na slunci 20 minut - EEPROM (Electrically EPROM) – „nekonečno“ zápisů, nekonečno čtení - flash – „nekonečno“ zápisů, nekonečno čtení - EEPROM + flash se dnes používají nejčastěji – souhrnný název NVRAM - EEPROM × flash - EEPROM – posloupnost bajtů - flash – bajty ukládá v blocích po 1–16 kB - EEPROM má sekvenční, random 1 byte a random block čtení průměrně rychlé - flash má pomalejší random 1 byte, ale rychlejší sekvenční čtení i random block čtení - zcela nekonečné zápisy nejsou možné, protože elektronům se postupně „přestává chtít ven z komůrek, kde jsou zabedněné“ - takže při běhu programu se používá RAM, do non-volatile paměti se v případě potřeby zapisuje v určitém rozumném intervalu - ADC (převodník z analogového na digitálního signálu) - např. uživatelský vstup – potenciometr - DAC – analogový výstup - GPIO řadič (General Purpose Input/Output) - registry ovlivňující, zda jsou piny vstupní/výstupní - permanentní datové úložiště (mass storage device) - von Neumannovská architektura - DRAM – kód + proměnné - CPU + SRAM - pevný disk / hard disk drive (HDD) - magnetický zápis - dipól – otočený na jednu stranu (podle toho 1 nebo 0) - dipóly jsou uloženy ve soustředných kružnicích - jedna kružnice = stopa - stopy jsou rozdělené na sektory (sektory jsou v podstatě kruhové výseče) - na jednom sektoru původně 512 B, dnes 4 kB (4096 B, advanced format) - čtecí hlava - 7200 RPM (otáček za minutu) - náhodný přístup v jedné stopě je lepší než sekvenční přístup pozpátku - hlava se otáčí, aby přistupovala k různým stopám – tomu se říká seek (seek time – doba otočení) - náhodný přístup mezi stopami je extrémně pomalý - přístup v řádech ms (jiné paměti se pohybují v řádu ns) - vhodné pro archivaci - několik ploten, lze zapisovat z obou stran každé z nich - všechny hlavy se pohybují najednou - stopám, které jsou nad sebou, se říká cylinder - v praxi se čísluje trojicí čísel – cylinder/hlava/sektor - stopy vzdálenější od středu mohou být rozděleny na více sektorů pro dosažení větší kapacity - úhlová rychlost je stejná, ale rychlost čtení/zápisu u jednotlivých stop se liší - CD/DVD/BluRay - zápis/čtení pomocí laseru - pomalejší zápis/čtení - jedna spirální stopa - Linear Block Addressing - jakmile dojdou data, přestává čtení – takže lze mít různé tvary CD - 1 sektor = 2048 B - řadič DVD - address register (LBA) - buffer = 1 sektor - command register – podle toho, zda chci provádět čtení/zápis - status register – ready? - info register – kapacita disku - potřebuju „magii“, která zajistí přesun dat z řadiče do paměti zařízení - data register – obsahuje interní address reg., vrací vždy 1 bajt z bufferu - řadič HDD (HDC = Hard Drive Controller) - řadič pevných disků se ovládá podobně jako řadič DVD, dostává LBA adresu - flash paměť s řadičem pevného disku – SSD - USB fleška: USB řadič → USB kabel → řadič → flash paměť - jakmile se data nahrají z disku do paměti, jsou uloženy v nějaké posloupnosti adres – první z nich se nazývá bázová - v Python potřebujeme pole bytů, není rozumné používat seznam, protože každé číslo seznamu by mělo svůj overhead - chceme na disk ukládat soubory - pamatujeme si data samotného souboru + metadata - metadata - seznam sektorů, kde je soubor uložený (nemusí být přímo za sebou → fragmentace) - délka v B - cesta souboru – adresáře (directories, složky/folders) a název souboru - datum, čas apod. - metadata → souborový systém (file system) - kromě zmíněného obsahuje i seznam volných sektorů - přístup k souborům řeší operační systém - soubor se otevře (jeho metadata se načtou do cache) → pracuje se s ním → zavře se (aby OS věděl, že ho nemusí držet v paměti) ## 11,5. přednáška - pythoní funkce open zavolá funkci operačního systému (OpenFile), která do paměti uloží metadata a vrátí ID souboru, které se uloží v pythoním objektu - soubor se dá otevřít jako binární (s příznakem *b*) – výsledný objekt má jiný typ - na binárním souboru máme funkci read, které zadáme, kolik bytů chceme přečíst - operační systém si do paměti připraví celý sektor, z něj vrátí požadované bajty - pythoní objekt si pamatuje aktuální offset - read posouvá offset o počet čtených bajtů, pokud chceme skočit k aktuálnímu bajtu, můžeme použít funkci seek (tato funkce umožňuje skákat relativně), funkce tell slouží ke zjištění aktuálního offsetu - pythoní funkce seek nesouvisí se čtecí hlavou - funkce readline (u textového souboru) vrátí celý řádek ve formě textu - textový soubor (text file) – všechny bajty souboru se dají interpretovat jako text - binární soubor (binary file) – pro některé nebo všechny bajty platí, že se nedají interpretovat jako text - hexdump / hexview - file format – specifikace, co bajty na konkrétních offsetech v souboru znamenají - binární soubory často na začátku obsahují metadata (hlavička souboru / header, může být na konci souboru nebo např. před skupinou dat) - na začátku souboru může být sekvence bytů, která jednoznačně určuje formát (takže lze případně vyloučit, že se jedná o soubor v daném formátu) – magic number / signature - MIDI soubor – zápis not (není uložen zvuk) - začátky a konce not - soubor BMP - obraz disku ## 12. + 12,5. přednáška - reprezentace obrazových dat - fotka = obdélníkový obrázek - doba expozice (n-tina sekundy) – za tu dobu se počítá, kam dopadají fotony - na sítnici oka dopadají fotony – vnímáme nějaký průměr - fotku můžeme rozdělit na čtverečky – pixely - potřebujeme označit pixely - sloupečky (osa x) se číslují od nuly zleva doprava - řádky (osa y) se číslují od nuly shora dolů - pixely se obvykle ukládají po řádcích, v rámci řádku zleva doprava - pixel nemusí mít jeden bajt - intenzita světla (počet fotonů) může nabývat hodnot 0 až nekonečno - pixel bude n bitů – bpp (bits per pixel) = bitová hloubka (bit depth) - nejjednodušší - jeden bit na pixel - stanovíme hraniční intenzitu – hodnoty pod ní uložíme jako nula, nad ní jako jedna - velmi omezená informace - pro určité zobrazovací technologie (klasický LCD displej) dostačující - tento princip ukládání nám umožňuje pixely sdružit např. po čtveřicích (tedy snížit rozlišení) a zachycovat odstíny šedé kombinací různého počtu černých a šedých pixelů (tzv. differing) - https://en.wikipedia.org/wiki/List_of_monochrome_and_RGB_color_formats - jeden bajt na pixel - stanovíme dvě meze – spodní (0) a horní (255) - intenzitu uložíme jako číslo v rozmezí 0 až 255 - meze je potřeba stanovit podle situace - bylo by hezké zaznamenávat obrázky, kde jsou oba extrémy (a u těchto extrémů ukazovat detaily) - použijeme floating-point čísla - HDR (High Definition Range) - moc se nepoužívá – je těžké takovou fotku zachytit atd. - chceme barvu - dívali jsme se jenom na počet fotonů, ne na jejich frekvenci (tedy barvu) - frekvence může být 0,00… (nenulová) až nekonečno - obvykle nás zajímá viditelné světlo - v oku - tyčinky – monochromatické vidění, velký rozsah - čípky – barevné vidění, malý rozsah - tři druhy čípků – jsou citlivé na různé frekvence (červené, zelené, modré) - barevný kanál → 3 kanály (RGB), nezávislé informace - 3-bit RGB – za každou barvu uložíme 1 bit - špatně se dělí osmi, přidáme bit navíc - 4-bit RGBI – navíc tmavší varianta barvy - 16-bit RGB - každou barvu pomocí 3 bitů - co s posledními bitem? - dáme ho zelené složce, protože tu lidské oko zvládne nejvíc rozlišovat - nebo s ním také nemusíme dělat nic (→ 15-bit RGB) - 24-bit RGB - 8 bitů na kanál - hi-color / True Color - ale máme 32bitové instrukce procesoru - 32-bit ARGB - čtvrtý bajt je tzv. alpha kanál - 255 = neprůhledný pixel - 0 = zcela průhledný pixel - metadata obrázku - počet kanálů - bitů na pixel/kanál (bitová hloubka) - šířka v pixelech - výška v pixelech - další informace ve formátu EXIF - jak uložit pixel - typicky ARGB (A v MSB, B v LSB) - nebo také RGBA - navíc záleží na endianitě - takže existují 4 možnosti: ARGB, RGBA, BGRA, ABGR - buď je v metadatech informace o pořadí složek, nebo je to ve specifikaci formátu - rastrový obraz, bitmapa - formát BMP - specifický způsob ukládání – zespodu nahoru - každý řádek je zarovnaný (align) – na konci má padding (nadbytečné bajty bez významu), aby řádky začínaly na místech dělitelných čtyřmi (aby se dobře načítaly) - textová data - textový řetězec (string) = posloupnost znaků - znak - písmeno - číslice - speciální znak - bílý znak (whitespace) - řídicí znak - kódování - jeden znak → jeden kód - kód → bitová reprezentace - pevná délka / proměnná délka - rasterizace textu - převod kód → obrázek (znak) - poznámka: jazyky se ukládají v pořadí, v jakém se čtou - kódování - ASCII - 7bitové (0–127) - písmena abecedy jsou uloženy za sebou, podobně číslice - znak nuly nemá kód nula - mezera má kód 32 (šestnáctkově 20) - při ukládání je MSb typicky nevyužitý - 128–255 jsou volné - rozšíření ASCII, tzv. codepage - nestačí ani na všechny evropské znaky – Evropa se rozdělila na tři části - ISO 8859-2 (ISO Latin2) - 852 (DOS Latin2) - Windows-1250 - nedá se napsat text, který by měl více kódování najednou (problém např. pro slovníky) - Unicode - 0–127 odpovídají ASCII - běžné znaky jsou v rozsahu 0–\$FFFF - je tam rozsah, kde je garantováno, že daným kódům nikdy nebudou přiděleny žádné znaky - „neběžné“ znaky v rozsahu \$10000–\$10FFFF - UTF-32 - jeden znak 4 bajty - UTF-32LE / UTF-32BE - prakticky se nepoužívá - UCS-2 - každý znak je dvoubajtový - podporuje málo znaků - UTF-16 - má proměnnou délku znaku – 2B nebo 4B - 4B znak se zachycuje pomocí sekvence dvou dvoubajtových surrogate znaků (z nepoužívaného „déčkového“ rozsahu) - UTF-16LE / UTF-16BE - UTF-8 - proměnná délka znaku – 1, 2, 3, 4B - princip kódování vícebytových znaků - vícebytové znaky mají v prvním bytu MSb roven jedné - pak počet bytů odpovídá počtu jedniček na začátku prvního bytu - první byte sekvence začíná 11, další byty začínají 10 - neřeší se endianita - nejběžnější kódování - internet: UTF-8 - Windows: UTF-16LE - když chceme text zobrazit uživateli – provedeme rasterizaci - zalomení řádku - CR (carriage return) – kód 13 - LF (line feed) – kód 10 - Windows: CR + LF - Unix/Linux: LF - Apple dříve: CR - Unicode (v podstatě nepoužívané) - LS – line separator - PS – paragraph separator - textový soubor jako posloupnost bytů - v Pythonu otevřeme pomocí r nebo w - řádky načítáme pomocí readline - v Pythonu je text uložen pomocí Unicodu - u příkazu open můžeme definovat kódování - výchozí kódování je win-1250 (obecně podle operačního systému) - chceme uložit binární soubor s textem (ale také dalšími daty) - data - 2B číslo - 4B délka textu - text - 4B číslo - pro převod na správný počet bytů můžeme použít funkci tobytes knihovny numpy - bajty stringu můžeme získat pomocí funkce str.encode - převod ze seznamu čísel na byty lze provést pomocí bytes() - převod bytů na konkrétní data se provádní pomocí frombuffer(bytes, type) - typ bytes je immutable - typ byteArray je mutable - bytes.decode – převede bajty na string ## 13. přednáška - von Neumannovská architektura - mezi procesor a paměť vložíme řadič paměti (memory controller) - řadič paměti zajišťuje refresh DRAM paměti, takže pokud procesor ukládá během refreshe, tak se data pozdrží a uloží se do paměti po refreshi - když chceme 1,5GB paměť, tak pořídíme dvě paměti (1GB a 0,5GB) - řadič paměti je namapuje v adresovém prostoru, aby fungovala kapacita 1,5 GB (modul 0 mapuje na první paměť, modul 1 na druhou) - procesor a paměť můžou mít různé komunikační protokoly – řadič to propojuje (to souvisí s velikostí adresových prostorů – např. procesor podporuje 8GB, ale paměti jenom 4GB, řadič umožňuje mít dvě 4GB paměti) - chceme, aby z procesoru vedla pouze jedna sběrnice – budeme jí říkat systémová sběrnice, je na ni napojen řadič paměti i všechno ostatní - každé zařízení na sběrnici má svou adresu - každé zařízení má nějaké registry - když oslovujeme zařízení, tak řekneme adresu zařízení a adresu registru, se kterým pracujeme – pak až pošleme data - potřebujeme, aby ta sběrnice byla multidrop (abychom mohli připojit více zařízení) - potřebujeme, aby ta sběrnice měla nějakou vlastnost, kterou I2C nemá – proto se jako systémová sběrnice typicky používá sběrnice PCI Express (PCIe) - PCIe - full duplex, multidrop - dva druhy packetů (transakcí) - adresace adresou zařízení - adresace adresou v paměťovém adresovém prostoru - memory write (MWr) - memory read (MRd) - procesor pošle požadavek - řadič paměti si ho zapamatuje a začne na tom pracovat - řadič v nějakém okamžiku pošle zpátky odpověď – řadič paměti vystupuje jako master, procesor jako slave, takže potřebujeme být schopni adresovat procesor - zejména pokud máme více procesorů (nebo procesorových jader) - v odpovědním packetu je kromě adresy procesoru také adresa řadiče paměti, aby si mohl procesor odpověď správně spojit s požadavkem - jak oslovovat zařízení na systémové sběrnici? - v paměťovém prostoru je obvykle spousta volného místa - toto volné místo namapujeme na zařízení - memory mapped I/O (MM I/O) - zařízení řekneme bázovou adresu v adresovém prostoru - z dokumentace zařízení zjistíme offset registru - když to zkombinujeme s bázovou adresou, tak zjistíme, na kterou adresu zapisovat - říká se tomu Host Controller Interface (HCI) – víme, co který registr dělá a na jakém je offsetu - komunikační protokol je daný systémovou sběrnicí - zvuková karta - zvuk = tlak se mění v čase - tlak budeme vzorkovat v čase – vždycky zaznamenáme jeho hodnotu - sample … signed integer - nekvalitní … 8-bit - klasická kvalita … 16-bit - kvalitnější … 24-bit - v reproduktoru je membrána s elektromagnetem – podle napětí elektromagnet membránu přitahuje silně/slabě - zvuková karta je jednoduchý digital analog converter (DAC) – podle vzorků vytváří napětí - potřebujeme ve stejných intervalech, jako se zaznamenával vstup, udávat napětí - sampling rate - typicky 44,1 kHz - někdy 22 kHz nebo 96 kHz - potřebujeme cyklus, který bude dělat store do registru zvukové karty v daném (velmi přesném) intervalu - bylo by hezké, kdybychom si mohli ve zvukové kartě připravit 1 ms předem (v bufferu) a zvuková karta by to následně přehrála (hodila by v tom bufferu po těch vzorcích a přehrávala by je) - zvuková karta tedy musí mít sadu konfiguračních registrů, kam uložíme různé informace (velikost vzorku, vzorkovací frekvence) - chceme mít n mikrofonů → n reproduktorů (mono/stereo/…) - chceme spustit/ukončit přehrávání - chceme nahrávat (tedy analog-digital converter) - chceme znát aktuální stav zvukové karty (co zrovna přehrává) - u zařízení s vícebytovými registry musíme řešit jejich endianitu (a případně převádět) - chceme mixovat zvuk – průměrujeme dva vzorky (pokud mají různou hlasitost, tak děláme vážený průměr) - dnešní zvukové karty mají HW akceleraci (CPU offloading) – typickým úkolem je právě mixování zvuku - DSP (digital signalling procesor) – strojovým kódem tohoto procesoru můžeme ovládat, jak se má zvuková karta chovat - řadič sběrnice - procesor – PCIe – USB řadič – USB sběrnice - takovým řadičům se říká HBA (Host Bus Adapter) – někdy také nesprávně bridge - USB HBA je komplikovaný, takže se podíváme na I2C HBA - průběh - pošleme write do konfiguračního registru, aby se do start condition bitu nastavila jednička - pomocí readu čekáme, až tam bude jednička - ze stavového registru přečteme stav řadiče - chceme poslat první (adresový) bajt - zrušíme start condition bit - … - pošleme data - … - mnoho transakcí na systémové sběrnici na jednu transakci na I2C lince - čekání = device polling, ztrácíme procesorový čas - grafická karta - je k ní připojený monitor - obsahuje paměť (typicky DRAM) – „video RAM“ - v její části je frame buffer – tam je bitmapa stavu obrazovky - karta x-krát za sekundu posílá monitoru obsah frame bufferu - tradičně se používala analogová linka VGA - dnes se používají digitální sériové linky DVI, HDMI, DisplayPort - nechceme frame buffer obsluhovat pomocí registrů, bylo by to neefektivní - frame buffer namapujeme do adresového prostoru, abychom do něj mohli zapisovat přímo - mezi snímky je díra (aby se CRT paprsek mohl přesunout na začátek) - registr grafické karty mi dává informaci o stavu vsync (že teď se právě paprsek přesouvá – je okamžik mezi snímky) - v okamžiku mezi snímky můžeme změnit obraz (překopírovat data do frame bufferu nebo říct jinou bázovou adresu frame bufferu, pokud máme dva frame bufferu, které střídáme – tzv. princip double bufferingu) - hardwarová akcelerace - rasterizace textu - kartě se nastaví textový režim - má pole bitmap, které odpovídají znakům - znaky přímo převádí na jim odpovídající bitmapy - dnes se příliš nepoužívá - rasterizace 2D - rasterizace 3D - do paměti nahrajeme mesh 3D modelu (trojúhelníky) a odpovídající textury, kterými se mesh pokryje – engine podle toho generuje obsah frame bufferu - moderní grafická karta má procesor - programu pro takový procesor se říká shader - jak dostat kód na von neumannovskou architekturu - jeden z paměťových modulů může být non-volatile – ROM - vykonává základní program, budeme mu říkat firmware - procesor má nastavený startup vector, což je adresa, kam se procesor nastaví po zapnutí - na té adrese je typicky jump, který směřuje jinam na reálný kód firmwarové ROM - funkce firmwarové ROM - bootování počítače - test a konfigurace hardwaru - plug & play – každému zařízení se přiřadí jiná bázová adresa a funguje to - nalezení užitečného softwaru - provede se jump na option ROM, kde je užitečný software (třeba editor a interpret basicu) - myšlenka, že bychom chtěli distribuovat programy - koupím si cartridge - zapojím ji do počítače - namapuje se jako další option ROM - je tam nějaký magic - užitečný software taky může být na mass storage device - pevný disk je rozdělený na sektory, je to zformátované souborovým systémem - nultý sektor je speciální – boot sector - může tam být strojový kód něčeho užitečného, co by se mělo spustit - je tam magic, který určuje, jestli je to zařízení bootovatelné (jestli v boot sektoru je něco rozumného) - jednotlivá zařízení (třeba grafická karta) mají své option ROM - v boot sektoru je typicky pouze část užitečného softwaru – bootloader - další funkce – firmwarové ROM: abstrakce nad hardwarem - funkce read sector, read key, print char - aby bootloader mohl používat tyto základní funkce - kdysi na jedné disketě jeden program - dnes si chceme vybírat z různých programů - jádro operačního systému (kernel) - poskytuje abstrakci souborového systému - abstrakce HW (lepší než firmware) – vstup/výstup (klávesnice, myš, text, grafika) - spouštění programů - typicky to nejprve spustí tzv. shell, aby si uživatel mohl vybrat, jaký program chce spustit - shell může být textový nebo grafický - více programů současně – programy se střídají (je to zjednodušení, více na počítačových systémech)