MMIXware: A RISC Computer for the Third Millennium

by Donald E. Knuth (Heidelberg: Springer-Verlag, 1999), viii+550pp.
(Lecture Notes in Computer Science, no. 1750.)
ISBN 3-540-66938-8

(A Japanese translation by Tooru Takizawa was published in 2002 by SiBaccess Co. Ltd.)

MMIX is a RISC computer designed by the author to illustrate machine-level aspects of programming. In the next editions of his books The Art of Computer Programming, MMIX will replace the 1960s-style machine MIX. A particular goal in the design of MMIX was to keep its machine language simple, elegant, and easy to learn. At the same time, all of the complexities needed to achieve high performance in practice were also taken into account, so that MMIX could in principle be built and even be competitive with some of the fastest general-purpose machines on the market. All in all, MMIX is a clean, complete, and well-documented machine-independent machine ideally suited as a testbed for long-term research projects of lasting value, even as real computers continue to change rapidly.

This book is a collection of programs written in CWEB that make MMIX a virtual reality. Among other utilities, an assembler converting MMIX symbolic files to MMIX objects and two simulators executing the programs in given object files are provided. Of particular interest is the MMMIX meta-simulator, which is able to do dynamic scheduling of a complex pipeline, allowing superscalar execution with any number of functional units and with many varieties of caching and branch prediction, etc., including a detailed implementation of both hard and soft interrupts.

The main purpose of this book is to provide a complete documentation of the MMIX computer and its assembly language, together with all necessary low-level details such as the format of MMIX object files. A secondary purpose is to provide literate programs of interest in their own right. For example, a full implementation of IEEE standard floating point arithmetic is developed in terms of 32-bit integer arithmetic, including new routines for floating point input and output that deliver the maximum possible accuracy. The meta-simulator includes a tutorial presentation about pipelines, comparing the processing to the activities in a high-tech automobile repair shop.

All programs of this book are in the public domain, and their final versions can be downloaded together with dozens of example programs from The Art of Computer Programming. The right-hand pages of this book contain exclusive mini-indexes, which greatly facilitate reading the programs at one's desk or in a comfortable chair. There also is a general master index covering the entire book.

Available from the publisher, Springer Verlag, Inc..

ONLINE VERSION (pdf format)

Errata

The following errors and infelicities are presently known to exist in the printed version. (Most of them are trivial typos; more substantive corrections are flagged with ***.) I encourage the use of this book as supplementary reading in university classes that deal with hardware architecture; if enough professors adopt it, we will soon be able to reprint the book with all corrections made.

page 2, line 19 (28 Dec 1999)
change "millenium" to "millennium"
page 10, line 20 (23 Dec 1999)
change "exclusive or" to "exclusive-or"
page 11, line 1 (23 Dec 1999)
change "not and" to "not-and"
page 11, line 6 (23 Dec 1999)
change "not or" to "not-or"
page 11, line 11 (23 Dec 1999)
change "not exclusive or" to "not-exclusive-or"
page 13, displayed formula on line 17 (23 Dec 1999)
change "y_{7j}z_{i7}" to "\lor y_{7j}z_{i7}"
page 13, lines 5 and 6 from the bottom (23 Dec 1999)
change "exclusive or" to "exclusive-or"
page 14, line 14 from the bottom (28 Dec 1999)***
change "0 or 16 or 32 or 48" to "48 or 32 or 16 or 0"
page 19, line 21 (4 Oct 2000)
change "@+XYZ" to "@+4*XYZ"
page 19, line 5 from the bottom (15 Jun 2002)
change "the the" to "the"
page 22, lines 12 and 13 from the bottom (12 Apr 2000)
change "does not define the representations of NaNs" to "does not fully define the result of operations with NaNs"
page 24, line 5 (05 Aug 2000)
delete "ignore $Y since they"
page 24, line 15 (15 Jun 2002)
change "set to $Y." to "set to $Y. (Registers $Y and $Z are not actually changed.)"
page 24, line 5 from the bottom (28 Dec 1999)***
change "rZ" to "$Z"
page 25, line 18 (28 Dec 1999)***
change "rY" to "$Y"
page 27, lines 7 and 13 (28 Dec 2000)
change "2^53" to "2^52" (3 changes)
page 27, line 18 (28 Dec 2000)
change "$2^{53}$" to "$\pm2^{52}$"
page 27, line 21 (28 Dec 2000)
change "$2^{106}+2^{54}$" to "$2^{105}+2^{53}$"
page 27, append another line to the program (08 Apr 2011)
OR   $X,$X,$2   make sure minus zero isn't lost
page 28, line 7 from the bottom (13 May 2000)
change "stored from" to "stored into"
page 32, line 1 (22 Mar 2005)
change "has a several" to "has several"
page 32, line 2 from the bottom (13 Oct 2001)***
change "If ${\rm X}\ge L$" to: "If $L\le{\rm X}<G$, the value of $L$ increases to $\rm X+1$ as described above; then the rules for ${\rm X}<L$ apply. [new paragraph]If ${\rm X}\ge G$"
page 33, lines 11--14 (05 Apr 2000)***
Replace the long sentence "Then we ... PUSHGO." by the following: "Then we set x <- S[\tau-1] mod 256; this is the effective value of the X field in the push instruction that is being undone. Stack position S[\tau-1] is now set to $(X-1) if 0 < X <= L, otherwise it is set to zero. Then we essentially set L <- min(x+X,G), $(L-1) <- $(L-x-2), ..., $(x+1) <- $0, $x <- S[\tau-1], ..., $0 <- S[\tau-x-1], \tau <- \tau-x-1."
page 34, line 7 from the bottom (15 Jun 2002)
change "restored" to "restored, assuming that G doesn't decrease"
page 34, line 4 from the bottom (05 Apr 2000)***
change "the hole" to "the hole (unless L = G = 255)"
page 36, line 26 (28 Dec 1999)
change "obtained." to "obtained.)"
page 38, line 6 (13 May 2000)
change "byte of E" to "byte of rA"
page 40, lines 8 and 9 (5 May 2011)
change "may" to "might" (twice)
page 41, line 8 (15 Feb 2002)***
change "set to zero" to "set to rJ"
page 41, line 14 (15 Feb 2002)
change "more than enough" to "just enough"
page 41, line 15 (15 Feb 2002)
change "GET" to "PUT rJ,$255; GET"
page 42, lines 2 and 3 (15 Feb 2002)***
change "(i) $255 is set ... not zero; (ii)" to "(i)"; also change "(iii)" to "(ii)" on line 4 and "(iv)" to "(iii)" on line 5
page 42, new paragraph to follow the second paragraph of section 36 (31 May 2011)***
When a forced trap occurs on a store instruction because of memory protection failure, the settings of rYY and rZZ are undefined. They do not necessarily correspond to the virtual address rY and octabyte to be stored rZ that are supplied to a trip handler after a tripped store instruction, because a forced trap aborts its instruction as soon as possible.
page 42, line 2 of section 37 (15 Jun 2002)
change "the the" to "the"
page 43, line 11 (15 Jun 2002)
change "GET $1,rK" to "LDOU $1,savedK"
page 43, line 12 (15 Jun 2002)
change this line to simply "SADD $2,$1,$0; ANDN $1,$0,$1"
page 43, line 15 (09 Nov 2005)
change "also in rX" to "also in rXX"
page 45, line 14 (15 Feb 2002)***
change "LDT" to "LDTU"
page 46, line 6 (01 Jun 2011)***
change "cycle counter" to "continuation register"
page 46, replacement for first five lines of section 40 (06 Jun 2011)
The interval counter rI decreases by 1 on every ``clock pulse'' of the MMIX processor. Thus if MMIX is running at 500 MHz, the interval counter decreases every 2 nanoseconds. It causes an
page 47, lines 5 and 6 (01 Jun 2011)
change "leftmost" to "next-to-leftmost" and "eighth-least" to "seventh-least"
page 47, line 11 (10 Sep 2013)
change "(mod 2^{48})" to "(modulo 2^{47})"
page 47, line 20 (01 Jun 2011)
change "counters rC and rI" to "counter rI"
page 48, line 3 (10 Jan 2000)
change "mean time" to "Mean Time"
page 49, line 12 (12 Jan 2002)
change "If many" to "(Actually $\beta$ is never allowed to increase to the point where it becomes equal to $\gamma$.) If many"
page 50, line 8 (01 Jun 2011)***
change "rC (the cycle counter) or rN" to "rN"
page 50, lines 14 and 15 (01 Jun 2011)***
change "special registers 8--11 ... namely rI" to "special registers 9--11 (namely rN, rO, and rS) must not change; special registers 8 and 12--18 (namely rC, rI"
page 52, line 9 (28 Dec 1999)***
change "7fffffffffff" to "7fffffffffffffff"
page 52, line 9 from the bottom (16 Jan 2000)
change "8K" to "8192"
page 53, line 6 (15 Jun 2002)
change "$a$ is" to "$2^s a$ is"
page 54, line 7 (16 Jan 2000)
change "8K" to "8192"
page 54, new paragraph following line 9
Several special cases have weird behavior, which probably isn't going to be useful. But I might as well mention them so that the flexibility of this scheme is clarified: If, for example, $b_1=2$, $b_2=b_3=1$, and $b_4=5$, then $r+1$ is used both for PTPs of segment 0 and PTEs of segment 2. And if $b_2=b_3<b_4$, then $r+b_2$ is used for the PTE of page 0 segments 2 and 3; page 1 of segment 2 is not allowed, but there is a page 1 in segment 3.
page 54, another new paragraph at end of section 45 (01 Jun 2011)***
Stack overflow presents a potential problem: If $\gamma$ increases to a virtual address on a new page for which there is no permission to write, the protection interrupt handler would have no stack space in which to work! Therefore MMIX has a continuation register rC, which contains the physical address of a ``continuation page.'' Pushed-down information is written to the continuation page until MMIX comes to an instruction that is safely interruptible. Then a stack overflow interrupt occurs, and the operating system can restore order. The format of rC is just like an ordinary PTE entry, except that the n field is ignored.
page 55, append new sentence to description of LDVTS (5 May 2011)
(Changes are not immediate; so SYNC and/or SYNCD ought to be done when appropriate, as discussed in MMIX-PIPE.)
page 56, lines 9 and 10 (26 Nov 2002)***
delete these two lines (namely the instructions AND $1,$7,#7 and BNZ $1,FAIL)
page 56, line 13 from the bottom (21 Mar 2004)***
just before the instruction "SRU $0,virt,s", insert a new line as follows:
ANDNH virt,#e0000 % zero out the segment number
page 56, lines 1, 3, 5, and 7 from the bottom (26 Nov 2002)***
change "AND $x,#3ff" to "AND $x,$x,$6" and insert a new instruction "SETL $6,#3ff" before that block of code
page 56, bottom 8 lines, and line 2 of page 57 (06 Jan 2010)***
change "OR $5,base,0" to "CMP $5,base,limit (5 changes)
page 57, lines 3, 6, 9, 12, 18 (06 Jan 2010)***
insert the instruction "BNN $5,Fail" just before "8ADDU" (5 changes)
page 57, lines 15--17 from the bottom (06 Jan 2010)***
replace the three instructions "BNZ $6,Fail; CMP $6,$5,limit; BN $6,Ready" by the single instruction "PBZ $6,Ready % branch if n matches"
page 57, lines 20 and 21 (21 Mar 2004)***
change these two instructions to "XOR $6,base,$7" and "ANDN $6,$6,#7", so that they don't change base
page 62, new material after line 13 (29 Jul 2000)***
#include <stdio.h>
#include <string.h>
#include <ctype.h>
page 62, line 7 from the bottom (13 Feb 2000)
change "tetrabytes makes" to "tetrabytes make"
page 66, line 3 from the bottom (10 Jan 2000)***
change "((aux.h^acc.h)&sign_bit)" to "(aux.h^(aux.h>>1)^(acc.h&sign_bit))"
page 67, line 7 (28 Dec 1999)
change "aux" to "aux."
page 68, line 5 from the bottom (15 Jun 2002)***
change "while" to "if (n>1) while"
page 71, line 4 of section 26 (21 Jun 2003)***
change "193.]" to "193. Some of the tricks used here were suggested by Balbir Singh, Peter Rossmanith, and Stefan Schwoon.]
page 71, replacement for line 6 from the bottom (21 Jun 2003)***
xx=xx-((xx>>1)&0x55555555);
page 71, replacement for lines 2, 3, 4 from the bottom (26 Jan 2000)***
xx=(xx+(xx>>4))&0x0f0f0f0f; xx=xx+(xx>>8); return (xx+(xx>>16)) & 0xff;
page 82, line 4 from the bottom (27 Aug 2000)***
change "xe++, xf=shift_right(xf,1,1)" to "xe++, d=xf.l&1, xf=shift_right(xf,1,1), xf.l|=d", thereby making this line the same as the bottom line
page 83, 4th-from-last line of section 49 (21 Aug 2000)***
change "oo.h \lor o.h" to "oo.h \ne o.h" (in C this changes || to !=)
page 84, line 1 (13 Feb 2000)
change "number" to "numbers"
page 85, lines 9 and 10 (15 Mar 2006)***
change "ye<0" to "ye<0 && yt!=zro", and change "ze<0" to "ze<0 && zt!=zro"
page 85, line 4 from the bottom (21 Jun 2003)***
change "-1:1" to "0:1"
page 90, line 19 (15 Jun 2002)***
change "*p=r" to "*p=r-1"
page 94, new paragraph to follow line 24 (26 Nov 2002)
The value of exceptions set by scan_const is not necessarily correct.
page 95, line 4 of section 71 (23 Dec 1999)***
change "val.h=0x600000" to "val.h=0x600000, exp=0x3fe"
page 96, lines 23-24 of section 73 (21 Mar 2009)***
these lines should say "exp=0;" and then "if (*p=='e' && !NaN) <Scan an exponent 77>"
page 97, line 16 (21 Mar 2009)
change "<1000" to "<100000000"
pages 93, 117, ..., 521, mini-index entries for strlen (29 Jul 2000)
change "int" to "size_t"
page 111, line 5 from the bottom (16 Feb 2002)***
change "2009" to "2003"
page 113, line 8 (16 Sep 2001)
change "a S-cache" to "an S-cache"
page 113, line 12 of section 5 (13 Oct 2001)
change "ultiplication" to "multiplication"
page 116, line 2 of section 11 (30 Mar 2005)
change "valid decimal integer" to "string of decimal digits"
page 116, new body for the get_int subroutine (30 Mar 2005)
int v; char *p;
get_token();
for (p=token,v=0; *p>='0' && *p<='9'; p++) v=10*v+*p-'0';
if (*p) return -1;
return v;
page 118, line 12 (13 Feb 2000)***
change "&max_mem_slots,1,1" to "&max_mem_slots,2,1"
page 118, line 16 from the bottom (16 Feb 2002)***
change "2009" to "2003"
page 127, line 4 (13 Feb 2000)
change "facing us" to "facing us is"
page 128, line 1 (06 Oct 2013)
change MMIX_pipe to MMIX_run
page 134, replacement for lines 22 and 23 (27 Sep 2001)***
if (bp_a+bp_b+bp_c>=31) panic(errprint0("Configuration error\
: Branch table has >= 2 gigabytes of data"));
page 134, replacement for line 7 from the bottom (05 Feb 2009)***
if (Icache && (Icache->bb>>3)>j) j=Icache->bb>>3;
page 138, line 9 from the bottom (13 Feb 2000)
change "tetrabytes makes" to "tetrabytes make"
pages 139, 141, and 143, mini-index entries for mmputchars (03 May 2000)
change "int" to "void"
page 140, line 10 (29 Jul 2000)
omit "FILE *tmp;"
page 141, line 9 of section 13 (15 Jun 2002)
change "goto done;" to "{ free(buf); goto done; }"
page 142, line 19 (04 June 2011)
change "buf" to "(unsigned char *)buf"
page 143, line 15 (21 Mar 2009)***
change "int eof;" to "int eof=0;"
page 143, line 24 (04 June 2011)
change "buf" to "(unsigned char *)buf"
page 145, after line 11 of section 20 (15 Jun 2002)
insert a copy of line 6 ("if (sfile[handle].mode ... ~#1;") here
page 148, new paragraph to follow line 7 (19 Jul 2011)
Many I/O devices communicate via bytes or wydes or tetras instead of octabytes. So these prototype routines have a size parameter, to distinguish between the various kinds of quantities that MMIX wants to read from and write to the memory-mapped addresses.
page 148, additional changes (19 Jul 2011)
(The new spec_read and spec_write involve a couple dozen rather tedious new lines of code, which can be found in the source file mmix-mem.w.)
page 150, lines 12--14 (06 Oct 2013)
change "as soon as possible to knuth-bug... version 0.)" to "as soon as possible. Instructions can be found at http://mmix.cs.hm.edu/bugs/."
page 152, just after line 5 (24 Mar 2006)
insert "<Preprocessor definitions>" [this comes from "@h" in the file mmix-pipe.w]
page 156, line 19 (13 Feb 2000)
change "tetrabytes makes" to "tetrabytes make"
page 157, mini-index entry for froot (05 Apr 2000)
change "912" to "91"
page 162, line 3 of section 34 (06 Aug 2001)
change "from to back" to "from front to back"
page 167, new line to follow line 1 (01 Jun 2011)
bool stack_alert; /* is there potential for stack overflow? */
page 168, replacement for line 8 from the bottom (05 Aug 2005)***
if (c->arith_exc) { printf(" exc="); print_bits(c->arith_exc<<8); }
page 169, the running headline (15 Mar 2000)
change "LISTS" to "COROUTINES"
page 176, lines 3--5 (01 Jun 2011)
change "8--11" to "9--11"; change "12--18" to "8 and 12--18"; change "15--20" to "8 or 15--20"
page 176, line 10 (01 Jun 2011)
change "cycle counter" to "continuation register"
page 177, new line at end of section 57 (01 Jun 2011)***
#define STACK_OVERFLOW (1<<7) /* data has been stored on the rC page */
[also change "1<<7" to "1<<6" on the previous line]
page 186, line 30 (29 Jul 2000)
change "==-1" to "==(tetra)-1"
Page 192, line 14 from the bottom (08 Apr 2011)***
change "#1a, #19" to "#3a, #39"
page 192, line 9 from the bottom (13 Oct 2001)***
change "#8a, #89" to "#aa, #a9"
page 192, line 2 from the bottom (13 Oct 2001)***
change "#c0, #c0, #c0, #c0" to "#c0, #c0, #e0, #e0"
page 194, replacement for section 87 (01 Jun 2011)***
<External variables> $+\equiv$
Extern octa ticks; /* the internal clock */
page 195, line 26 (29 Jul 2000)
change "==-1" to "==(tetra)-1"
page 198, line 23 (01 Jun 2011)***
change cool->interim to cool->interim = cool->stack_alert
page 202, replacement for line 4 (03 Jun 2011)***
if (cool->xx>cool_G) { if (i!=pushgo && i!=pushj && i!=cswap) cool->ren_x=true, spec_install(&g[cool->xx],&cool->x);}
page 202, in the former line 6 (03 Jun 2011)***
change "cool->ren_x ... &cool->x);" to "{ if (i!=cswap) cool->ren_x ... &cool->x); }"
page 202, replacement for the former line 8 (12 Jan 2002)***
increase_L: if (((cool_S.l-cool_O.l-cool_L-1)&lring_mask)==0)
page 203, after line 3 (10 Sep 2013)***
insert a new line "cool->stack_alert=!(cool->y.o.h&sign_bit);"
page 203, new line 3 of section 114 (30 May 2011)
The value of $\beta$ may need to be decreased too (by decreasing rL).
page 203, replacement for all the code in this section (30 May 2011)***
{
  if (cool_O.l+cool_L==cool_S.l+lring_size) { /* don't let $\gamma$ pass $\beta$ */
    if (cool->i==pop && cool->xx==cool_L && cool_L>1) {
      cool->i=or; /* we'll preserve the main result by moving it down */
      head->inst-=0x10000; /* decrease X field of \.{POP} in fetch buffer */
      op=OR;
      cool->y=specval(&l[(cool_O.l+cool->xx-1)&lring_mask]);
      spec_install(&l[(cool_O.l+cool->xx-2)&lring_mask],&cool->x);
    } else { /* decrease rL by 1 */
      spec_install(&g[rL],&cool->rl);
      cool->rl.o.l=cool_L-1;
      cool->set_l=true;
    }
  }
  if (cool->i!=or) {
    cool->i=decgamma;
    new_S=incr(cool_S,-1);
    cool->y.p=NULL, cool->y.o=shift_left(new_S,3);
    spec_install(&l[new_S.l&lring_mask],&cool->x);
    op=LDOU; /* this instruction needs to be handled by load/store unit */
    cool->ptr_a=(void*)mem.up;
  }
  cool->z=cool->b=zero_spec; cool->need_b=false;
  cool->ren_x=cool->interim=true;
  goto dispatch_done;
}
page 204, line 1 of section 118 (01 Jun 2011)
change "special registers 16--21 (namely rK" to "special registers 8 or 15--20 (namely rC, rK"
page 204, line 8 of section 118 (01 Jun 2011)***
change "11" to "11 && cool->xx!=8"
page 204, line 11 of section 118 (01 Jun 2011)***
change "if (...)" to "if (cool->xx==8 || (...))"
page 205, line 1 (13 Oct 2001)
change "$\rm X\ge L$" to "$\rm X\ge G$"
page 205, line 8 (13 Oct 2001)
change "cool_L" to "cool_G"
page 205, replacement for line 9 (12 Jan 2002)***
if (((cool_S.l-cool_O.l-cool_L-1)&lring_mask)==0)
page 205, lines 12 and 13 (13 Oct 2001)
interchange these lines, so the "cool->ren_x=true..." comes before the right curly brace
page 208, line 7 (14 Apr 2000)
change "that that" to "that"
page 216, line 13 (11 Jan 2002)
change "to written" to "to be written"
page 216, replacement for line 19 (19 Jul 2011)***
else if (data->mem.x) {
  data->x.known=true;
  if (!(data->x.addr.h&0xffff0000)) data->x.addr.l&=-8;
}
page 218, new code following 7 (01 Jun 2011)***
if (hot->stack_alert) stack_overflow=true;
else if (stack_overflow && !hot->interim) {
  g[rQ].o.l|=STACK_OVERFLOW, new_Q.l|=STACK_OVERFLOW, stack_overflow=false;
  if (verbose&issue_bit) {
    printf(" setting rQ="); print_octa(g[rQ].o); printf("\n");
  }
}
page 219, new line for end of section 148 (01 Jun 2011)
bool stack_overflow; /* stack overflow not yet reported */
page 222, line 8 (27 Sep 2001)***
change "(cool_hist&bp_bcmask)<<bp_b" to "(cool_hist&bp_bcmask)<<bp_a"
page 222, line 23 (27 Sep 2001)***
change "(cool_hist&bp_bcmask)<<bp_b" to "(cool_hist&bp_bcmask)<<bp_a"
page 223, line 8 (27 Sep 2001)
change "the $n$-bit code for $-1$" to "the sign bit of an $n$-bit number"
page 226, line 27 (13 Oct 2001)
change "table lookaside buffer" to "translation lookaside buffer"
page 227, line 11 (28 Sep 2004)
change "$r_1\ldots r_a$" to "$r_1\ldots r_{2^a-1}$"
page 237, line 1 of section 198 (15 Mar 2000)
change "we want" to "we"
page 239, line 21 (29 Jul 2000)
omit "register int j;"
pag 239, new line after the original line 22 (19 Jul 2011)***
if (c->flusher.next && c->outbuf.tag.h==alf.h &&
  !((c->outbuf.tag.l^alf.l)&c->tagmask)) return NULL;
page 240, line 12 from the bottom (16 Feb 2002)
change "2009" to "2003"
page 240, line 5 from the bottom (19 Jul 2011)
change "." to ", but with an additional size parameter, which specifies that 1<<size bytes should be read or written.
page 240, lines 1 and 2 from the bottom (19 Jul 2011)***
change "))" to ", int size))"
page 241, line 7 of section 210 (19 Jul 2011)***
delete this line (which calls spec_read the old way)
page 242, line 7 of section 213 (19 Jul 2011)***
delete this line (which calls spec_write the old way)
page 245, replacement for lines 4 thru 9 (18 Sep 2000)***
{ register int count = block_diff>>3;
register int off, delay;
octa addr;
if (mem_lock) wait(1);
addr.h = c->outbuf.tag.h; addr.l = c->outbuf.tag.l&-Scache->bb;
off = (addr.l&0xffff)>>3;
for (j=0; j<Scache->bb>>3; j++)
if (j==0) Scache->inbuf.data[j] = mem_read(addr);
page 246, line 5 of section 222 (08 Mar 2012)
change "Icache or Dcache" to "Icache, Dcache, or Scache"
page 246, line 10 of section 222 (08 Mar 2012)
change "ptr_b" to "ptr_a"
page 246, line 11 of section 222 (21 Aug 2000)
change "or the receive" to "or to receive"
page 248, the lines for cases 4 and 5 (10 Sep 2013)***
first change "case 5" to "case 6" and "case 4" to "case 5"; change "data->state=5;" to "data->state=6;"; insert a new line before the new "case 5": "case 4: Scache->lock=NULL; data->state=5;"; and delete the former line that said "Scache->lock=NULL;"
page 252, line 9 (03 Jan 2000)***
change "p->tag.h != data->x.o.h" to "p->tag.h |= data->x.o.h"
page 253, line 3 (03 Jan 2000)***
change "p->tag.h != data->x.o.h" to "p->tag.h |= data->x.o.h"
page 254, line 18 (15 Jun 2002)
change "quantites" to "quantities"
page 256, new line of code for section 238 (22 Feb 2011)***
int page_f; /* the 3-bit $f$ field of rV */
page 256, replacement for line 4 of section 239 (22 Feb 2011)***
page_f=rv.l&0x7, page_bad=(page_f>1);
page 257, line 5 of section 241 (01 Jun 2011)***
change "t=trans; t.l&=-8" to "t=oandn(trans, page_mask)"
page 260, new line to follow line 13 (19 Jul 2011)***
int size;
page 262, line 8 (12 Sep 2000)
change "block." to "block, unless ptr_a points to a committed instruction."
page 262, new code to follow line 7 of section 255 (12 Sep 2000)***
if (p == &mem) goto qloop;
if (p > &hot->x && ctl <= hot) goto qloop; /* already committed */
if (p < &ctl->x && (ctl <= hot || p > &hot->x)) goto qloop;
page 262, line 9 of section 255 (29 Jul 2000)
change "==-1" to "==(tetra)-1"
page 262, line 13 of section 255 (12 Sep 2000)***
change "for (;;)" to "qloop: for (;;)"
page 262, new code preceding line -2 (17 Jul 2011)***
if (hot->x.addr.h&0xffff0000) {
  if (hot->op>=STB&&hot->op<STSF) q->size=(hot->op&0xf)>>2;
  else if (hot->op>=STSF&&hot->op>STCO) q->size=2;
  else q->size=3;
}
page 264, insert new code 3 lines after case 0 (19 Jul 2011)***
if (write_head->addr.h&0xffff0000) goto mem_direct;
(and delete the test on write_head two lines further down)
page 265, line 6 (19 Jul 2011)***
change "mem_write" to "if (write_head->addr.h&0xffff0000) spec_write(write_head->addr,write_head->o,write_head->size); else mem_write"
page 267, the running headline (15 Mar 2000)
change "LOADING AND STORING" to "THE WRITE BUFFER"
page 268, line 8 of section 266 (2 Feb 2011)***
change "data->i==st||(data->i<preld&&data->i>syncid)" to "data->i<preld||data->i==st||data->i==pst"
page 270, lines 14--15 of section 268 (01 Jun 2011)***
change "<Update ... p->data[0]);" to "p=use_and_fix(DTcache,p), data->z.o=p->data[0];
<Check the protection bits and get the physical address>;"
page 271, lines 4--5 of section 269 (01 Jun 2011)***
change "<Update ... DTcache,p);" to "<Check the protection bits and get the physical address> $\equiv$
if (data->stack_alert) {
  if (data->z.o.l&(PW_BIT>>PROT_OFFSET)) data->stack_alert=false;
  else data->z.o=g[rC].o; /* use the continuation page for stack overflow */
}"
page 271, the former lines 7 and 10 of section 269 (01 Jun 2011)***
change "p->data[0].l" to "data->z.o.l" (twice)
page 271, the former line 11 of section 269 (01 Jun 2011)***
change "goto fin_ex;" to "data->stack_alert=false; goto fin_ex;"
page 271, new line of code for end of section 269 (01 Jun 2011)***
data->z.o=phys_addr(data->y.o,data->z.0);
page 271, lines 4--5 of section 270 (01 Jun 2011)***
change "<Update ... p->data[0]);" to "p=use_and_fix(DTcache,p), data->z.o=p->data[0];
<Check the protection bits and get the physical address>;"
page 272, replacement for if on line 9 (19 Jul 2011)***
if (data->z.o.h&0xffff0000) {
  switch (data->i) {
  case ldvts: case preld: case prest: case prego: case syncd: case syncid: goto fin_ex;
  case ld: case ldunc: if (mem_lock) wait(1);
    if (data->op<LDSF) i=(data->op&0xf)>>2;
    else if (data->op<CSWAP) i=2;
  else i=3;
  data->x.o=spec_read(data->z.o,i);
  goto make_ld_ready;
  case pst: if ((data->op^CSWAP)<=1) {
      data->x.o=spec_read(data->z.o,3); goto make_ld_ready;
    }
    data->x.o=zero_octa;
  case st: data->state=st_ready; pass_after(1); goto passit;
    }
} else if
page 272, replacement for the former lines 15--18 (19 Jul 2011)***
  pass_after(1); goto passit;
} else if (!Dcache) {
  if (mem_lock) wait(1);
  data->x.o=mem_read(data->z.o);
make_ld_ready: set_lock(&mem_locker,mem_lock);
page 274, lines 17--18 of section 272 (01 Jun 2011)***
change "<Update ... p->data[0]);" to "p=use_and_fix(DTcache,p), data->z.o=p->data[0];
<Check the protection bits and get the physical address>;"
page 274, line 25 of section 272 (22 Feb 2011)***
change "no_hardware_PT" to "no_hardware_PT || page_f"
page 274, replacement for 7 lines following case got_DT (01 Jun 2011)***
change "j=PRW_BITS; ... data->z.o);" to "<Check the protection bits and get the physical address>;"
page 278, bottom line (05 Aug 2000)***
change "data->b.o.h" to "set_round; data->b.o.h"
page 281, line 17 (05 Apr 2000)
change "known; it" to "known; if"
page 284, line 15 from the bottom (05 Feb 2009)***
change "j<Icache->bb" to "j<Icache->bb>>3"
page 286, line 4 of section 298 (22 Feb 2011)***
change "no_hardware_PT" to "no_hardware_PT || page_f"
page 291, insert a new line after line 12 (08 Apr 2011)***
data->arith_exc|=(j&~(0x10000>>(m>>4)))>>8;
page 292, line 11 from the bottom (15 Feb 2002)***
change "!g[rT].up->known" to "!g[rT].up->known || !g[rJ].up->known"
page 292, line 7 from the bottom (15 Feb 2002)***
change "trip:" to "trip: if (!g[rJ].up->known) goto stall;
page 292, line 5 from the bottom (15 Feb 2002)***
change "if (i==trip) cool->x.o=" to "cool->x.o=g[rJ].up->o; if (i==trip)"
page 295, replacement for lines 4 and 5 (15 Feb 2002)***
g[255].o=g[rJ].o;
page 295, line 9 (15 Feb 2002)***
make this line identical to line 12
page 298, line 19 from the bottom (15 Jun 2003)
change "insure" to "ensure"
page 301, in section 327 (01 Aug 2011)***
remove "case jmp: case pushj:" from its line, and insert a new line: "case jmp: case pushj: data->go.o=data->z.o; goto fin_ex;"
page 301, line 5 from end of section 328 (2 Feb 2011)***
change "==rK" to "==rK || data->zz==rQ"
page 302, line 5 (01 Jun 2011)***
change "if (...)" to "if (data->xx==8 || (...))"
page 302, line 2 from end of section 330 (5 Mar 2011)***
change "B_BIT;" to "B_BIT, data->z.o.h=0, data->z.o.l&=0x3ffff;"
page 302, line 6 in section 330 (2 February 2011)***
change "B_BIT;" to "B_BIT, data->z.o=g[rG].o;"
page 304, replacement for line 6 from the bottom (12 Jan 2002)***
else if (((cool_S.l-cool_O.l-cool_L-1)&lring_mask)==0)
page 309, cases fsqrt, fint, fix, and flot (05 Aug 2000)***
change "data->x.o" to "set_round; data->x.o"
page 309, mini-index entry for froot (05 Apr 2000)
change "912" to "91"
page 310, line 5 of section 350 (22 Feb 2011)***
change "goto" to "data->interrupt|=exceptions; goto"
page 311, mini-index entry for fcomp (21 Jun 2003)
change "84" to "85"
page 320, line 6 of section 373 (19 Jul 2011)
change 90 to f0
page 321, line 7 (03 May 2000)
change "int mmputchars" to "void mmputchars"
page 322, line 9 of magic_read and also line 9 of magic_write (11 Aug 2004)***
change "q->addr.l==addr.l" to "(q->addr.l&-8)==(addr.l&-8)"
page 322, line 17 (23 Mar 2004)***
after this line (which begins "if (p) return..."), insert the following new lines of code:
if (((Dcache->outbuf.tag.l^addr.l)&-Dcache->bb)==0 && Dcache->outbuf.tag.h==addr.h)
  return Dcache->outbuf.data[(addr.l&(Dcache->bb-1))>>3];
page 322, line 20 (23 Mar 2004)***
after this line (which begins "if (p) return..."), insert the following new lines of code:
if (((Scache->outbuf.tag.l^addr.l)&-Scache->bb)==0 && Scache->outbuf.tag.h==addr.h)
  return Scache->outbuf.data[(addr.l&(Scache->bb-1))>>3];
"
page 322, lines 4 and 6 from the bottom (27 Feb 2004)***
change "Dcache->tagmask" to "-Dcache->bb"
page 323, lines 2 and 4 (27 Feb 2004)***
change "Scache->tagmask" to "-Scache->bb"
page 325, line 17 (03 May 2000)
change "int mmputchars" to "void mmputchars"
page 325, line 27 (03 May 2000)
change "return 0" to "return"
page 328, in general (05 Apr 2000)
raise all the text on this page (except the headline) by one line
page 330, top (05 Apr 2000)
raise all the text on this page (except the headline) by one line
page 332, line 20 (01 Jun 2011)
change "clock register rC" to "simulated clock"
page 332, line 22 (10 Sep 2013)
change "instruction, and the usage counter rU increases by 1" to "$\upsilon$; and the usage count field of rU may increase by 1 (modulo 2^{47})"
page 332, lines 8 and 12 from the bottom (05 Apr 2000)***
change "-x" to "-e" (three changes)
page 333, line 7 (05 Apr 2000)
change "-P." to "-P. If <n> is omitted it is assumed to be 3."
page 333, line 9 (05 Apr 2000)***
change "-r -s" to "-e -r -s"
page 333, line 8 from the bottom (24 Jul 2000)***
change "program." to "program. This option should be used whenever the simulator is not being used interactively, because the simulator will not recognize end of file when standard input has been defined in any other way.
page 334, line 7 from the bottom (10 Sep 2013)
change "250 instructions have been executed" to "$250\upsilon$ have elapsed"
page 336, line 3 (09 Mar 2013)
change "is a string" to "is the address of the first byte of a string"
page 336, line 7 (12 Jan 2002)
change "TextWrite or BinaryWrite" to "TextWrite, BinaryWrite, or BinaryReadWrite"
page 336, line 19 from the bottom (24 Jul 2000)
change "; the" to ", unless the -f option has been used. The"
page 336, line 15 from the bottom (05 Apr 2000)
change "<stdio>" to "stdio"
page 339, lines 13--15 (04 Jun 2011)***
change "90" to "f0" (thrice)
page 342, line 19 (13 Feb 2000)
change "tetrabytes makes" to "tetrabytes make"
page 345, mini-index entry for froot (05 Apr 2000)
change "912" to "91"
page 347, line 1 (13 Oct 2001)
change "2K" to "2048"
page 348, new line of code for section 19 (01 Jun 2011)***
octa sclock; /* simulated clock */
page 350, after line 7 of section 24 (15 Jun 2002)
insert "if (!alt_name) panic("Can't allocate file name buffer");"
page 353, line 7 (25 Aug 2000)***
change "read_tet(); cur_loc.h=(ybyte<<24)+tet" to "j=ybyte; read_tet(); cur_loc.h=(j<<24)+tet"
page 353, line 19 (25 Aug 2000)***
change "read_tet(); tmp.h=(ybyte<<24)+tet" to "j=ybyte; read_tet(); tmp.h=(j<<24)+tet"
page 354, line 9 from the bottom (05 Apr 2000)
change "and $ = argc" to "and $0 = argc"
page 355, after line 6 of section 41 (15 Jun 2002)
insert "if (!buffer) panic("Can't allocate source line buffer");"
page 357, line 12 (05 Apr 2000)
change "Set file pointer to ''offset''" to "code for setting the file pointer to a given offset"
page 357, mini-index entry for st_mtime (05 Apr 2000)
change "stat.h" to "stat.h>"
page 363, line 2 from the bottom (05 Apr 2000)
change "how it is" to "how it"
page 369, lines 2 and 3 from the bottom (13 Oct 2001)***
change "#8a" to "#aa" and "#89" to "#a9"
page 371, lines 3 and 4 (13 Oct 2001)***
change "#c0" to "#e0"
page 371, line 16 (15 Feb 2002)***
change "rY" to "rW=%#w, rX=%#x, rY"
page 371, line 16 (15 Feb 2002)***
change "=0" to "=%#a"
page 374, insert the following after line 15, then delete line 13 (12 Jan 2002)***
if (((S-O-L)&lring_mask)==0) stack_store();
page 378, line 15 from the bottom (18 Sep 2006)***
insert the following after "case DIVI:" (it handles integer divide check):
if (!z.l && !z.h) aux=y, exc|=D_BIT, overflow=false; else
page 379, mini-index entry for froot (05 Apr 2000)
change "912" to "91"
page 381, mini-index entry for fcomp (21 Jun 2003)
change "84" to "85"
page 382, line 18 (11 Sep 2013)***
change "else bad_guesses++,g[rC].l+=2;" to "else { bad_guesses++, sclock.l+=2; if (g[rI].l<=2 && g[rI].l && g[rI].u==0) tracing=breakpoint=true; g[rI]=incr(g[rI],-2); }"
page 385, replacement for line 9 (14 Aug 2011)***
if (xx<=11 && xx!=8) goto illegal_inst; /* can't change rN, rO, rS */
page 386, line 6 of section 101 (13 Oct 2001)
change "xx>=L" to "xx>G"
page 386, insert the following after line 8 of section 101, then delete line 7 (12 Jan 2002)***
if (((S-O-L)&lring_mask)==0) stack_store();
page 387, replacement for lines 5--7 (12 Jan 2002) and (02 Jun 2005)***
l[(O+L)&lring_mask].l=L, L++;
if (((S-O-L)&lring_mask)==0) stack_store();
O+=L; g[rO]=incr(g[rO],L<<3);
page 388, line 7 from the bottom (06 Sep 2013)
change "if (k==rZ+1) FOO;", where FOO is the long statement x.l=G=...=#3ffff, to "if (k==rZ+1) { FOO; if (G<32) x.l=G=g[rG].l=32; }"
page 389, line 17 (10 Oct 2001)
change "zz>6" to "zz>7"
page 389, line 4 of section 106 (02 Jun 05)
change "inst_ptr=z; break;" to "inst_ptr=z; case SWYM: break;"
page 393, lines 8 and 9 (03 May 2000)
change "int mmputchars" to "void mmputchars"
page 393, line 17 (29 Jul 2000)
omit "register tetra x;"
page 394, line 18 (24 Jul 2000)***
change "fgets(stdin_buf,256,stdin);" to "if (!fgets(stdin_buf,256,stdin)) panic("End of file on standard input; use the -f option, not <");"
page 395, replacement for line 7 (15 Feb 2002)***
g[255]=g[rJ];
if (op==TRIP) w=g[rW], x=g[rX], a=g[255];
page 396, new code to replace the former code for section 127 (10 Sep 2013)***
if sclock.l || sclock.h || !resuming) {
  sclock.h+=info[op].mems;
  sclock.l+=info[op].oops;
  if ((!loc.h&sign_bit)||(g[rU].h&0x8000))&&
      ((op&(g[rU].h>>16)))==(g[rU].h>>24)) {
    g[rU].l++; if (g[rU].l==0) {g[rU].h++; if ((g[rU].h&0x7fff)==0) g[rU].h-=0x80000;}
  }
  if (g[rI].l<=info[op].oops&&g[rI].l&&g[rI].h==0) tracing=breakpoint=true;
  g[rI]=incr(g[rI],-info[op].oops);
}
page 400, line 4 (05 Apr 2000)
change "\$1" to "$1"
page 400, line 11 (05 Apr 2000)
change "and^" to "and ^"
page 403, lines 9 and 10 (01 Jun 2011)***
change "g[rC]" to "sclock" (four times)
page 404, line 13 (29 Jul 2000)
change "main" to "int main"
page 404, new material after line 34 (12 Jan 2002)
"return g[255].l;" should be the final statement of "main"
page 404, new paragraph near the beginning of section 142 (28 Apr 2012)
We assume that argv[0] is never null. (The author believes strongly that the wizards who decided to allow argc=0 were mistaken when they defined the C89 standard; hence he has taken no pains to avoid system crashes when people try to invoke any of his programs with a null environment. Null invocations are contrary to the intent of C's designers.)
page 408, new line to follow line 34 (05 Apr 2000)
"rA<t>    set and/or show register rA in format t\n"
page 409, line 5 (24 Jul 2000)***
change "fclose(fake_stdin)" to "if (fake_stdin) fclose(fake_stdin)"
page 410, line 8 of section 150 (08 Mar 2012)
change "printf(command_buf)" to "printf("%s",command_buf)"
page 417, line 12 of section 163 (03 May 2000)
change "*cur_arg" to "(unsigned char *)*cur_arg"
page 417, mini-index entry for mmputchars (03 May 2000)
change "int" to "void"
page 418, line 2 (04 Jun 2011)
change "90" to "f0"
page 418, line 12 (30 Mar 2005)***
change "exit(1)" to "exit(0)"
page 423, line 16 (04 Sep 2001)
change "#12" to "#a"
page 424, line 6 of section 9 (30 Aug 2001)
change "location field" to "label field"
page 424, line 7 from the bottom (13 Oct 2001)
change "2F; 2H" to "2F ;2H"
page 426, line 12 (05 Apr 2000)
change "number''." to "number.''"
page 426, line 21 (15 Aug 2011)
change xy to x&y
page 426, line 25 (15 Aug 2011)
change xy to x|y
page 426, line 26 (23 Dec 1999)
change "exclusive or" to "exclusive-or"
page 427, line 4 from the bottom (05 Apr 2000)***
change "| <pseudo-operation>" to "| <alias operation> | <pseudo-operation>" and also add a new line: "<alias operation> --> SET | LDA"
page 428, line 10 (19 Mar 2001)
change the single-close-quote to a double-close-quote
page 428, line 16 from the bottom (13 Oct 2001)
change "when subtracted from the current location and divided by four" to "when the current location is subtracted from it and the result is divided by four"
page 437, line 2 (07 Apr 2000)
change "LDB $3,b,1, uses base address b" to "LDB $3,a,1, uses base address a"
page 437, lines 15 and 16 (05 Apr 2000)
add a right parenthesis at the end of both lines
page 437, line 20 (05 Apr 2000)
change "&b<<8" to "&a<<8"
page 438, line 24 (05 Apr 2000)
change italic Z to roman Z
page 438, line 26 (08 Mar 2013)
change "will either" to "will either be"
page 441, line 11 (13 Feb 2000)
change "tetrabytes makes" to "tetrabytes make"
page 443, line 7 of section 34 (30 Apr 2001)***
change "fgetc(src_file)" to "(j=fgetc(src_file))"
page 443, mini-index entry for fwprintf (29 Jul 2006)
change "multibyte``function" to "multibyte function"
page 444, line 3 (30 Apr 2001)***
change "do ... EOF)" to "while (j!='\n' && j!=EOF) j=fgetc(src_file)"
page 444, line 5 of section 37 (10 May 2000)
change "char" to "Char"
page 444, line 6 of section 38 (15 Aug 2011)***
change j=*p++-'0' to j=0
page 444, replacement for lines 14--18 of section 38 (15 Aug 2011)***
for (p++,k=0;*p && *p!='\"' && k<FILENAME_MAX; p++,k++)
  filename[filename_count][k]=*p;
if (k==FILENAME_MAX) panic("Capacity exceeded: File name too long");
if (*p=='\"' && *(p-1)!='\"') { /* yes, it's a line directive */
  filename[filename_count][k]='\0';
for (k=0;strcmp(filename[k],filename[filename_count])!=0;k++);
  if (k==filename_count) {
   if (filename_count==256) panic("Capacity exceeded: More than 256 file names");
   filename_count++;
  }
page 446, line 9 (29 Jul 2000)
omit "octa o;"
page 451, line 11 (29 Jul 2000)
change "j,k" to "j"
page 450, line 4 (10 May 2000)
change "(char,char,char)" to "(char,unsigned char,unsigned char)"
page 450, line 20 (10 May 2000)
change "char x,y,z;" to "char x; unsigned char y,z;"
page 451, line 12 (10 May 2000)
change "char" to "unsigned char"
page 454, line 5 (04 Jun 2011)***
change "c>126" to "(unsigned int)(c)>126"
page 454, line 14 (08 May 2013)
change "Char *p=s;" to "unsigned char *p=(unsigned char*)s"
page 454, line 17 (08 May 2013)
change "=p" to "=(Char*)p"
page 454, line 5 from the bottom (05 Apr 2000)
change "when are" to "when"
page 457, line 25 (10 May 2000)
change "char" to "Char"
page 460, lines 22 and 27 (10 May 2000)
change "char" to "Char"
page 463, lines 14 and 15 (29 Jul 2000)***
change "trie_node *" to "void" (twice)
page 470, lines 3 and 8 (29 Apr 2013)***
change *p to (unsigned char)*p
page 473, line 9 (15 Aug 2011)***
change "true" to "1"
page 476, line 10 from the bottom (10 Sep 2013)
new line "if (val_stack[0].state==undefined) err("the operand is undefined");
page 479, line 12 of section 116 (15 Aug 2011)***
change <Do a two-operand operation 124> to:
if ((op_bits&(three_arg_bit+mem_bit))==three_arg_bit) goto make_two_three;
<Do a two-operand operation 124>
make_two_three: val_stack[2]=val_stack[1], val_ptr=3;
val_stack[1].equiv=zero_octa, val_stack[1].link=NULL,
  val_stack[1].status=pure; /* insert 0 as the second operand */
page 484, new line to follow line 1 (11 Mar 2010)***
#define SETL 0xe3
page 484, line 14, formerly line 13 (11 Mar 2010)***
change "if (yz)" to "if (yz || j==SETL)"
page 488, line 6 from the bottom (12 Mar 2009)***
change "argv[j]+1" to "argv[j]+2"
page 494, new material after line 27 (07 Feb 2008)
"#include <stdlib.h>" and "#include <string.h>"
page 494, new material after line 32 (29 Jul 2000)
"return 0;" should be the final statement of "main"
page 495, line 2 (16 Sep 2001)
change "strcmp" to "strlen(prog_file_name)>4 && strcmp"
page 498, line 18 from the bottom (13 Feb 2000)
change "big-Endian" to "big-endian"
page 500, line 4 from the bottom (15 Jun 2002)***
change "#3692004" to "#369c2004"
page 501, the running headline (15 Mar 2000)
change "INTERACTION" to "BINARY INPUT TO MEMORY"
page 501, the mini-index (13 Feb 2000)***
GET=#fe, NEGI=#35, PUTI=#f7, RESUME=#f9, UNSAVE=#f6, all defined in MMIX-PIPE §47
page 502, new line to follow line 5 (19 Jul 2011)
$\bullet$ k: Toggle the sign bit of the instruction pointer.
page 503, new line to follow line 4 (19 Jul 2011)
printf(" k   to change the sign bit of the instruction location\n");
page 502, line 12 from the bottom (23 Mar 2004)***
change "printf("mmmix> ");" to "printf("mmmix> "); fflush(stdout);"
page 502, line 8 (13 Feb 2000)
change "2^48$." to "2^48; #80 shows details of branch prediction; #100 displays full cache contents including blocks with invalid tags."
page 502, replacement for line -3 (19 Jul 2011)
case '@': inst_ptr.o=read_hex(buffer+1); goto new_inst_ptr;
case 'k': inst_ptr.o.h^=0x80000000; /* shortcut to kernel mode */
  if (!ticks.l && head) head->loc.h^=0x80000000; /* fix the UNSAVE loc */
new_inst_ptr: if (inst_ptr.o.h&0x80000000)
  g[rK].o.h&=-2; /* disable interrupts on P_BIT */
  inst_ptr.p=NULL; continue;
page 503, line 33 (29 Jul 2000)
change "==-1" to "==(tetra)-1" (twice)
page 506, line 5 from the bottom (19 Jul 2011)
change 'k' to '!'
page 507, new material after line 10 (29 Jul 2000)
extern void MMIX_config ARGS ((char*));
page 510, new material after line 8 (29 Jul 2000)***
#include <string.h>
page 510, line 16 (29 Jul 2000)
change "j,k,delta" to "j,delta"
page 510, line 18 (29 Jul 2000)
omit "register tetra t;"
page 510, new material after line 24 (29 Jul 2000)
"return 0;" should be the final statement of "main"
page 514, line 16 (16 Mar 2001)
change "error" to "err"
page 516, line 8 (25 Aug 2000)***
change "read_tet(); cur_loc.h=(y<<24)+tet" to "j=y; read_tet(); cur_loc.h=(j<<24)+tet"
page 516, line 20 (25 Aug 2000)***
change "read_tet(); tmp.h=(y<<24)+tet" to "j=y; read_tet(); tmp.h=(j<<24)+tet"
page 516, line 6 from the bottom (26 Feb 2005)
this line, "if (z) ...", should move down to follow "cur_file=y;"
page 519, line 10 (11 Dec 2004)
change "%d!" to "%d!\n"
page 521, new line of code to follow line 21 (06 Aug 2001)***
equiv_buf[33-2*j]='\0';
pages 524--550 in general (06 Apr 2000)
uses of new types defined by typedef are not always indexed
pages 524--550 in general (02 Jan 2002)
a duplicate entry "MMIXAL 63" occurs in the index entries for BSPEC, BYTE, ESPEC, GREG, IS, LOC, LOCAL, OCTA, PREFIX, TETRA, WYDE
pages 525 and 534 (13 Feb 2000)
add "MMMIX 10" to the entries for big-endian and little-endian
pages 542 and 543 (26 Jan 2000)***
new entries: Rossmanith, Peter, MMIX-ARITH 26. Schwoon, Stefan, MMIX-ARITH 26.

(A few minor improvements have been made to the program documentation but not listed here. Furthermore -- sigh -- due to recent decisions of the committee revising IEEE standard floating point arithmetic, I've had to change "denormal" to "subnormal" in about three dozen places.)

With these corrections, I hope the book is now error-free. Alas, it probably isn't. Still, I've given it my best shot. The MMIX software dated 17 October 2013 represents the final and stable source files that I am able to work on myself, because I must devote full time henceforth to The Art of Computer Programming. Any remaining bugs should be considered "features" of this frozen version 1.0 of the software, to be worked-around as necessary but never to be corrected.

Further developments are being undertaken by an excellent group of volunteers in Germany, who have organized the MMIX home pages.

Special Offer (While Supplies Last)!

Anybody who discovers a genuine bug in the MMIX software will receive an MMIX T-shirt, courtesy of Addison-Wesley Publishing Company. Multiple bugs entitle you to multiple T-shirts. (You should send bug reports to Germany, as mentioned above, not to me. The people there will dispense one or more T-shirts, if they accept your contribution.) Please specify whether you prefer size L or XL.

Don Knuth's home page

Don Knuth's other books

Valid HTML 4.01 Transitional