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
shodit: x &= ~(1 << n)
přepnout: x ^= (1 << n)
zeptat se: (x >> n) & 1jeden 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:
č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ě.