% c-bits-and-registers.tex — bit idioms, masks/fields, x&(x-1), popcount,
% stdint, volatile register access + read-modify-write hazards (W1TS/W1TC,
% W1C), C bitfields vs hardware, signed vs unsigned shifts, a register diagram.
% Sources: docs/memos/cs-bit-manipulation.md, docs/memos/c-systems.md (Q4, §4,
% Q14, Q25), docs/school/session/2026-06-24.md (Q4 PARTIAL: masks swapped,
% toggle unknown; Q9 endianness reversed; Q14 promotion).
% Build ONLY with: tools/print/print-sheet.py <this>.tex --dry-run
% @source: hiot monorepo, docs/school/sheets/c/c-bits-and-registers.tex — the SOURCE OF TRUTH; a copy anywhere else (e.g. artur.gurgul.pro) is regenerated from it, never edited
% @labels: area=c kind=concept level=deep platform=embedded new=no round=c-esp32-2026-09-24 topic=hardware,language
% @tags: bit-masks, bit-fields, popcount, w1c, w1ts-w1tc, read-modify-write, mmio, stdint, integer-promotion, signed-shift, power-of-two
\documentclass[8pt]{extarticle}
\usepackage{printup-sheet}
\usepackage{array}

\tikzset{
  bit/.style={draw=sheetGrey, minimum width=4.9mm, minimum height=5mm, inner sep=0pt,
              font=\ttfamily\scriptsize},
  bno/.style={font=\ttfamily\tiny, text=sheetGrey, inner sep=0.5pt},
  lbl/.style={font=\scriptsize, inner sep=1pt, align=center},
}

\begin{document}

\sheettitle{Bits, masks and hardware registers in C}{c · memo}

\oneliner{A register is a \textbf{memory address} you reach through a
\texttt{volatile uint32\_t *}; you change \emph{one field} with a
\textbf{mask + shift} and must keep every other bit intact —
\texttt{|=} sets, \texttt{\&= \textasciitilde} clears, \texttt{\^{}=} toggles,
\texttt{(r >> n) \& 1u} reads. The dangerous part is not the operator, it is the
\textbf{read-modify-write}.}

\vspace{2pt}
\noindent\begin{tikzpicture}[sheet]
  % 32 bits, bit 31 on the left
  \foreach \i in {0,...,31} {
    \pgfmathtruncatemacro{\b}{31-\i}
    \node[bno] at (\i*0.49+0.245, 0.42) {\b};
  }
  % field fills: 31..24 reserved, 23..16 DIV, 15..12 MODE, 11..8 res, 7 EN, 6 IE, 5..2 res, 1 ERR, 0 DONE
  \foreach \i in {0,...,31} {
    \pgfmathtruncatemacro{\b}{31-\i}
    \ifnum\b>23 \def\f{black!6}\def\v{-}\fi
    \ifnum\b<24 \ifnum\b>15 \def\f{sheetBlue!18}\def\v{0}\fi\fi
    \ifnum\b<16 \ifnum\b>11 \def\f{sheetGreen!20}\def\v{0}\fi\fi
    \ifnum\b<12 \ifnum\b>7 \def\f{black!6}\def\v{-}\fi\fi
    \ifnum\b=7 \def\f{sheetOrange!25}\def\v{1}\fi
    \ifnum\b=6 \def\f{sheetOrange!12}\def\v{0}\fi
    \ifnum\b<6 \ifnum\b>1 \def\f{black!6}\def\v{-}\fi\fi
    \ifnum\b<2 \def\f{sheetRed!18}\def\v{0}\fi
    \node[bit, fill=\f] at (\i*0.49+0.245, 0) {\v};
  }
  % DIV value 0x2A = 0010 1010 in bits 23..16 (i = 8..15)
  \foreach \i/\v in {10/1,12/1,14/1} \node[bit, fill=sheetBlue!35] at (\i*0.49+0.245, 0) {\v};
  % MODE = 0x3 in bits 15..12 (i = 16..19): bits 13,12 -> i=18,19
  \foreach \i/\v in {18/1,19/1} \node[bit, fill=sheetGreen!40] at (\i*0.49+0.245, 0) {\v};
  % braces
  \draw[decorate, decoration={brace, mirror, amplitude=3pt}, thick, sheetGrey] (0.02,-0.3) -- (3.9,-0.3)
     node[midway, below=3pt, lbl, text=sheetGrey]{reserved: \textbf{write back what you read}};
  \draw[decorate, decoration={brace, mirror, amplitude=3pt}, thick, sheetBlue] (3.94,-0.3) -- (7.82,-0.3)
     node[midway, below=3pt, lbl, text=sheetBlue]{\textbf{DIV} [23:16] = 0x2A\\\texttt{(r >> 16) \& 0xFFu}};
  \draw[decorate, decoration={brace, mirror, amplitude=3pt}, thick, sheetGreen] (7.86,-0.3) -- (9.78,-0.3)
     node[midway, below=3pt, lbl, text=sheetGreen]{\textbf{MODE} [15:12]\\\texttt{(r >> 12) \& 0xFu}};
  \draw[decorate, decoration={brace, mirror, amplitude=3pt}, thick, sheetOrange] (11.78,-0.3) -- (12.72,-0.3)
     node[midway, below=3pt, lbl, text=sheetOrange]{EN, IE\\RW flags};
  \draw[decorate, decoration={brace, mirror, amplitude=3pt}, thick, sheetRed] (14.72,-0.3) -- (15.66,-0.3)
     node[midway, below=3pt, lbl, text=sheetRed]{ERR, DONE\\\textbf{W1C}};
  \node[lbl, anchor=west, text=black!70] at (-0.05,0.85) {\textbf{CTRL} — an illustrative 32-bit peripheral register (value \texttt{0x002A3080}); bit 31 left, bit 0 right. Field = \emph{position} + \emph{width}.};
\end{tikzpicture}

\vspace{-2pt}
\begin{multicols}{2}

\section{The idioms (Q4: masks swapped, toggle unknown)}
{\footnotesize
\begin{tabular}{@{}>{\raggedright\arraybackslash}p{13mm}>{\ttfamily\raggedright\arraybackslash}p{30mm}>{\raggedright\arraybackslash}p{24mm}@{}}
\toprule
set bit $n$ & r |= (1u << n) & OR forces 1 \\
clear bit $n$ & r \&= \textasciitilde(1u << n) & AND with a hole \\
toggle bit $n$ & r \^{}= (1u << n) & \textbf{XOR} flips \\
test bit $n$ & (r >> n) \& 1u & 0 or 1 \\
get field & (r >> pos) \& mask & \texttt{mask=(1u<{}<w)-1} \\
put field & r = (r \& \textasciitilde(mask<<pos)) | ((v \& mask)<<pos) & clear, then OR \\
\bottomrule
\end{tabular}\par}
The \emph{bit number} goes in the shift, never in the mask: bit 3 is
\texttt{1u << 3} = \texttt{0x08}. Write \texttt{1u}, not \texttt{1} (see traps).

\section{Tricks worth knowing cold}
\begin{itemize}
  \item \texttt{x \& (x - 1)} clears the \textbf{lowest set bit}: \texttt{-1} turns that 1 into 0
        and every 0 below it into 1. Loop it = Kernighan popcount, O(set bits).
  \item \texttt{x \& (\textasciitilde x + 1)} (= \texttt{x \& -x}) isolates the lowest set bit.
  \item Power of two: \texttt{x \&\& !(x \& (x - 1))} — the \texttt{x != 0} guard is the trap.
  \item Round up to a power-of-two \texttt{a}: \texttt{(x + a - 1) \& \textasciitilde(a - 1)} —
        buffer / DMA alignment.
  \item Popcount: \texttt{\_\_builtin\_popcount} (GCC/Clang), C23 \texttt{stdc\_count\_ones}
        (\texttt{<stdbit.h>}). Also \texttt{\_\_builtin\_ctz}/\texttt{clz} (undefined for 0).
  \item \texttt{h \& (cap - 1)} = \texttt{h \% cap} when \texttt{cap} is $2^k$.
  \item Byte $k$ of a value: \texttt{(v >> (8*k)) \& 0xFFu} — arithmetic, so it is the same on
        little- \emph{and} big-endian. Endianness only bites when you reinterpret \emph{memory}
        (ESP32 is little-endian: bytes \texttt{01 02 03 04} read as \texttt{0x04030201}).
\end{itemize}

\section{Types: \texttt{<stdint.h>}}
\begin{itemize}
  \item \texttt{uint8\_t \dots\ uint64\_t} exact width; \texttt{int} is ``at least 16 bits'' —
        never use it for a register or a wire format. \texttt{uintptr\_t} holds an address.
  \item Literals: \texttt{UINT32\_C(1)}, \texttt{1u}, \texttt{1ull}; print with
        \texttt{PRIu32}/\texttt{PRIx32} from \texttt{<inttypes.h>}.
  \item \textbf{Promotion}: anything narrower than \texttt{int} becomes \texttt{int} first.
        \texttt{uint8\_t x = 0xFF; \textasciitilde x} is \texttt{0xFFFFFF00}, not 0.
\end{itemize}

\section{Shifts: unsigned vs signed}
\begin{itemize}
  \item Unsigned \texttt{>>} shifts in zeros (logical). Signed negative \texttt{>>} is
        \emph{implementation-defined} (GCC: arithmetic, copies the sign).
  \item \texttt{1 << 31}: shifting a 1 into \texttt{int}'s sign bit is \textbf{UB};
        \texttt{1u << 31} = \texttt{0x80000000}. Shift by $\geq$ the width (\texttt{1u << 32})
        is UB for every type.
\end{itemize}

\columnbreak

\section{Register access}
\begin{lstlisting}[language=C]
#define REG32(a) (*(volatile uint32_t *)(a))
#define CTRL     REG32(PERIPH_BASE + 0x10)  // illustrative
#define DIV_POS  16u
#define DIV_MSK  0xFFu

uint32_t div = (CTRL >> DIV_POS) & DIV_MSK;       // read field
CTRL = (CTRL & ~(DIV_MSK << DIV_POS))             // RMW: clear
     | ((new_div & DIV_MSK) << DIV_POS);          //      insert
STATUS = 1u << DONE_BIT;  // W1C: write only that 1, never |=

// ESP-IDF (soc/soc.h): one store, no read -> atomic
REG_WRITE(GPIO_OUT_W1TS_REG, 1u << 5);  // GPIO5 high
REG_WRITE(GPIO_OUT_W1TC_REG, 1u << 5);  // GPIO5 low
\end{lstlisting}
\begin{itemize}
  \item \texttt{volatile}: every access is a real load/store (never kept in a register,
        dropped or merged). \emph{No} atomicity, no ordering.
  \item \textbf{RMW hazard}: \texttt{r |= b} is load → OR → store. An ISR or the
        \emph{other core} changing another bit in between is overwritten → lost update.
  \item Hence \textbf{SET/CLR registers}: ESP32 \texttt{GPIO\_OUT\_W1TS}/\texttt{W1TC}
        (write-1-to-set/-clear) — one store, only the 1-bits act.
  \item \textbf{W1C} status bits: \texttt{STATUS |= DONE} writes back every pending 1
        → clears interrupts you never handled. Some bits clear \emph{on read}.
\end{itemize}

\section{C bitfields — why not for hardware}
Bit order, allocation unit, straddling and plain-\texttt{int} signedness are
\textbf{implementation-defined}; the compiler picks the \emph{access width} (a byte
store to a 32-bit-only register can fault) and each field write is a hidden RMW.
ESP-IDF's \texttt{soc/*\_struct.h} uses them anyway — one pinned compiler + ABI.
Portable: masks + shifts; wire formats: \texttt{memcpy} + shifts.

\section{Interview traps}
\begin{itemize}
  \trap{\textbf{You swapped the masks} (set 5, cleared 3) — the bit number goes in the
        shift. Toggle = \textbf{XOR}, the one you missed.}
  \trap{\texttt{if (r \& 1u << n == 0)} — \texttt{==} binds tighter than \texttt{\&}:
        it parses as \texttt{r \& ((1u<<n) == 0)}. Parenthesise every mask test.}
  \trap{\texttt{1 << 40} into a \texttt{uint64\_t} is still an \texttt{int} shift → UB.
        ESP-IDF's \texttt{pin\_bit\_mask} is 64-bit: write \texttt{1ULL << pin}.}
\end{itemize}

\section{Remember}
\textbf{OR sets, AND-NOT clears, XOR flips, shift-then-AND reads — and every
\texttt{|=} on a register is three instructions.}

\section{Likely questions}
\begin{enumerate}
  \item Why \texttt{1u}? — \texttt{1 << 31} overflows signed \texttt{int} = UB.
  \item Two tasks, one register, different bits? — lost update → W1TS/W1TC or a lock.
  \item \texttt{n \& (n-1)}? — drops the lowest 1; \texttt{== 0} ⇒ power of 2 ($n>0$).
  \item Bitfields for registers? — layout + access width not portable.
\end{enumerate}

\end{multicols}

\noindent{\footnotesize\color{sheetGrey}\textit{Related:} volatile vs \_Atomic ·
integer promotion · endianness + \texttt{ntohl} · struct padding / \texttt{packed} ·
ESP32 architecture \& memory · peripherals \& DMA · Swift \texttt{OptionSet}}

\end{document}
