From a9779382d1ac2404d10ebdb340a77da6a4436f12 Mon Sep 17 00:00:00 2001 From: Mark Wooding Date: Sat, 26 May 2018 18:22:39 +0100 Subject: [PATCH] utils/bits.3: Basically rewrite it, filling in the missing things. Oh, dear. This manpage has been neglected for years. --- utils/bits.3 | 622 +++++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 503 insertions(+), 119 deletions(-) diff --git a/utils/bits.3 b/utils/bits.3 index fc2885d..7eb1e2b 100644 --- a/utils/bits.3 +++ b/utils/bits.3 @@ -1,24 +1,99 @@ .\" -*-nroff-*- .TH bits 3 "20 June 1999" "Straylight/Edgeware" "mLib utilities library" +.ie t \{\ +. ds ss \s8\u +. ds se \d\s0 +.\} +.el \{\ +. ds ss ^ +. ds se +.\} .SH NAME bits \- portable bit manipulation macros +.\" octet +.\" uint16 +.\" uint24 +.\" uint32 +.\" uint64 +.\" kludge64 +.\" +.\" MASK_8 +.\" MASK_16 +.\" MASK_16_L +.\" MASK_16_B +.\" MASK_24 +.\" MASK_24_L +.\" MASK_24_B +.\" MASK_32 +.\" MASK_32_L +.\" MASK_32_B +.\" MASK_64 +.\" MASK_64_L +.\" MASK_64_B +.\" +.\" SZ_8 +.\" SZ_16 +.\" SZ_16_L +.\" SZ_16_B +.\" SZ_24 +.\" SZ_24_L +.\" SZ_24_B +.\" SZ_32 +.\" SZ_32_L +.\" SZ_32_B +.\" SZ_64 +.\" SZ_64_L +.\" SZ_64_B +.\" +.\" TY_8 +.\" TY_16 +.\" TY_16_L +.\" TY_16_B +.\" TY_24 +.\" TY_24_L +.\" TY_24_B +.\" TY_32 +.\" TY_32_L +.\" TY_32_B +.\" TY_64 +.\" TY_64_L +.\" TY_64_B +.\" +.\" DOUINTSZ +.\" DOUINTCONV +.\" .\" @U8 .\" @U16 +.\" @U24 .\" @U32 +.\" @U64 +.\" @U64_ .\" .\" @LSL8 .\" @LSR8 .\" @LSL16 .\" @LSR16 +.\" @LSL24 +.\" @LSR24 .\" @LSL32 .\" @LSR32 +.\" @LSL64 +.\" @LSR64 +.\" @LSL64_ +.\" @LSR64_ .\" .\" @ROL8 .\" @ROR8 .\" @ROL16 .\" @ROR16 +.\" @ROL24 +.\" @ROR24 +.\" @ROL32 .\" @ROL32 -.\" @ROR32 +.\" @ROL64 +.\" @ROR64 +.\" @ROL64_ +.\" @ROR64_ .\" .\" @GETBYTE .\" @PUTBYTE @@ -33,6 +108,13 @@ bits \- portable bit manipulation macros .\" @STORE16_B .\" @STORE16 .\" +.\" @LOAD24_L +.\" @LOAD24_B +.\" @LOAD24 +.\" @STORE24_L +.\" @STORE24_B +.\" @STORE24 +.\" .\" @LOAD32_L .\" @LOAD32_B .\" @LOAD32 @@ -40,54 +122,100 @@ bits \- portable bit manipulation macros .\" @STORE32_B .\" @STORE32 .\" +.\" @LOAD64_L +.\" @LOAD64_B +.\" @LOAD64 +.\" @STORE64_L +.\" @STORE64_B +.\" @STORE64 +.\" +.\" @LOAD64_L_ +.\" @LOAD64_B_ +.\" @LOAD64_ +.\" @STORE64_L_ +.\" @STORE64_B_ +.\" @STORE64_ +.\" +.\" @SET64 +.\" @X64 +.\" @ASSIGN64 +.\" @HI64 +.\" @LO64 +.\" @GET64 +.\" @AND64 +.\" @OR64 +.\" @XOR64 +.\" @CPL64 +.\" @ADD64 +.\" @SUB64 +.\" @CMP64 +.\" @ZERO64 .SH SYNOPSIS .nf .B "#include " -.BI "octet U8(" v ); -.BI "uint16 U16(" v ); -.BI "uint32 U32(" v ); +.BR "typedef " ... " octet;" +.BR "typedef " ... " uint16;" +.BR "typedef " ... " uint24;" +.BR "typedef " ... " uint32;" +.BR "typedef " ... " uint64;" +.BR "typedef " ... " kludge64;" + +.BI "#define TY_" we " " type +.BI "#define SZ_" we " \fR..." +.BI "#define MASK_" we " \fR..." -.BI "octet LSL8(" v ", " s ); -.BI "octet LSR8(" v ", " s ); -.BI "uint16 LSL16(" v ", " s ); -.BI "uint16 LSR16(" v ", " s ); -.BI "uint32 LSL32(" v ", " s ); -.BI "uint32 LSR32(" v ", " s ); +.BI "#define DOUINTSZ(" f ") \fR..." +.BI "#define DOUINTCONV(" f ") \fR..." -.BI "octet ROL8(" v ", " s ); -.BI "octet ROR8(" v ", " s ); -.BI "uint16 ROL16(" v ", " s ); -.BI "uint16 ROR16(" v ", " s ); -.BI "uint32 ROL32(" v ", " s ); -.BI "uint32 ROR32(" v ", " s ); +.IB type " U" w ( v ); -.BI "octet GETBYTE(" p ", " o ); -.BI "void PUTBYTE(" p ", " o ", " v ); +.IB type " LSL" w ( type " " v ", int " s ); +.IB type " LSR" w ( type " " v ", int " s ); +.IB type " ROL" w ( type " " v ", int " s ); +.IB type " ROR" w ( type " " v ", int " s ); -.BI "octet LOAD8(" p ); -.BI "void STORE8(" p ", " v ); +.BI "octet GETBYTE(void *" p ", size_t " o ); +.BI "void PUTBYTE(void *" p ", size_t " o ", octet " v ); -.BI "uint16 LOAD16_B(" p ); -.BI "uint16 LOAD16_L(" p ); -.BI "uint16 LOAD16(" p ); -.BI "void STORE16_B(" p ", " v ); -.BI "void STORE16_L(" p ", " v ); -.BI "void STORE16(" p ", " v ); +.IB type " LOAD" we "(void *" p ); +.BI "void STORE" we "(void *" p ", " type " " v ); -.BI "uint32 LOAD32_B(" p ); -.BI "uint32 LOAD32_L(" p ); -.BI "uint32 LOAD32(" p ); -.BI "void STORE32_B(" p ", " v ); -.BI "void STORE32_L(" p ", " v ); -.BI "void STORE32(" p ", " v ); +.BI "void SET64(kludge64 &" d ", uint32 " h ", uint32 " l ); +.BI "kludge64 X64(" hexh ", " hexl ); +.BI "void ASSIGN64(kludge64 &" d ", " x ); +.BI "uint32 HI64(kludge64" x ); +.BI "uint32 LO64(kludge64" x ); +.IB ty " GET64(" ty ", kludge64 " x ); +.BI "void AND64(kludge64 &" d ", kludge64 " x ", kludge64 " y ); +.BI "void OR64(kludge64 &" d ", kludge64 " x ", kludge64 " y ); +.BI "void XOR64(kludge64 &" d ", kludge64 " x ", kludge64 " y ); +.BI "void CPL64(kludge64 &" d ", kludge64 " x ); +.BI "void ADD64(kludge64 &" d ", kludge64 " x ", kludge64 " y ); +.BI "void SUB64(kludge64 &" d ", kludge64 " x ", kludge64 " y ); +.BI "int CMP64(kludge64 " x ", " op ", kludge64 " y ); +.BI "int ZERO64(kludge64 " x ); .fi .SH DESCRIPTION The header file .B contains a number of useful definitions for portably dealing with bit- -and byte-level manipulation of larger quantities. It declares three -types: +and byte-level manipulation of larger quantities. The various macros +and types are named fairly systematically. +.PP +The header provides utilities for working with 64-bit quantities, but a +64-bit integer type is not guaranteed to exist under C89 rules. This +header takes two approaches. Firstly, if a 64-bit type is found, the +header defines the macro +.B HAVE_UINT64 +and defines the various +.RB ... 64 +macros as described below. Secondly, it unconditionally defines a type +.B kludge64 +and a family of macros for working with them. See below for details. +. +.SS "Type definitions" +A number of types are defined. .TP .B octet Equivalent to @@ -105,106 +233,362 @@ Intended to be used when a 16-bit value is required. This type is always capable of representing any 16-bit unsigned value, but the actual type may be wider than 16 bits and will require masking. .TP +.B uint24 +Equivalent to some (architecture-dependent) standard type. Capable of +representing any unsigned 24-bit value, although the the actual type may +be wider than 24 bits. +.TP .B uint32 Equivalent to some (architecture-dependent) standard type. Capable of representing any unsigned 32-bit value, although the the actual type may be wider than 32 bits. +pp.TP +.B uint64 +Equivalent to some (architecture-dependent) standard type, if it exists. +Capable of representing any unsigned 64-bit value, although the the +actual type may be wider than 64 bits. +. +.SS "Size/endianness suffixes" +Let +.I w +be one of the size suffixes: 8, 16, 24, 32, and (if available) 64. +Furthermore, let +.I we +be one of the size-and-endian suffixes +.IR w , +or, where +.IR w \~>\~8, +.IB w _L +or +.IB w _B \fR, +where +.RB ` _L ' +denotes little-endian (Intel, VAX) representation, and +.RB ` _B ' +denotes big-endian (IBM, network) representation; omitting an explicit +suffix gives big-endian order by default, since this is most common in +portable data formats. .PP -The constants -.BR MASK8 , -.B MASK16 -and -.B MASK32 -contain bitmasks appropriate for discarding additional bits from a value -before use as an 8-, 16- or 32-bit quantity. The macros -.BR U8 , -.B U16 -and -.B U32 -perform masking and type-coercion on a value, and may be more useful in -general. For example, -.B U16(x) -yields a value of type -.B uint16 -which contains (only) the least-significant 16 bits of -.BR x . +The macro invocation +.BI DOUINTSZ( f ) +invokes a given macro +.I f +repeatedly, as +.IB f ( w ) +for each size suffix +.I w +listed above. .PP -The macros -.BI LSL n -and -.BI LSR n -perform left and right logical shift operations on values of width -.IR n , +The macro invocation +.BI DOUINTCONV( f ) +invokes a given macro +.I f +repeatedly, as +.IR f ( w ", " we ", " suff ) where -.I n -is one of -.BR 8 , -.B 16 +.I we +ranges over size-and-endian suffixes as described above, +.I w +is just the corresponding bit width, as an integer, and +.I suff +is a suffix +.IR w , +.IB w l\fR, or -.BR 32 . -The first argument, written -.IR v , -is the value to shift, and the second, written -.IR s , -is the number of bits to shift. The value -.I s -is reduced modulo -.I n -before use. Similarly, the macros -.BI ROL n -and -.BI ROR n -perform left and right rotations (cyclic shifts) on values of width -.IR n . -These macros are all written in such a way as to maximize portability. -A compiler may be able to spot that simple machine instructions will -suffice in many cases, although that's not the main objective. +.IB w b\fR, +suitable for a C function name. .PP -The macros -.BI LOAD n +These macros are intended to be used to define families of related +functions. +. +.SS "Utility macros" +For each size-and-endian suffix +.IR we , +the following macros are defined. +.TP +.BI TY_ we +A synonym for the appropriate one of the types +.BR octet , +.BR uint32 , +etc.\& listed above. +.TP +.BI SZ_ we +The number of octets needed to represent a value of the corresponding +type; i.e., this is +.IR w /8. +.TP +.BI MASK_ we +The largest integer representable in the corresponding type; i.e., this +is +.RI 2\*(ss w \*(se\~\-\~1. +.PP +(Note that the endianness suffix is irrelevant in the above +definitions.) +.PP +For each size suffix +.IR w , +the macro invocation +.BI U w ( x ) +coerces an integer +.I x +to the appropriate type; specifically, it returns the smallest +nonnegative integer congruent to +.I x +(modulo +.RI 2\*(ss w \*(se). +. +.SS "Shift and rotate" +For each size suffix +.IR w , +the macro invocations +.BI LSL w ( x ", " n ) and -.BI STORE n -(where again +.BI LSR w ( x ", " n ) +shift a +.IR w -bit +quantity +.I x +left or right, respectively, by .I n -is one of -.BR 8 , -.B 16 -or -.BR 32 ) -perform transformations between -.IR n -bit -quantities and arrays of octets. For example, -.B LOAD32(q) -returns the 32-bit value stored in the four octets starting at address -.BR q , -and -.B STORE16(q, x) -stores the 16-bit value -.B x -in the 2 octets starting at address -.BR q . -Values are loaded and stored such that the most significant octet is -assigned the lowest address (i.e., they use network, or big-endian byte -order). Macros -.BI LOAD n _L +places; if +.IR n \~\(>=\~ w +then +.I n +is reduced modulo +.IR w . +(This behaviour is unfortunate, but (a) it's what a number of CPUs +provide natively, and (b) it's a cheap way to prevent undefined +behaviour.) Similarly, +.BI ROL w ( x ", " n ) and -.BI STORE n _L -are also provided for +.BI ROR w ( x ", " n ) +rotate a +.IR w -bit +quantity +.I x +left or right, respectively, by .I n -either -.B 16 +places. +. +.SS "Load and store" +The macro invocation +.BI GETBYTE( p ", " o ) +returns the +.IR o th +octet following the address +.IR p . +Conversely, +.BI PUTBYTE( p ", " o ", " v) +stores +.I +v in the +.IR o th +byte following the address +.IR p . +These macros always operate on byte offsets regardless of the type of +the pointer +.IR p . +.PP +For each size-and-endian suffix +.IR we , +the macro invocation +.BI LOAD we ( p ) +loads and returns a value in the corresponding format at address +.IR p ; +similarly, +.BI STORE we ( p ", " x ) +stores the value +.I x +at address +.I p +in the corresponding format. +. +.SS "64-bit support" +For portability to environments without native 64-bit integers, the +structure +.B kludge64 +is defined. If the target platform is known to have an unsigned 64-bit +integer type, then this structure merely encapsulates a native integer, +and a decent optimizing compiler can be expected to handle this exactly +as if it were the native type. Otherwise, it contains two 32-bit halves +which are processed the hard way. +.PP +For each of the above macros with a suffix +.BR 64 , +.BR 64_L , or -.BR 32 : -they use little-endian byte order. There are -explicit big-endian macros -.BI LOAD n _B +.BR 64_B , +an additional `kludge' macro is defined, whose name has an additional +final underscore; e.g., the kludge macro corresponding to +.B ROR64 +is +.BR ROR64_ ; +and that corresponding to +.B LOAD64_L +is +.BR LOAD64_L_ . +If the original macro would have +.I returned +a value of type +.BR uint64 , +then the kludge macro has an additional first argument, denoted +.IR d , +which should be an lvalue of type +.BR kludge64 , +and the kludge macro will store its result in +.IR d . +The kludge macro's remaining arguments are the same as the original +macro, except that where the original macro accepts an argument of type +.BR uint64 , +the kludge macro accepts an argument of type +.B kludge64 +instead. +.PP +Finally, a number of additional macros are provided, to make working +with +.B kludge64 +somewhat less awful. +.TP +.BI SET64( d ", " h ", " l ) +Set the high 32 bits of +.I d +to be +.IR h , +and the low 32 bits to be +.IR l . +Both +.I h +and +.I l +may be arbitrary integers. +.TP +.BI X64( hexh ", " hexl ) +Expands to an initializer for an object of type +.B kludge64 +where +.I hexh +and +.I hexl +encode the high and low 32-bit halves in hexadecimal, without any +.B 0x +prefix. +.TP +.BI ASSIGN( d ", " x ) +Make +.I d +be a copy of the +.B kludge64 +.IR x . +.TP +.BI HI64( x ) +Return the high 32 bits of +.IR x . +.TP +.BI LO64( x ) +Return the low 32 bits of +.IR x . +.TP +.BI GET64( t ", " x ) +Return the value of +.I x +as a value of type +.IR t . +If +.I t +is an unsigned integer type, then the value will be truncated to fit as +necessary; if +.I t +is a signed integer type, then the behaviour is undefined if the value +of +.I x +is too large. +.TP +.BI AND64( d ", " x ", " y ) +Set +.I d +to be the bitwise-and of the two +.B kludge64 +arguments +.I x and -.BI STORE n _B -too. The pointer arguments don't have to be pointers to octets; the -value arguments don't have to be of the right type. The macros perform -all appropriate type casting and masking. Again, these macros are -written with portability foremost in mind, although it seems they don't -actually perform at all badly in real use. +.IR y . +.TP +.BI OR64( d ", " x ", " y ) +Set +.I d +to be the bitwise-or of the two +.B kludge64 +arguments +.I x +and +.IR y . +.TP +.BI XOR64( d ", " x ", " y ) +Set +.I d +to be the bitwise-exclusive-or of the two +.B kludge64 +arguments +.I x +and +.IR y . +.TP +.BI CPL64( d ", " x ) +Set +.I d +to be the bitwise complement of the +.B kludge64 +argument +.IR x . +.TP +.BI ADD64( d ", " x ", " y ) +Set +.I d +to be the sum of the two +.B kludge64 +arguments +.I x +and +.IR y . +.TP +.BI SUB64( d ", " x ", " y ) +Set +.I d +to be the difference of the two +.B kludge64 +arguments +.I x +and +.IR y . +.TP +.BI CMP64( x ", " op ", " y ) +Here, +.I x +and +.I y +should be arguments of type +.B kludge64 +and +.I op +should be one of the relational operators +.BR == , +.BR < , +.BR <= , +.BR > , +or +.B >= +\(en +.I not +.BR !=. +Evaluates nonzero if +.IR x \~ op \~ y . +.TP +.BI ZERO64( x ) +Evaluates nonzero if the +.B kludge64 +argument +.I x +is exactly zero. .SH "SEE ALSO" .BR mLib (3). .SH AUTHOR -- 2.11.0