BitLab vzorek, který se někdo zeptá

Tohle je statická kopie kapitoly pro vyhledávače. Interaktivní verze má animované obrázky, kontrolní otázky a tlačítka, která příklad načtou do kalkulačky.

Masky a registry: sáhnout na jedno pole a nerozbít sousedy

Registr periferie je jedno slovo, ve kterém sedí vedle sebe věci, které spolu nesouvisí: tři bity dělička hodin, jeden bit povolení, dva bity režim, zbytek nepoužito. Napsat do něj celé číslo znamená přepsat i to, na co se nesahalo — a to je nejběžnější chyba v ovladači.

Čtyři idiomy, které stačí umět

nastavit:   x |= (1 << n)
shodit:     x &= ~(1 << n)
přepnout:   x ^= (1 << n)
zeptat se:   (x >> n) & 1
jeden bit

Všechny mají tvar přečti, uprav, zapiš. To „přečti“ je podstatné: bez něj se o hodnotě ostatních bitů dělá předpoklad, a ten předpoklad bývá „byly nula“.

Celé pole, ne jeden bit

Pole o šířce w začínající na bitu lsb se čte a píše takhle:

maska = ((1 << w) − 1) << lsb
čtení:   (x & maska) >> lsb
zápis:   x = (x & ~maska) | ((v << lsb) & maska)
pole v registru

To & maska na konci zápisu vypadá zbytečně — vždyť v se do pole vejde. Není zbytečné. Kdyby v bylo větší, než se do w bitů vejde, přeteklo by do sousedního pole, a to je chyba, kterou nic nenahlásí. Ta maska je pojistka, ne ozdoba.

A jedna past, která je specificky hardwarová: u některých registrů čtení mění stav — příznak přerušení se čtením shodí. Idiom „přečti, uprav, zapiš“ tam příznak zahodí a přerušení se ztratí. Proto mají takové registry často zvlášť adresu pro „nastav tyhle bity“ a zvlášť pro „shoď tyhle bity“; čte se pak jen jednou a nic se nepřepisuje.

Bitová pole v C: pohodlné, ale nepřenositelné

Jazyk C umí struct { unsigned mode : 2; unsigned enable : 1; }; a je to čitelnější než maska. Pořadí těch polí ve slově ale norma nestanoví — záleží na překladači a na architektuře. Pro vnitřní stav programu je to v pořádku; pro popis registru, který je předepsaný v katalogovém listu, nebo pro rámec, který poletí po lince, se to použít nedá. Tam patří maska a posun napsané ručně.

Vzorce v této kapitole

pole — maska pole
m = ((1 << w) − 1) << lsb [—] kap. 6
zápis — čti, uprav, zapiš
x = (x & ~m) | ((v << lsb) & m) [—] kap. 6