image_bng.lbc

The implementation in Brevis, as it runs on the Serēnum operating system: one file holding the portable path and a hand-written path for each board — download, 154904 bytes, 3318 lines.

// image_bng.lbc -- BTPNGF1, the .bng lossless image format.
//
// One format, three implementations of it, selected at compile time and
// producing the same bytes:
//
//   the reference   portable Brevis, written to be read. What the format
//                   MEANS is what this code does.
//   SRISA1          the Allwinner D1 (XuanTie C906): the symbol loops in
//                   hand-written RISC-V, tables sized for that L1.
//   SRISA2          the VisionFive 2 Lite (SiFive U74): the same loops,
//                   shaped for a core that pays for a bigger table and
//                   predicts its branches.
//
// A caller that wants the reference anywhere says so at the import:
//
//   #invocā "../bng_format/image_bng.lbc" optiōnibus { NO_ASM; }
//
// and one that does not gets the tuned path on the two Serenum boards and
// the reference on everything else. The entry points are the same two
// names in every configuration: bng_encode and bng_decode.
//
// This file needs nothing beside it. Every table is carried here as a
// constant, so there is no companion to lose, no build step to call and no
// mutable global to race -- two harts may encode at once. The numbers come
// out of cōdex/tools/bng_tables.py, which derives all of them from the 144
// canonical code lengths and prints the declarations verbatim.
//
// THE FORMAT
//
//   container  20-byte header, then the body.
//                0      0xFF
//                1..6   "BTPNGF" in the Serenum clear encoding: 0E 38 30
//                       2A 1A 18
//                7      version, also clear: '1' = 0x01
//                8..11  width,  u32 little-endian
//                12..15 height, u32 little-endian
//                16..19 stream_byte_count, u32 little-endian. Bit 31 is
//                       the RAW flag; bits 0..30 are the length of the
//                       body, header NOT included. The whole file is
//                       20 + (count & 0x7FFFFFFF).
//              With bit 31 set the body is not a bitstream: it is the
//              XRGB8888 pixels themselves, row after row, 4wh bytes. That
//              is what bounds every file at 20 + 4wh -- the encoder emits
//              raw whenever the coded body would not be smaller.
//   pixels     XRGB8888: on a little-endian machine, the bytes B, G, R, X
//              in memory. X is coded like any other plane, so it round
//              trips exactly whether it carries alpha or padding.
//   colour     YCoCg-R, reversible, all four planes eight bits.
//   predict    MED (the LOCO-I/PNG Paeth-free predictor) per plane, with
//              the row above read as zeros for row 0 and the left sample
//              as zero at column 0.
//   order      Row-major, plane-minor: all four planes of row 0, then all
//              four of row 1.
//   alphabet   144 tokens: one zero, 126 signed magnitudes 1..63, four
//              exponent tokens for 64..255 with mantissa bits, one
//              end-of-row, twelve zero-run lengths.
//   code       ONE canonical Huffman code, max length 12, frozen in
//              bng_lengths.bin, from which every table here comes.
//              Nothing about the model is transmitted.
//              Bits MSB-first, token then mantissa, last byte zero-padded.
//
// The spec is bng_spec.txt and the C reference is bng_reference.h; all of
// them agree byte for byte, which is checked rather than assumed.

#vulgā prius P4_TDIR  = 63;
#vulgā prius P4_KEXP  = 6;
#vulgā prius P4_ALPHA = 144;
#vulgā prius P4_EOL   = 131;          // 2*TDIR + 1 + 2*(8 - KEXP)
#vulgā prius P4_RUN   = 132;
#vulgā prius P4_MAXLEN = 12;
#vulgā prius P4_VERSION = 0x01;       // '1' in the clear encoding
#vulgā prius P4_HEADER = 20;
// Bit 31 of stream_byte_count says the body is not a bitstream at all but
// the XRGB8888 pixels themselves, row after row. That is what bounds a
// file at 20 + 4wh.
#vulgā prius P4_RAW_FLAG = 0x80000000;
#vulgā prius P4_COUNT_MASK = 0x7FFFFFFF;
// Byte offsets inside one XRGB8888 pixel, little-endian.
#vulgā prius P4_B = 0;
#vulgā prius P4_G = 1;
#vulgā prius P4_R = 2;
#vulgā prius P4_X = 3;
// The longest codeword is twelve bits and the widest mantissa seven, so
// four planes cost at most 76 bits per pixel. The reference encoder sizes
// its buffer with this and falls back to a raw body when the coded one
// would not be smaller, which is what bounds a file at 20 + 4wh.
#vulgā prius P4_WORST_BYTES_PER_PIXEL = 10;

#vulgā prōcēdūra p4_u32([]n8 s; n64 at; -> n64;) {
   #refer (n64)s[at]% | ((n64)s[at + 1]% << 8) | ((n64)s[at + 2]% << 16) |
          ((n64)s[at + 3]% << 24);
}

#vulgā prōcēdūra p4_put_u32([]n8 d; n64 at; n64 v;) {
   d[at]% = (n8)(v & 0xFF);
   d[at + 1]% = (n8)((v >> 8) & 0xFF);
   d[at + 2]% = (n8)((v >> 16) & 0xFF);
   d[at + 3]% = (n8)((v >> 24) & 0xFF);
}

#vulgā prōcēdūra p4_put_magic([]n8 d;) {
   d[0]% = 0xFF;
   d[1]% = 0x0E; d[2]% = 0x38; d[3]% = 0x30;
   d[4]% = 0x2A; d[5]% = 0x1A; d[6]% = 0x18;
   d[7]% = (n8)P4_VERSION;
}

#vulgā prōcēdūra p4_magic_ok([]n8 s; -> n64;) {
   sī s.m < P4_HEADER { #refer 0; }
   sī s[0]% != 0xFF { #refer 0; }
   sī s[1]% != 0x0E || s[2]% != 0x38 || s[3]% != 0x30 { #refer 0; }
   sī s[4]% != 0x2A || s[5]% != 0x1A || s[6]% != 0x18 { #refer 0; }
   sī s[7]% != P4_VERSION { #refer 0; }
   #refer 1;
}

#sī (NO_ASM | (^TARGET_CPU_RV_SRISA1 & ^TARGET_CPU_RV_SRISA2))

// ===================================================== the reference
//
// Portable Brevis, and the arbiter of what the bytes mean. Nothing here is
// hoisted, unrolled or table-driven beyond what the format itself
// mandates. Arrays are file-scope because a fixed-size LOCAL array makes
// the compiler address the whole stack frame through lui+add pairs.

// ---------------------------------------------------------------- tables
//
// Carried, not built. p4_code/p4_clen give a token its codeword;
// first/count/base and p4_sym describe the same code by length, which is
// all the decoder needs. p4_tbase/p4_tbits/p4_tkind are the alphabet
// itself. cōdex/tools/bng_tables.py derives every one of them from the 144
// canonical code lengths and prints exactly what is below, which is the
// only place the derivation is written down now.

commūnis [144]n32 p4_code = n32.[
   0x0000, 0x0001, 0x0002, 0x0006, 0x0007, 0x0008, 0x0009, 0x0016,
   0x0017, 0x0030, 0x0031, 0x0032, 0x0033, 0x006A, 0x006B, 0x006C,
   0x006D, 0x006E, 0x006F, 0x00E6, 0x00E7, 0x00E8, 0x00E9, 0x00EA,
   0x00EB, 0x00EC, 0x00ED, 0x01DE, 0x01DF, 0x01E0, 0x01E1, 0x01E2,
   0x01E3, 0x01E4, 0x01E5, 0x01E6, 0x01E7, 0x03D4, 0x03D5, 0x03D6,
   0x03D7, 0x03D8, 0x03D9, 0x03DA, 0x03DB, 0x03DC, 0x03DD, 0x03DE,
   0x03DF, 0x03E0, 0x03E1, 0x03E2, 0x03E3, 0x07CC, 0x07CD, 0x07CE,
   0x07CF, 0x07D0, 0x07D1, 0x07D2, 0x07D3, 0x07D4, 0x07D5, 0x07D6,
   0x07D7, 0x07D8, 0x07D9, 0x07DA, 0x07DB, 0x07DC, 0x07DD, 0x07DE,
   0x07DF, 0x0FC6, 0x0FC7, 0x0FC8, 0x0FC9, 0x0FCA, 0x0FCB, 0x0FCC,
   0x0FCD, 0x0FCE, 0x0FCF, 0x0FD0, 0x0FD1, 0x0FD2, 0x0FD3, 0x0FD4,
   0x0FD5, 0x0FD6, 0x0FD7, 0x0FD8, 0x0FD9, 0x0FDA, 0x0FDB, 0x0FDC,
   0x0FDD, 0x0FDE, 0x0FDF, 0x0FE0, 0x0FE1, 0x0FE2, 0x0FE3, 0x0FE4,
   0x0FE5, 0x0FE6, 0x0FE7, 0x0FE8, 0x0FE9, 0x0FEA, 0x0FEB, 0x0FEC,
   0x0FED, 0x0FEE, 0x0FEF, 0x0FF0, 0x0FF1, 0x0FF2, 0x0FF3, 0x0FF4,
   0x0FF5, 0x0FF6, 0x0FF7, 0x0FF8, 0x0FF9, 0x07E0, 0x0FFA, 0x0070,
   0x0071, 0x0FFB, 0x07E1, 0x01E8, 0x000A, 0x0034, 0x0072, 0x00EE,
   0x01E9, 0x03E4, 0x03E5, 0x07E2, 0x0FFC, 0x0FFD, 0x0FFE, 0x0FFF,
];
commūnis [144]n8 p4_clen = n8.[
   0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07,
   0x07, 0x07, 0x07, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x09, 0x09,
   0x09, 0x09, 0x09, 0x09, 0x09, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
   0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B,
   0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
   0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
   0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
   0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0B, 0x0C, 0x07,
   0x07, 0x0C, 0x0B, 0x09, 0x04, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0A, 0x0B, 0x0C, 0x0C, 0x0C, 0x0C,
];
commūnis [144]n8 p4_sym = n8.[
   0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x84, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x85, 0x0D,
   0x0E, 0x0F, 0x10, 0x11, 0x12, 0x7F, 0x80, 0x86, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A,
   0x87, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x83, 0x88, 0x25, 0x26, 0x27,
   0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x89, 0x8A, 0x35,
   0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45,
   0x46, 0x47, 0x48, 0x7D, 0x82, 0x8B, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52,
   0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62,
   0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72,
   0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7E, 0x81, 0x8C, 0x8D, 0x8E, 0x8F,
];
commūnis [144]s64 p4_tbase = s64.[
   0x0000, 0x0001, 0x0001, 0x0002, 0x0002, 0x0003, 0x0003, 0x0004,
   0x0004, 0x0005, 0x0005, 0x0006, 0x0006, 0x0007, 0x0007, 0x0008,
   0x0008, 0x0009, 0x0009, 0x000A, 0x000A, 0x000B, 0x000B, 0x000C,
   0x000C, 0x000D, 0x000D, 0x000E, 0x000E, 0x000F, 0x000F, 0x0010,
   0x0010, 0x0011, 0x0011, 0x0012, 0x0012, 0x0013, 0x0013, 0x0014,
   0x0014, 0x0015, 0x0015, 0x0016, 0x0016, 0x0017, 0x0017, 0x0018,
   0x0018, 0x0019, 0x0019, 0x001A, 0x001A, 0x001B, 0x001B, 0x001C,
   0x001C, 0x001D, 0x001D, 0x001E, 0x001E, 0x001F, 0x001F, 0x0020,
   0x0020, 0x0021, 0x0021, 0x0022, 0x0022, 0x0023, 0x0023, 0x0024,
   0x0024, 0x0025, 0x0025, 0x0026, 0x0026, 0x0027, 0x0027, 0x0028,
   0x0028, 0x0029, 0x0029, 0x002A, 0x002A, 0x002B, 0x002B, 0x002C,
   0x002C, 0x002D, 0x002D, 0x002E, 0x002E, 0x002F, 0x002F, 0x0030,
   0x0030, 0x0031, 0x0031, 0x0032, 0x0032, 0x0033, 0x0033, 0x0034,
   0x0034, 0x0035, 0x0035, 0x0036, 0x0036, 0x0037, 0x0037, 0x0038,
   0x0038, 0x0039, 0x0039, 0x003A, 0x003A, 0x003B, 0x003B, 0x003C,
   0x003C, 0x003D, 0x003D, 0x003E, 0x003E, 0x003F, 0x003F, 0x0040,
   0x0040, 0x0080, 0x0080, 0x2000, 0x0002, 0x0004, 0x0008, 0x0010,
   0x0020, 0x0040, 0x0080, 0x0100, 0x0200, 0x0400, 0x0800, 0x1000,
];
commūnis [144]n8 p4_tbits = n8.[
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06,
   0x06, 0x07, 0x07, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C,
];
commūnis [144]n8 p4_tkind = n8.[
   0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
   0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
   0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
   0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
   0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
   0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
   0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
   0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
   0x01, 0x00, 0x01, 0x02, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
];
commūnis [16]s64 p4_first = s64.[
   0x0000, 0x0000, 0x0000, 0x0000, 0x0006, 0x0016, 0x0030, 0x006A,
   0x00E6, 0x01DE, 0x03D4, 0x07CC, 0x0FC6, 0x0000, 0x0000, 0x0000,
];
commūnis [16]s64 p4_count = s64.[
   0x0000, 0x0000, 0x0000, 0x0003, 0x0005, 0x0002, 0x0005, 0x0009,
   0x0009, 0x000C, 0x0012, 0x0017, 0x003A, 0x0000, 0x0000, 0x0000,
];
commūnis [16]s64 p4_base = s64.[
   0x0000, 0x0000, 0x0000, 0x0000, 0x0003, 0x0008, 0x000A, 0x000F,
   0x0018, 0x0021, 0x002D, 0x003F, 0x0056, 0x0000, 0x0000, 0x0000,
];

// ------------------------------------------------------- colour, predict

#vulgā prōcēdūra p4_med(s64 L; s64 T; s64 TL; -> s64;) {
   s64 mn = L; sī T < mn { mn = T; }
   s64 mx = L; sī T > mx { mx = T; }
   s64 g = L + T - TL;
   sī g < mn { g = mn; }
   sī g > mx { g = mx; }
   #refer g;
}

// arithmetic shift right by one of a byte read as int8
#vulgā prōcēdūra p4_sra1(n64 v; -> s64;) {
   s64 s = (s64)(v & 0xFF);
   sī s >= 128 { s -= 256; }
   #refer s >> 1;
}

prōcēdūra p4_to_ycocg(n64 r; n64 g; n64 b; -> n64; n64; n64;) {
   n64 co = (r - b) & 0xFF;
   n64 t  = (n64)((s64)b + p4_sra1(co,)) & 0xFF;
   n64 cg = (g - t) & 0xFF;
   n64 y  = (n64)((s64)t + p4_sra1(cg,)) & 0xFF;
   #refer (y, co, cg,);
}

prōcēdūra p4_from_ycocg(n64 y; n64 co; n64 cg; -> n64; n64; n64;) {
   n64 t = (n64)((s64)y - p4_sra1(cg,)) & 0xFF;
   n64 g = (cg + t) & 0xFF;
   n64 b = (n64)((s64)t - p4_sra1(co,)) & 0xFF;
   n64 r = (b + co) & 0xFF;
   #refer (r, g, b,);
}

#vulgā prōcēdūra p4_log2(n64 v; -> n64;) {
   n64 e = 0;
   dum (v >> (e + 1)) != 0 { e += 1; }
   #refer e;
}

// ---------------------------------------------------------------- bit i/o
//
// State is passed explicitly and returned. Globals would force a memory
// round trip on every symbol, which is exactly the register-allocation
// problem PGO cannot repair once the values leave the procedure.

// Writes whole bytes as they fall out. `at` keeps counting past the end of
// the buffer, so the caller detects overflow by comparing it with d.m.
prōcēdūra p4_put([]n8 d; n64 at; n64 acc; n64 nb; n64 code; n64 len;
                 -> n64; n64; n64;) {
   sī len == 0 { #refer (at, acc, nb,); }
   acc = (acc << len) | code;
   nb += len;
   dum nb >= 8 {
      nb -= 8;
      sī at < d.m { d[at]% = (n8)((acc >> nb) & 0xFF); }
      at += 1;
   }
   #refer (at, acc, nb,);
}

prōcēdūra p4_flush([]n8 d; n64 at; n64 acc; n64 nb; -> n64;) {
   sī nb != 0 {
      sī at < d.m { d[at]% = (n8)((acc << (8 - nb)) & 0xFF); }
      at += 1;
   }
   #refer at;
}

// Past the end the reader shifts in zeros: the final byte is padded, so a
// legitimate last symbol can want bits that were never written. Only
// sustained padding means the file is truncated, which the caller checks
// once per image rather than once per bit.
prōcēdūra p4_bit([]n8 s; n64 at; n64 end; n64 acc; n64 nb;
                 -> n64; n64; n64; n64;) {
   sī nb == 0 {
      n64 by = 0;
      sī at < end { by = (n64)s[at]%; }
      at += 1;
      acc = by;
      nb = 8;
   }
   nb -= 1;
   #refer ((acc >> nb) & 1, at, acc, nb,);
}

// Walk the code one bit at a time against the boundaries for each length.
// No decode table: this is the definition an optimized decoder replaces.
// Returns P4_ALPHA when nothing matches, which cannot happen on a
// well-formed stream because the code is complete.
prōcēdūra p4_symbol([]n8 s; n64 at; n64 end; n64 acc; n64 nb;
                    -> n64; n64; n64; n64;) {
   n64 code = 0;
   n64 sym = P4_ALPHA;
   dum n64 L = 1; L <= P4_MAXLEN {
      n64 b;
      (b, at, acc, nb,) = p4_bit(s, at, end, acc, nb,);
      code = (code << 1) | b;
      sī (s64)code - p4_first[L]% < p4_count[L]% {
         sym = (n64)p4_sym[(n64)(p4_base[L]% + (s64)code - p4_first[L]%)]%;
         #dēsine;
      }
      L += 1;
   }
   #refer (sym, at, acc, nb,);
}

// ================================================================= encode

// One row of one plane: tokens for w samples, in order.
prōcēdūra p4_encode_row([]n8 d; n64 at; n64 acc; n64 nb; []s8 rc; n64 w;
                        -> n64; n64; n64;) {
   n64 x = 0;
   dum x < w {
      s64 e = (s64)rc[x]%;
      sī e != 0 {
         n64 a = (n64)e;
         sī e < 0 { a = (n64)(0 - e); }
         sī a <= P4_TDIR {
            n64 tk = 2 * a - 1;
            sī e < 0 { tk += 1; }
            (at, acc, nb,) = p4_put(d, at, acc, nb, (n64)p4_code[tk]%, (n64)p4_clen[tk]%,);
         } nisī {
            n64 ex = p4_log2(a,);
            n64 tk = 2 * P4_TDIR + 1 + 2 * (ex - P4_KEXP);
            sī e < 0 { tk += 1; }
            (at, acc, nb,) = p4_put(d, at, acc, nb, (n64)p4_code[tk]%, (n64)p4_clen[tk]%,);
            (at, acc, nb,) = p4_put(d, at, acc, nb, a - (1 << ex), ex,);
         }
         x += 1;
      } nisī {
         n64 run = 1;
         dum x + run < w && rc[x + run]% == 0 { run += 1; }
         sī x + run == w {
            // the rest of the row is zero, however long it is
            (at, acc, nb,) = p4_put(d, at, acc, nb, (n64)p4_code[P4_EOL]%, (n64)p4_clen[P4_EOL]%,);
            x = w;
         } aliter sī run == 1 {
            (at, acc, nb,) = p4_put(d, at, acc, nb, (n64)p4_code[0]%, (n64)p4_clen[0]%,);
            x += 1;
         } nisī {
            sī run > 8191 { run = 8191; }
            n64 j = p4_log2(run,);
            n64 tk = P4_RUN + j - 1;
            (at, acc, nb,) = p4_put(d, at, acc, nb, (n64)p4_code[tk]%, (n64)p4_clen[tk]%,);
            (at, acc, nb,) = p4_put(d, at, acc, nb, run - (1 << j), j,);
            x += run;
         }
      }
   }
   #refer (at, acc, nb,);
}

// Encode the body into `body`, returning the number of bytes it needs.
// That may exceed body.m: p4_put keeps counting what it cannot store, so
// an overflow tells the caller exactly how much to allocate.
prōcēdūra p4_encode_into([]n8 body; []n8 px; n64 w; n64 h; n64 pitch;
                         []n8 pix; []s8 rr; -> n64;) {
   n64 at = 0; n64 acc = 0; n64 nb = 0;
   dum n64 i = 0; i < 8 * w { pix[i]% = 0; i += 1; }

   dum n64 y = 0; y < h {
      n64 rowoff = y * pitch;
      n64 cb = (y & 1) * (4 * w);          // this row's samples
      n64 pb = (1 - (y & 1)) * (4 * w);    // the row above

      dum n64 x = 0; x < w {
         n64 yy; n64 co; n64 cg;
         (yy, co, cg,) = p4_to_ycocg((n64)px[rowoff + x * 4 + P4_R]%,
                                     (n64)px[rowoff + x * 4 + P4_G]%,
                                     (n64)px[rowoff + x * 4 + P4_B]%,);
         pix[cb + x]% = (n8)yy;
         pix[cb + w + x]% = (n8)co;
         pix[cb + 2 * w + x]% = (n8)cg;
         pix[cb + 3 * w + x]% = px[rowoff + x * 4 + P4_X]%;
         x += 1;
      }

      dum n64 p = 0; p < 4 {
         n64 co = p * w;
         n64 c0 = cb + co;
         n64 p0 = pb + co;
         sī y == 0 {
            rr[co]% = (s8)pix[c0]%;
            dum n64 x = 1; x < w {
               rr[co + x]% = (s8)(((n64)pix[c0 + x]% - (n64)pix[c0 + x - 1]%) & 0xFF);
               x += 1;
            }
         } nisī {
            rr[co]% = (s8)(((n64)pix[c0]% - (n64)pix[p0]%) & 0xFF);
            dum n64 x = 1; x < w {
               s64 L = (s64)pix[c0 + x - 1]%;
               s64 T = (s64)pix[p0 + x]%;
               s64 TL = (s64)pix[p0 + x - 1]%;
               rr[co + x]% = (s8)(((n64)pix[c0 + x]% - (n64)p4_med(L, T, TL,)) & 0xFF);
               x += 1;
            }
         }
         p += 1;
      }
      dum n64 p = 0; p < 4 {
         []s8 one; one.i = rr.i + (@s8)(p * w); one.m = w;
         (at, acc, nb,) = p4_encode_row(body, at, acc, nb, one, w,);
         p += 1;
      }
      y += 1;
   }
   #refer p4_flush(body, at, acc, nb,);
}

// bng_encode(px, w, h) -> (file, ok). The file is allocated on
// situla_data and survives the call; the row scratch comes out of a
// transient situla and dies on return.
// pitch is the source's row stride in bytes, so a caller can encode a
// SUB-RECTANGLE of a framebuffer -- a cropped screenshot -- by pointing px
// at the crop's first pixel and passing the surface's own stride.
#vulgā prōcēdūra bng_encode([]n8 px; n64 w; n64 h; n64 pitch;
                                -> []n8; n64;) {
   #situla trānsitōria: temp_sit;
   []n8 none;
   sī w == 0 || h == 0 { #refer (none, 0,); }
   n64 n = w * h;
   sī pitch < w * 4 { #refer (none, 0,); }
   sī px.m < (h - 1) * pitch + w * 4 { #refer (none, 0,); }

   []n8 pix = situlā_adlocā<n8,>(temp_sit, 8 * w,);
   []s8 rr  = situlā_adlocā<s8,>(temp_sit, 4 * w,);

   // The ordinary size first. Only an image that codes larger than its own
   // pixels pays for a second pass, and no real one does -- the worst of
   // 2848 corpus images was 26.7 of the 32 bits a pixel costs raw.
   // Capped at what raw would cost: a body that reaches that has lost.
   n64 cap = 4 * n;
   []n8 dst = situlā_adlocā<n8,>(circum.situla_data%, P4_HEADER + cap,);
   []n8 body; body.i = dst.i + (@n8)P4_HEADER; body.m = cap;
   n64 at = p4_encode_into(body, px, w, h, pitch, pix, rr,);

   p4_put_magic(dst,);
   p4_put_u32(dst, 8, w,);
   p4_put_u32(dst, 12, h,);
   sī at >= cap {
      // The pixels themselves, row after row. Only noise gets here, and it
      // is what bounds every file at 20 + 4wh.
      dum n64 y = 0; y < h {
         dum n64 i = 0; i < w * 4 {
            dst[P4_HEADER + y * w * 4 + i]% = px[y * pitch + i]%;
            i += 1;
         }
         y += 1;
      }
      p4_put_u32(dst, 16, cap | P4_RAW_FLAG,);
      #refer (dst[0:P4_HEADER + cap], 1,);
   }
   p4_put_u32(dst, 16, at,);          // stream_byte_count, raw bit clear
   #refer (dst[0:P4_HEADER + at], 1,);
}

// ================================================================= decode

// One row of one plane: w residual samples. Runs write nothing, so the row
// is cleared first. Returns (ok, at, acc, nb).
prōcēdūra p4_decode_row([]n8 s; n64 at; n64 end; n64 acc; n64 nb; []s8 rc;
                        n64 w; -> n64; n64; n64; n64;) {
   dum n64 i = 0; i < w { rc[i]% = 0; i += 1; }
   n64 x = 0;
   n64 ok = 1;
   dum x < w {
      n64 tk;
      (tk, at, acc, nb,) = p4_symbol(s, at, end, acc, nb,);
      sī tk >= P4_ALPHA { ok = 0; #dēsine; }
      n64 mb = (n64)p4_tbits[tk]%;
      n64 m = 0;
      dum n64 i = 0; i < mb {
         n64 b;
         (b, at, acc, nb,) = p4_bit(s, at, end, acc, nb,);
         m = (m << 1) | b;
         i += 1;
      }
      s64 v = p4_tbase[tk]% + (s64)m;
      n64 kind = (n64)p4_tkind[tk]%;
      sī kind < 2 {
         s64 val = v;
         sī kind == 1 { val = 0 - v; }
         rc[x]% = (s8)val;
         x += 1;
      } nisī {
         // end of row and zero run differ only in how far they reach
         n64 adv = (n64)v;
         sī adv > w - x { adv = w - x; }
         sī adv == 0 { ok = 0; #dēsine; }
         x += adv;
      }
   }
   #refer (ok, at, acc, nb,);
}

// bng_decode(file) -> (rgba, w, h, ok). The RGBA buffer is allocated
// on situla_data; every working buffer is transient.
#vulgā prōcēdūra bng_decode([]n8 src; -> []n8; n64; n64; n64;) {
   #situla trānsitōria: temp_sit;
   []n8 none;
   sī p4_magic_ok(src,) == 0 { #refer (none, 0, 0, 0,); }
   n64 w = p4_u32(src, 8,);
   n64 h = p4_u32(src, 12,);
   n64 count_field = p4_u32(src, 16,);
   n64 raw = count_field & P4_RAW_FLAG;
   n64 stream_byte_count = count_field & P4_COUNT_MASK;
   sī w == 0 || h == 0 || w > 65535 || h > 65535 { #refer (none, 0, 0, 0,); }
   n64 n = w * h;
   // The header says how long the body is, so a short file is a comparison
   // rather than a guess about padding, and whatever follows belongs to the
   // next image in the stream.
   sī stream_byte_count > src.m - P4_HEADER { #refer (none, 0, 0, 0,); }
   sī raw != 0 {
      // Bit 31: the body is the XRGB8888 pixels themselves, packed.
      sī stream_byte_count != 4 * n { #refer (none, 0, 0, 0,); }
      []n8 rawpx = situlā_adlocā<n8,>(circum.situla_data%, 4 * n,);
      dum n64 i = 0; i < 4 * n { rawpx[i]% = src[P4_HEADER + i]%; i += 1; }
      #refer (rawpx, w, h, 1,);
   }
   sī stream_byte_count * 8 < h { #refer (none, 0, 0, 0,); }

   []n8 dst = situlā_adlocā<n8,>(circum.situla_data%, 4 * n,);
   // Both row parities in one buffer; see the note in bng_encode.
   []n8 pix = situlā_adlocā<n8,>(temp_sit, 8 * w,);
   []s8 rr  = situlā_adlocā<s8,>(temp_sit, 4 * w,);
   dum n64 i = 0; i < 8 * w { pix[i]% = 0; i += 1; }

   n64 at = P4_HEADER;
   n64 end = P4_HEADER + stream_byte_count;
   n64 acc = 0;
   n64 nb = 0;
   n64 ok = 1;

   dum n64 y = 0; y < h {
      n64 cb = (y & 1) * (4 * w);
      n64 pb = (1 - (y & 1)) * (4 * w);
      dum n64 p = 0; p < 4 {
         n64 co = p * w;
         n64 c0 = cb + co;
         n64 p0 = pb + co;
         []s8 one; one.i = rr.i + (@s8)co; one.m = w;
         n64 rok;
         (rok, at, acc, nb,) = p4_decode_row(src, at, end, acc, nb, one, w,);
         sī rok == 0 { ok = 0; }

         // residual + prediction, the encoder's step run backwards
         sī y == 0 {
            n64 run = 0;
            dum n64 x = 0; x < w {
               run = (run + (n64)(s64)rr[co + x]%) & 0xFF;
               pix[c0 + x]% = (n8)run;
               x += 1;
            }
         } nisī {
            pix[c0]% = (n8)(((n64)pix[p0]% + (n64)(s64)rr[co]%) & 0xFF);
            dum n64 x = 1; x < w {
               s64 L = (s64)pix[c0 + x - 1]%;
               s64 T = (s64)pix[p0 + x]%;
               s64 TL = (s64)pix[p0 + x - 1]%;
               pix[c0 + x]% = (n8)(((n64)p4_med(L, T, TL,) + (n64)(s64)rr[co + x]%) & 0xFF);
               x += 1;
            }
         }
         p += 1;
      }
      sī ok == 0 { #dēsine; }

      n64 rowoff = (y * w) * 4;
      dum n64 x = 0; x < w {
         n64 r; n64 g; n64 b;
         (r, g, b,) = p4_from_ycocg((n64)pix[cb + x]%, (n64)pix[cb + w + x]%,
                                    (n64)pix[cb + 2 * w + x]%,);
         dst[rowoff + x * 4 + P4_R]% = (n8)r;
         dst[rowoff + x * 4 + P4_G]% = (n8)g;
         dst[rowoff + x * 4 + P4_B]% = (n8)b;
         dst[rowoff + x * 4 + P4_X]% = pix[cb + 3 * w + x]%;
         x += 1;
      }
      y += 1;
   }

   // Sustained padding past the end means the stream was truncated.
   sī at > end + 16 { ok = 0; }
   sī ok == 0 { #refer (none, 0, 0, 0,); }
   #refer (dst, w, h, 1,);
}

#fīnis

#sī (TARGET_CPU_RV_SRISA1 & ^NO_ASM)

// ============================= SRISA1: the Allwinner D1 (C906)
//
// The two machines disagree about what the decoder should look like, and
// the disagreement is measured rather than assumed -- which is why this
// section and the next are not one body with a flag in it.
//
//   An EIGHT-BIT root table with 16-entry escape blocks: 1 KiB plus 4 KiB.
// Twelve bits direct is one load and no branch and it is 7.6% SLOWER
// here -- 16 KiB of table does not fit beside the row buffers in this
// core's L1.
//
// The bytes are identical to the reference above; only the shape of the
// work differs.
//
// Measured on the board at 768x512, best of three:
//                  encode   decode
//   photograph      5079     4187  KP/s
//   screenshot      9203     7305

// The tables are carried, not built: cōdex/tools/bng_tables.py derives them
// from the 144 canonical code lengths and prints what is below. Nothing
// runs before the first image and there is no state to race.
//
// A root entry is
//   bits 0..13  base   14..17 nbits   18..21 len (0 = escape)
//   bits 22..23 kind   24..29 escape block   30 escape-present
//
// Measured on this core: 8-bit root 3252 KP/s, 10-bit 3223, 12-bit
// direct 3005. The C906 wants the SMALL table even though the big one
// removes a dependent load -- 1 KiB of root plus 4 KiB of escapes stays
// resident beside the row buffers where 16 KiB does not.
commūnis [256]n32 p4f_root = n32.[
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002,
   0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002,
   0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00500002, 0x00500002,
   0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002,
   0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002,
   0x00500002, 0x00500002, 0x00100003, 0x00100003, 0x00100003, 0x00100003,
   0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003,
   0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003,
   0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003,
   0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003,
   0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00D04002, 0x00D04002,
   0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002,
   0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002,
   0x00D04002, 0x00D04002, 0x00140004, 0x00140004, 0x00140004, 0x00140004,
   0x00140004, 0x00140004, 0x00140004, 0x00140004, 0x00540004, 0x00540004,
   0x00540004, 0x00540004, 0x00540004, 0x00540004, 0x00540004, 0x00540004,
   0x00180005, 0x00180005, 0x00180005, 0x00180005, 0x00580005, 0x00580005,
   0x00580005, 0x00580005, 0x00180006, 0x00180006, 0x00180006, 0x00180006,
   0x00580006, 0x00580006, 0x00580006, 0x00580006, 0x00D88004, 0x00D88004,
   0x00D88004, 0x00D88004, 0x001C0007, 0x001C0007, 0x005C0007, 0x005C0007,
   0x001C0008, 0x001C0008, 0x005C0008, 0x005C0008, 0x001C0009, 0x001C0009,
   0x005C0009, 0x005C0009, 0x001D8040, 0x001D8040, 0x005D8040, 0x005D8040,
   0x00DCC008, 0x00DCC008, 0x0020000A, 0x0060000A, 0x0020000B, 0x0060000B,
   0x0020000C, 0x0060000C, 0x0020000D, 0x0060000D, 0x00E10010, 0x40000000,
   0x41000000, 0x42000000, 0x43000000, 0x44000000, 0x50000000, 0x45000000,
   0x46000000, 0x47000000, 0x48000000, 0x49000000, 0x4A000000, 0x4B000000,
   0x4C000000, 0x4D000000, 0x4E000000, 0x4F000000,
];
commūnis [1024]n32 p4f_sub = n32.[
   0x0024000E, 0x0024000E, 0x0024000E, 0x0024000E, 0x0024000E, 0x0024000E,
   0x0024000E, 0x0024000E, 0x0064000E, 0x0064000E, 0x0064000E, 0x0064000E,
   0x0064000E, 0x0064000E, 0x0064000E, 0x0064000E, 0x0024000F, 0x0024000F,
   0x0024000F, 0x0024000F, 0x0024000F, 0x0024000F, 0x0024000F, 0x0024000F,
   0x0064000F, 0x0064000F, 0x0064000F, 0x0064000F, 0x0064000F, 0x0064000F,
   0x0064000F, 0x0064000F, 0x00240010, 0x00240010, 0x00240010, 0x00240010,
   0x00240010, 0x00240010, 0x00240010, 0x00240010, 0x00640010, 0x00640010,
   0x00640010, 0x00640010, 0x00640010, 0x00640010, 0x00640010, 0x00640010,
   0x00240011, 0x00240011, 0x00240011, 0x00240011, 0x00240011, 0x00240011,
   0x00240011, 0x00240011, 0x00640011, 0x00640011, 0x00640011, 0x00640011,
   0x00640011, 0x00640011, 0x00640011, 0x00640011, 0x00240012, 0x00240012,
   0x00240012, 0x00240012, 0x00240012, 0x00240012, 0x00240012, 0x00240012,
   0x00640012, 0x00640012, 0x00640012, 0x00640012, 0x00640012, 0x00640012,
   0x00640012, 0x00640012, 0x00280013, 0x00280013, 0x00280013, 0x00280013,
   0x00680013, 0x00680013, 0x00680013, 0x00680013, 0x00280014, 0x00280014,
   0x00280014, 0x00280014, 0x00680014, 0x00680014, 0x00680014, 0x00680014,
   0x00280015, 0x00280015, 0x00280015, 0x00280015, 0x00680015, 0x00680015,
   0x00680015, 0x00680015, 0x00280016, 0x00280016, 0x00280016, 0x00280016,
   0x00680016, 0x00680016, 0x00680016, 0x00680016, 0x00280017, 0x00280017,
   0x00280017, 0x00280017, 0x00680017, 0x00680017, 0x00680017, 0x00680017,
   0x00280018, 0x00280018, 0x00280018, 0x00280018, 0x00680018, 0x00680018,
   0x00680018, 0x00680018, 0x00280019, 0x00280019, 0x00280019, 0x00280019,
   0x00680019, 0x00680019, 0x00680019, 0x00680019, 0x0028001A, 0x0028001A,
   0x0028001A, 0x0028001A, 0x0068001A, 0x0068001A, 0x0068001A, 0x0068001A,
   0x00E98040, 0x00E98040, 0x00E98040, 0x00E98040, 0x00E9C080, 0x00E9C080,
   0x00E9C080, 0x00E9C080, 0x002C001B, 0x002C001B, 0x006C001B, 0x006C001B,
   0x002C001C, 0x002C001C, 0x006C001C, 0x006C001C, 0x002C001D, 0x002C001D,
   0x006C001D, 0x006C001D, 0x002C001E, 0x002C001E, 0x006C001E, 0x006C001E,
   0x002C001F, 0x002C001F, 0x006C001F, 0x006C001F, 0x002C0020, 0x002C0020,
   0x006C0020, 0x006C0020, 0x002C0021, 0x002C0021, 0x006C0021, 0x006C0021,
   0x002C0022, 0x002C0022, 0x006C0022, 0x006C0022, 0x002C0023, 0x002C0023,
   0x006C0023, 0x006C0023, 0x002C0024, 0x002C0024, 0x006C0024, 0x006C0024,
   0x002C003F, 0x002C003F, 0x006DC080, 0x006DC080, 0x00EE0100, 0x00EE0100,
   0x00300025, 0x00700025, 0x00300026, 0x00700026, 0x00300027, 0x00700027,
   0x00300028, 0x00700028, 0x00300029, 0x00700029, 0x0030002A, 0x0070002A,
   0x0030002B, 0x0070002B, 0x0030002C, 0x0070002C, 0x0030002D, 0x0070002D,
   0x0030002E, 0x0070002E, 0x0030002F, 0x0070002F, 0x00300030, 0x00700030,
   0x00300031, 0x00700031, 0x00300032, 0x00700032, 0x00300033, 0x00700033,
   0x00300034, 0x00700034, 0x00300035, 0x00700035, 0x00300036, 0x00700036,
   0x00300037, 0x00700037, 0x00300038, 0x00700038, 0x00300039, 0x00700039,
   0x0030003A, 0x0070003A, 0x0030003B, 0x0070003B, 0x0030003C, 0x0070003C,
   0x0030003D, 0x0070003D, 0x0030003E, 0x0070003E, 0x0070003F, 0x0031C080,
   0x00F24200, 0x00F28400, 0x00F2C800, 0x00F31000, 0x00A42000, 0x00A42000,
   0x00A42000, 0x00A42000, 0x00A42000, 0x00A42000, 0x00A42000, 0x00A42000,
   0x00E54020, 0x00E54020, 0x00E54020, 0x00E54020, 0x00E54020, 0x00E54020,
   0x00E54020, 0x00E54020, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
   0x00000000, 0x00000000, 0x00000000, 0x00000000,
];
commūnis [144]n64 p4f_enc = n64.[
   0x0300000000, 0x0300000001, 0x0300000002, 0x0400000006, 0x0400000007, 0x0400000008,
   0x0400000009, 0x0500000016, 0x0500000017, 0x0600000030, 0x0600000031, 0x0600000032,
   0x0600000033, 0x070000006A, 0x070000006B, 0x070000006C, 0x070000006D, 0x070000006E,
   0x070000006F, 0x08000000E6, 0x08000000E7, 0x08000000E8, 0x08000000E9, 0x08000000EA,
   0x08000000EB, 0x08000000EC, 0x08000000ED, 0x09000001DE, 0x09000001DF, 0x09000001E0,
   0x09000001E1, 0x09000001E2, 0x09000001E3, 0x09000001E4, 0x09000001E5, 0x09000001E6,
   0x09000001E7, 0x0A000003D4, 0x0A000003D5, 0x0A000003D6, 0x0A000003D7, 0x0A000003D8,
   0x0A000003D9, 0x0A000003DA, 0x0A000003DB, 0x0A000003DC, 0x0A000003DD, 0x0A000003DE,
   0x0A000003DF, 0x0A000003E0, 0x0A000003E1, 0x0A000003E2, 0x0A000003E3, 0x0B000007CC,
   0x0B000007CD, 0x0B000007CE, 0x0B000007CF, 0x0B000007D0, 0x0B000007D1, 0x0B000007D2,
   0x0B000007D3, 0x0B000007D4, 0x0B000007D5, 0x0B000007D6, 0x0B000007D7, 0x0B000007D8,
   0x0B000007D9, 0x0B000007DA, 0x0B000007DB, 0x0B000007DC, 0x0B000007DD, 0x0B000007DE,
   0x0B000007DF, 0x0C00000FC6, 0x0C00000FC7, 0x0C00000FC8, 0x0C00000FC9, 0x0C00000FCA,
   0x0C00000FCB, 0x0C00000FCC, 0x0C00000FCD, 0x0C00000FCE, 0x0C00000FCF, 0x0C00000FD0,
   0x0C00000FD1, 0x0C00000FD2, 0x0C00000FD3, 0x0C00000FD4, 0x0C00000FD5, 0x0C00000FD6,
   0x0C00000FD7, 0x0C00000FD8, 0x0C00000FD9, 0x0C00000FDA, 0x0C00000FDB, 0x0C00000FDC,
   0x0C00000FDD, 0x0C00000FDE, 0x0C00000FDF, 0x0C00000FE0, 0x0C00000FE1, 0x0C00000FE2,
   0x0C00000FE3, 0x0C00000FE4, 0x0C00000FE5, 0x0C00000FE6, 0x0C00000FE7, 0x0C00000FE8,
   0x0C00000FE9, 0x0C00000FEA, 0x0C00000FEB, 0x0C00000FEC, 0x0C00000FED, 0x0C00000FEE,
   0x0C00000FEF, 0x0C00000FF0, 0x0C00000FF1, 0x0C00000FF2, 0x0C00000FF3, 0x0C00000FF4,
   0x0C00000FF5, 0x0C00000FF6, 0x0C00000FF7, 0x0C00000FF8, 0x0C00000FF9, 0x0B000007E0,
   0x0C00000FFA, 0x0700000070, 0x0700000071, 0x0C00000FFB, 0x0B000007E1, 0x09000001E8,
   0x040000000A, 0x0600000034, 0x0700000072, 0x08000000EE, 0x09000001E9, 0x0A000003E4,
   0x0A000003E5, 0x0B000007E2, 0x0C00000FFC, 0x0C00000FFD, 0x0C00000FFE, 0x0C00000FFF,
];
// A residual byte decides everything the encoder emits for it: which
// token, and the mantissa that follows. The table holds the finished
// emission, codeword and mantissa already concatenated.
//   bits 0..18  the bits to emit, MSB-first in the low bits
//   bits 19..23 how many of them
commūnis [256]n32 p4f_res = n32.[
   0x00000000, 0x00180001, 0x00200006, 0x00200008, 0x00280016, 0x00300030,
   0x00300032, 0x0038006A, 0x0038006C, 0x0038006E, 0x004000E6, 0x004000E8,
   0x004000EA, 0x004000EC, 0x004801DE, 0x004801E0, 0x004801E2, 0x004801E4,
   0x004801E6, 0x005003D4, 0x005003D6, 0x005003D8, 0x005003DA, 0x005003DC,
   0x005003DE, 0x005003E0, 0x005003E2, 0x005807CC, 0x005807CE, 0x005807D0,
   0x005807D2, 0x005807D4, 0x005807D6, 0x005807D8, 0x005807DA, 0x005807DC,
   0x005807DE, 0x00600FC6, 0x00600FC8, 0x00600FCA, 0x00600FCC, 0x00600FCE,
   0x00600FD0, 0x00600FD2, 0x00600FD4, 0x00600FD6, 0x00600FD8, 0x00600FDA,
   0x00600FDC, 0x00600FDE, 0x00600FE0, 0x00600FE2, 0x00600FE4, 0x00600FE6,
   0x00600FE8, 0x00600FEA, 0x00600FEC, 0x00600FEE, 0x00600FF0, 0x00600FF2,
   0x00600FF4, 0x00600FF6, 0x00600FF8, 0x005807E0, 0x00681C00, 0x00681C01,
   0x00681C02, 0x00681C03, 0x00681C04, 0x00681C05, 0x00681C06, 0x00681C07,
   0x00681C08, 0x00681C09, 0x00681C0A, 0x00681C0B, 0x00681C0C, 0x00681C0D,
   0x00681C0E, 0x00681C0F, 0x00681C10, 0x00681C11, 0x00681C12, 0x00681C13,
   0x00681C14, 0x00681C15, 0x00681C16, 0x00681C17, 0x00681C18, 0x00681C19,
   0x00681C1A, 0x00681C1B, 0x00681C1C, 0x00681C1D, 0x00681C1E, 0x00681C1F,
   0x00681C20, 0x00681C21, 0x00681C22, 0x00681C23, 0x00681C24, 0x00681C25,
   0x00681C26, 0x00681C27, 0x00681C28, 0x00681C29, 0x00681C2A, 0x00681C2B,
   0x00681C2C, 0x00681C2D, 0x00681C2E, 0x00681C2F, 0x00681C30, 0x00681C31,
   0x00681C32, 0x00681C33, 0x00681C34, 0x00681C35, 0x00681C36, 0x00681C37,
   0x00681C38, 0x00681C39, 0x00681C3A, 0x00681C3B, 0x00681C3C, 0x00681C3D,
   0x00681C3E, 0x00681C3F, 0x0093F080, 0x00681C7F, 0x00681C7E, 0x00681C7D,
   0x00681C7C, 0x00681C7B, 0x00681C7A, 0x00681C79, 0x00681C78, 0x00681C77,
   0x00681C76, 0x00681C75, 0x00681C74, 0x00681C73, 0x00681C72, 0x00681C71,
   0x00681C70, 0x00681C6F, 0x00681C6E, 0x00681C6D, 0x00681C6C, 0x00681C6B,
   0x00681C6A, 0x00681C69, 0x00681C68, 0x00681C67, 0x00681C66, 0x00681C65,
   0x00681C64, 0x00681C63, 0x00681C62, 0x00681C61, 0x00681C60, 0x00681C5F,
   0x00681C5E, 0x00681C5D, 0x00681C5C, 0x00681C5B, 0x00681C5A, 0x00681C59,
   0x00681C58, 0x00681C57, 0x00681C56, 0x00681C55, 0x00681C54, 0x00681C53,
   0x00681C52, 0x00681C51, 0x00681C50, 0x00681C4F, 0x00681C4E, 0x00681C4D,
   0x00681C4C, 0x00681C4B, 0x00681C4A, 0x00681C49, 0x00681C48, 0x00681C47,
   0x00681C46, 0x00681C45, 0x00681C44, 0x00681C43, 0x00681C42, 0x00681C41,
   0x00681C40, 0x00600FFA, 0x00600FF9, 0x00600FF7, 0x00600FF5, 0x00600FF3,
   0x00600FF1, 0x00600FEF, 0x00600FED, 0x00600FEB, 0x00600FE9, 0x00600FE7,
   0x00600FE5, 0x00600FE3, 0x00600FE1, 0x00600FDF, 0x00600FDD, 0x00600FDB,
   0x00600FD9, 0x00600FD7, 0x00600FD5, 0x00600FD3, 0x00600FD1, 0x00600FCF,
   0x00600FCD, 0x00600FCB, 0x00600FC9, 0x00600FC7, 0x005807DF, 0x005807DD,
   0x005807DB, 0x005807D9, 0x005807D7, 0x005807D5, 0x005807D3, 0x005807D1,
   0x005807CF, 0x005807CD, 0x005003E3, 0x005003E1, 0x005003DF, 0x005003DD,
   0x005003DB, 0x005003D9, 0x005003D7, 0x005003D5, 0x004801E7, 0x004801E5,
   0x004801E3, 0x004801E1, 0x004801DF, 0x004000ED, 0x004000EB, 0x004000E9,
   0x004000E7, 0x0038006F, 0x0038006D, 0x0038006B, 0x00300033, 0x00300031,
   0x00280017, 0x00200009, 0x00200007, 0x00180002,
];

// pictor4_asm.lbc -- the BTPNGF1 symbol loop in hand-written RISC-V.
//
// Same format, same bytes. What is in assembly is the part that dominates
// both directions: the per-symbol loop, where every instruction sits in a
// loop-carried chain and the compiler's register allocation has to be
// exactly right or the bit cursor spills.
//
// ABI, from compiler/no_tree_rv.lbc and bootloader/rv_atomic_queues.lbc:
// Brevis passes arguments in x8..x31 and returns in x8, x9, x10, ... A
// compīlāta body is entered with the frame already banked (ra and tp); it
// leaves with `c.mv sp tp` then `c.ret`. Registers that carry parameters
// are the callee's to clobber, which is why the trailing z0..z5 exist:
// declaring them as parameters is how this file claims x17..x22 as
// scratch without guessing what the allocator considers volatile.
//
// The instructions are plain RV64GC. The C906 has T-Head custom opcodes
// and RVV 0.7, the U74 has neither, and there is no macro that tells them
// apart -- both targets report TARGET_CPU_RV64GCV0_7 and the VF2L
// restriction is only a ban on what the compiler itself may emit. Hand
// assembly bypasses that ban, so anything board-specific has to be a
// separate procedure that the board-specific driver alone calls.



/*  One row of one plane: residuals to tokens. The mirror of the decode
    loop, and the same shape -- state in registers for the whole row, one
    table load per symbol, bytes leaving the accumulator as they fill.

    x8  dst base        x15 enc table (len<<32 | code)
    x9  at              x16 one past the last storable byte
    x10 acc             x17 x (column)
    x11 nb              x18 e (residual byte)
    x12 rc row          x19 token / length
    x13 w               x20 x21 x22 scratch
    x14 residual -> emitted bits, 256 entries
    x23 write pointer   x24 the constant 8

    Returns (at, acc, nb) in x8, x9, x10.
*/
prōcēdūra compīlāta p4a_encode_row(@n8 dst; n64 at; n64 acc; n64 nb; @s8 rc;
                                   n64 w; @n64 res; @n64 enc; n64 cap;
                                   n64 z0; n64 z1; n64 z2; n64 z3; n64 z4;
                                   n64 z5; n64 z6; n64 z7; -> n64; n64; n64;)
***
   li x17 0
   add x16 x8 x16                 // one past the last byte that may be stored
   add x23 x8 x9                  // the write pointer, so a byte costs no add
   li x24 8

p4e_row:
   bgeu x17 x13 p4e_done
   add x20 x12 x17
   lbu x18 0(x20)
   beqz x18 p4e_zero

   // ---- nonzero residual: the byte indexes its own emission. Which
   // token it is, and the mantissa that follows, are both decided by the
   // residual byte alone -- so the table holds the finished bits and the
   // hot path loses a magnitude, a compare ladder and three branches.
   slli x21 x18 2
   add x21 x14 x21
   lwu x21 0(x21)
   srli x20 x21 19                // how many bits
   slli x19 x21 45
   srli x19 x19 45                // the bits themselves
   sll x10 x10 x20
   or x10 x10 x19
   add x11 x11 x20
   addi x17 x17 1
   j p4e_drain

p4e_zero:
   // ---- a zero: scan the run, then EOL, single zero, or a run token
   addi x20 x17 1
p4e_scan:
   // to the next 8-byte boundary one byte at a time
   bgeu x20 x13 p4e_scan_end
   add x21 x12 x20
   andi x22 x21 7
   beqz x22 p4e_scan_word
   lb x21 0(x21)
   bnez x21 p4e_scan_end
   addi x20 x20 1
   j p4e_scan
p4e_scan_word:
   // eight zero bytes at a time; the row's stride is 8-aligned so this
   // load never straddles
   addi x22 x20 8
   bltu x13 x22 p4e_scan_tail
   add x21 x12 x20
   ld x21 0(x21)
   bnez x21 p4e_scan_tail
   mv x20 x22
   j p4e_scan_word
p4e_scan_tail:
   bgeu x20 x13 p4e_scan_end
   add x21 x12 x20
   lb x21 0(x21)
   bnez x21 p4e_scan_end
   addi x20 x20 1
   j p4e_scan_tail
p4e_scan_end:
   sub x21 x20 x17                // run length
   bltu x20 x13 p4e_notend

   // reaches the end of the row: one EOL token, and the row is finished
   li x19 131
   li x20 0
   li x21 0
   mv x17 x13
   j p4e_emit

p4e_notend:
   li x22 1
   bne x21 x22 p4e_runtok
   li x19 0                       // the single-zero token
   li x20 0
   li x21 0
   addi x17 x17 1
   j p4e_emit

p4e_runtok:
   add x17 x17 x21                // advance by the whole run
   li x22 8191
   bgeu x22 x21 p4e_runok
   mv x21 x22
p4e_runok:
   // j = floor(log2 run), by shifting down; runs are short so this is
   // cheaper than any table and has no memory in the chain
   li x20 0
   mv x22 x21
p4e_log:
   srli x22 x22 1
   beqz x22 p4e_logdone
   addi x20 x20 1
   j p4e_log
p4e_logdone:
   li x19 132
   add x19 x19 x20
   addi x19 x19 -1                // token = RUN + j - 1
   li x22 1
   sll x22 x22 x20
   sub x21 x21 x22                // mantissa = run - (1 << j)
   j p4e_emit

p4e_emit:
   // x19 token, x20 mantissa width, x21 mantissa
   slli x22 x19 3
   add x22 x15 x22
   ld x22 0(x22)                  // enc[token]
   srli x19 x22 32
   andi x19 x19 255               // code length
   slli x22 x22 48
   srli x22 x22 48                // codeword
   sll x10 x10 x19
   or x10 x10 x22
   add x11 x11 x19
   beqz x20 p4e_drain
   sll x10 x10 x20
   or x10 x10 x21
   add x11 x11 x20

p4e_drain:
   bltu x11 x24 p4e_row
   addi x11 x11 -8
   bgeu x23 x16 p4e_nostore
   srl x22 x10 x11                // sb keeps the low byte: no mask
   sb x22 0(x23)
p4e_nostore:
   addi x23 x23 1
   j p4e_drain

p4e_done:
   sub x8 x23 x8                  // the write position it reached
   mv x9 x10
   mv x10 x11
   c.mv sp tp
   c.ret
***

/*  The inverse colour transform and the RGBA interleave for one row.

    Every pixel here is independent -- no prediction, no neighbours -- so
    this is the one part of decode that is pure straight-line work. It
    stays scalar because RVV 0.7 exists only on the C906 and a single
    image has to run on both boards.

    x8 y row  x9 co row  x10 cg row  x11 a row  x12 out  x13 w
*/
prōcēdūra compīlāta p4a_ycocg_row(@n8 yr; @n8 cor; @n8 cgr; @n8 ar; @n8 out;
                                  n64 w; n64 z0; n64 z1; n64 z2; n64 z3;
                                  n64 z4; n64 z5; n64 z6; n64 z7; n64 z8;
                                  -> n64;)
***
   li x14 0

p4y_loop:
   bgeu x14 x13 p4y_done
   add x15 x8 x14
   lbu x15 0(x15)                 // y
   add x16 x9 x14
   lbu x16 0(x16)                 // co
   add x17 x10 x14
   lbu x17 0(x17)                 // cg

   // t = (y - (cg as int8 >> 1)) & 255
   slli x18 x17 56
   srai x18 x18 56
   srai x18 x18 1
   sub x18 x15 x18
   andi x18 x18 255               // t
   add x19 x17 x18
   andi x19 x19 255               // g
   slli x20 x16 56
   srai x20 x20 56
   srai x20 x20 1
   sub x20 x18 x20
   andi x20 x20 255               // b
   add x21 x20 x16
   andi x21 x21 255               // r

   slli x22 x14 2
   add x22 x12 x22
   sb x20 0(x22)                  // b
   sb x19 1(x22)                  // g
   sb x21 2(x22)                  // r
   add x15 x11 x14
   lbu x15 0(x15)
   sb x15 3(x22)                  // x
   addi x14 x14 1
   j p4y_loop

p4y_done:
   li x8 0
   c.mv sp tp
   c.ret
***

/*  Symbols straight to samples, in one pass.

    The two-pass shape writes a residual row, reads it back and adds the
    prediction: a memset, a store and a load per sample per plane, three
    passes over memory for data consumed immediately. Here a token becomes
    a pixel before the next token is read and the residual row never
    exists. Worth 32-37% of decode on this format.

    A run still predicts every pixel, but not the hard way: where T equals
    TL the clamp collapses to L exactly, so the sample is the one already
    in hand and nothing but the store has to happen. That is the whole of
    a flat region, and row 0 as well -- its row above reads as zeros, so
    T = TL = 0 and the prediction is L, which is what row 0 wants.

    x8  src base     x16 root table    x23 T
    x9  at           x17 escape table  x24 entry
    x10 end          x19 x (column)    x25 x26 scratch
    x11 acc          x20 L             x27 12-bit window
    x12 nb           x21 TL
    x13 cur row      x22 scratch
    x14 prv row
    x15 w

    Returns (ok, at, acc, nb) in x8, x9, x10, x11.
*/
prōcēdūra compīlāta p4a_dec_rec_row(@n8 src; n64 at; n64 end; n64 acc; n64 nb;
                                    @n8 cur; @n8 prv; n64 w; @n64 root;
                                    @n64 sub; n64 z0; n64 z1; n64 z2;
                                    n64 z3; n64 z4; n64 z5; n64 z6; n64 z7;
                                    n64 z8; n64 z9; -> n64; n64; n64; n64;)
***
   li x19 0
   li x20 0                       // L, zero before the first pixel
   li x21 0                       // TL

p4f_row:
   bgeu x19 x15 p4f_done

p4f_refill:
   li x22 56
   bltu x22 x12 p4f_have
   add x25 x8 x9
   bgeu x9 x10 p4f_pad
   lbu x22 0(x25)
   j p4f_shift
p4f_pad:
   li x22 0
p4f_shift:
   addi x9 x9 1
   li x25 56
   sub x25 x25 x12
   sll x22 x22 x25
   or x11 x11 x22
   addi x12 x12 8
   j p4f_refill

p4f_have:
   // eight bits index the root; long codes take the escape block. The
   // small table is this core's preference: twelve bits direct measured
   // 7.6% slower here and 1.7% faster on the U74.
   srli x27 x11 52
   srli x22 x27 4
   slli x22 x22 2
   add x22 x16 x22
   lwu x24 0(x22)
   srli x25 x24 18
   andi x25 x25 15
   bnez x25 p4f_got
   srli x22 x24 24
   andi x22 x22 63
   slli x22 x22 4
   andi x26 x27 15
   add x22 x22 x26
   slli x22 x22 2
   add x22 x17 x22
   lwu x24 0(x22)
   srli x25 x24 18
   andi x25 x25 15
   beqz x25 p4f_fail
p4f_got:
   sll x11 x11 x25
   sub x12 x12 x25

   slli x22 x24 50
   srli x22 x22 50                // base
   srli x25 x24 14
   andi x25 x25 15                // mantissa width
   beqz x25 p4f_nomant
   li x26 64
   sub x26 x26 x25
   srl x26 x11 x26
   add x22 x22 x26
   sll x11 x11 x25
   sub x12 x12 x25
p4f_nomant:
   srli x25 x24 22
   andi x25 x25 3                 // kind
   li x26 2
   bgeu x25 x26 p4f_run

   // ---- one residual, one pixel
   beqz x25 p4f_pos
   sub x22 x0 x22
p4f_pos:
   add x23 x14 x19
   lbu x23 0(x23)                 // T
   beq x23 x21 p4f_flat           // T == TL: the clamp can only give L
   mv x25 x20
   bgeu x23 x20 p4f_hasmn
   mv x25 x23
p4f_hasmn:
   mv x26 x23
   bgeu x23 x20 p4f_hasmx
   mv x26 x20
p4f_hasmx:
   add x24 x20 x23
   sub x24 x24 x21                // g = L + T - TL
   bge x24 x25 p4f_ge
   mv x24 x25
p4f_ge:
   bge x26 x24 p4f_le
   mv x24 x26
p4f_le:
   mv x21 x23                     // TL = T
   j p4f_add
p4f_flat:
   mv x24 x20
p4f_add:
   add x22 x24 x22
   andi x22 x22 255
   add x25 x13 x19
   sb x22 0(x25)
   mv x20 x22                     // L
   addi x19 x19 1
   j p4f_row

p4f_run:
   sub x26 x15 x19
   bltu x22 x26 p4f_runok
   mv x22 x26
p4f_runok:
   beqz x22 p4f_fail
   add x26 x19 x22
p4f_runloop:
   bgeu x19 x26 p4f_row
   add x23 x14 x19
   lbu x23 0(x23)
   bne x23 x21 p4f_rmed           // the flat case: L again, and TL is T
   add x25 x13 x19
   sb x20 0(x25)
   addi x19 x19 1
   j p4f_runloop
p4f_rmed:
   mv x25 x20
   bgeu x23 x20 p4f_rmn
   mv x25 x23
p4f_rmn:
   mv x24 x23
   bgeu x23 x20 p4f_rmx
   mv x24 x20
p4f_rmx:
   add x22 x20 x23
   sub x22 x22 x21
   bge x22 x25 p4f_rge
   mv x22 x25
p4f_rge:
   bge x24 x22 p4f_rle
   mv x22 x24
p4f_rle:
   mv x21 x23
   andi x22 x22 255
   add x25 x13 x19
   sb x22 0(x25)
   mv x20 x22
   addi x19 x19 1
   j p4f_runloop

p4f_fail:
   mv x10 x11
   mv x11 x12
   li x8 0
   c.mv sp tp
   c.ret

p4f_done:
   mv x10 x11
   mv x11 x12
   li x8 1
   c.mv sp tp
   c.ret
***

// MEASURED DEAD ENDS, kept here so they are not tried twice.
//
//   Fusing the residual pass into the SYMBOL pass on the encode side --
// computing a residual, using it and dropping it, with the zero-run scan
// becoming "keep predicting until a pixel disagrees" -- is worth +1.3% on
// photographic content and -8% on a screenshot. The scan is why: the
// two-pass encoder finds a run with one aligned 8-byte load per eight
// pixels, and the fused one has to run MED for every pixel it skips.
// Fusing the COLOUR pass into the residual pass, which is what this file
// does below, is a different trade and wins on both.
//
//   Writing MED without branches -- min and max from k = min(L - T, 0),
// both clamps from the sign bit -- costs one instruction more per sample
// and measures -4.2% here and -15.4% on the U74. The branches it removes
// are the ones real images predict best.

/*  Colour transform and residuals for one row, in one pass.

    The two-pass shape writes four plane rows and reads them straight back
    to predict from them. Here a pixel is transformed and its four
    residuals fall out while the samples are still in registers; cur is
    written only because the NEXT row predicts from it, and is never read
    again.

    cur and prv hold the four samples INTERLEAVED -- Y, Co, Cg, X per
    pixel -- so the row above costs four loads off one line and no stride
    arithmetic. The residual rows stay planar: that is what the emitter
    scans.

    L and TL start at zero, which is exactly what row 0 and column 0 want.
    MED with T = TL = 0 clamps to L, and with L = TL = 0 clamps to T, so
    the two edge rules are the general rule here and cost no branch.

    x8  src    x11..x14 rr per plane   x16..x19 L per plane
    x9  cur    x15 src end             x20..x23 TL per plane
    x10 prv                            x24..x31 scratch
*/
prōcēdūra compīlāta p4a_ycocg_resid_row(@n8 src; @n8 cur; @n8 prv; @s8 rr0;
                                        @s8 rr1; @s8 rr2; @s8 rr3; n64 w;
                                        n64 z0; n64 z1; n64 z2; n64 z3;
                                        n64 z4; n64 z5; n64 z6; n64 z7;
                                        n64 z8; n64 z9; n64 z10; n64 z11;
                                        n64 z12; n64 z13; n64 z14; n64 z15;
                                        -> n64;)
***
   slli x15 x15 2
   add x15 x8 x15                 // one past the last pixel
   li x16 0
   li x17 0
   li x18 0
   li x19 0
   li x20 0
   li x21 0
   li x22 0
   li x23 0

p4c_loop:
   bgeu x8 x15 p4c_done

   lbu x24 0(x8)                  // b   XRGB8888 in memory is B,G,R,X
   lbu x25 1(x8)                  // g
   lbu x26 2(x8)                  // r
   lbu x27 3(x8)                  // x
   sub x28 x26 x24
   andi x28 x28 255               // co = r - b
   slli x29 x28 56
   srai x29 x29 56
   srai x29 x29 1
   add x29 x24 x29                // t = b + (co >> 1), left unwrapped:
   sub x30 x25 x29                // everything downstream of it is mod 256
   andi x30 x30 255               // cg = g - t
   slli x31 x30 56
   srai x31 x31 56
   srai x31 x31 1
   add x31 x29 x31
   andi x31 x31 255               // y = t + (cg >> 1)
   sb x31 0(x9)
   sb x28 1(x9)
   sb x30 2(x9)
   sb x27 3(x9)

   lbu x24 0(x10)                 // T
   bne x24 x20 p4c_ymed           // T == TL: the MED is L
   sub x29 x31 x16
   sb x29 0(x11)                   // sb keeps the low byte: no mask
   mv x16 x31
   j p4c_yend
p4c_ymed:
   mv x25 x16
   bgeu x24 x16 p4c_y1
   mv x25 x24                     // mn = min(L, T)
p4c_y1:
   mv x26 x24
   bgeu x24 x16 p4c_y2
   mv x26 x16                     // mx = max(L, T)
p4c_y2:
   add x29 x16 x24
   sub x29 x29 x20                // L + T - TL
   mv x20 x24
   bge x29 x25 p4c_y3
   mv x29 x25
p4c_y3:
   bge x26 x29 p4c_y4
   mv x29 x26
p4c_y4:
   sub x29 x31 x29
   sb x29 0(x11)
   mv x16 x31
p4c_yend:

   lbu x24 1(x10)                 // T
   bne x24 x21 p4c_omed           // T == TL: the MED is L
   sub x29 x28 x17
   sb x29 0(x12)                   // sb keeps the low byte: no mask
   mv x17 x28
   j p4c_oend
p4c_omed:
   mv x25 x17
   bgeu x24 x17 p4c_o1
   mv x25 x24                     // mn = min(L, T)
p4c_o1:
   mv x26 x24
   bgeu x24 x17 p4c_o2
   mv x26 x17                     // mx = max(L, T)
p4c_o2:
   add x29 x17 x24
   sub x29 x29 x21                // L + T - TL
   mv x21 x24
   bge x29 x25 p4c_o3
   mv x29 x25
p4c_o3:
   bge x26 x29 p4c_o4
   mv x29 x26
p4c_o4:
   sub x29 x28 x29
   sb x29 0(x12)
   mv x17 x28
p4c_oend:

   lbu x24 2(x10)                 // T
   bne x24 x22 p4c_gmed           // T == TL: the MED is L
   sub x29 x30 x18
   sb x29 0(x13)                   // sb keeps the low byte: no mask
   mv x18 x30
   j p4c_gend
p4c_gmed:
   mv x25 x18
   bgeu x24 x18 p4c_g1
   mv x25 x24                     // mn = min(L, T)
p4c_g1:
   mv x26 x24
   bgeu x24 x18 p4c_g2
   mv x26 x18                     // mx = max(L, T)
p4c_g2:
   add x29 x18 x24
   sub x29 x29 x22                // L + T - TL
   mv x22 x24
   bge x29 x25 p4c_g3
   mv x29 x25
p4c_g3:
   bge x26 x29 p4c_g4
   mv x29 x26
p4c_g4:
   sub x29 x30 x29
   sb x29 0(x13)
   mv x18 x30
p4c_gend:

   lbu x24 3(x10)                 // T
   bne x24 x23 p4c_xmed           // T == TL: the MED is L
   sub x29 x27 x19
   sb x29 0(x14)                   // sb keeps the low byte: no mask
   mv x19 x27
   j p4c_xend
p4c_xmed:
   mv x25 x19
   bgeu x24 x19 p4c_x1
   mv x25 x24                     // mn = min(L, T)
p4c_x1:
   mv x26 x24
   bgeu x24 x19 p4c_x2
   mv x26 x19                     // mx = max(L, T)
p4c_x2:
   add x29 x19 x24
   sub x29 x29 x23                // L + T - TL
   mv x23 x24
   bge x29 x25 p4c_x3
   mv x29 x25
p4c_x3:
   bge x26 x29 p4c_x4
   mv x29 x26
p4c_x4:
   sub x29 x27 x29
   sb x29 0(x14)
   mv x19 x27
p4c_xend:

   addi x8 x8 4
   addi x9 x9 4
   addi x10 x10 4
   addi x11 x11 1
   addi x12 x12 1
   addi x13 x13 1
   addi x14 x14 1
   j p4c_loop

p4c_done:
   li x8 0
   c.mv sp tp
   c.ret
***

// ================================================================= decode
//
// Everything outside the symbol loop stays in Brevis: it is row work with
// no loop-carried dependency worth hand-scheduling, and the compiler
// already vectorises none of it either way.

#vulgā prōcēdūra bng_decode([]n8 src; -> []n8; n64; n64; n64;) {
   #situla trānsitōria: temp_sit;
   []n8 none;
   sī p4_magic_ok(src,) == 0 { #refer (none, 0, 0, 0,); }
   n64 w = p4_u32(src, 8,);
   n64 h = p4_u32(src, 12,);
   n64 count_field = p4_u32(src, 16,);
   n64 raw = count_field & P4_RAW_FLAG;
   n64 stream_byte_count = count_field & P4_COUNT_MASK;
   sī w == 0 || h == 0 || w > 65535 || h > 65535 { #refer (none, 0, 0, 0,); }
   n64 n = w * h;
   sī stream_byte_count > src.m - P4_HEADER { #refer (none, 0, 0, 0,); }
   sī raw != 0 {
      // Bit 31: the body is the XRGB8888 pixels themselves, packed.
      sī stream_byte_count != 4 * n { #refer (none, 0, 0, 0,); }
      []n8 rawpx = situlā_adlocā<n8,>(circum.situla_data%, 4 * n,);
      dum n64 i = 0; i < 4 * n { rawpx[i]% = src[P4_HEADER + i]%; i += 1; }
      #refer (rawpx, w, h, 1,);
   }
   sī stream_byte_count * 8 < h { #refer (none, 0, 0, 0,); }

   []n8 dst = situlā_adlocā<n8,>(circum.situla_data%, 4 * n,);
   []n8 pix = situlā_adlocā<n8,>(temp_sit, 8 * w,);
   n64 rstride = ((w + 7) / 8) * 8;        // 8-aligned rows for the wide scan
   []s8 rr  = situlā_adlocā<s8,>(temp_sit, 4 * rstride + 8,);
   dum n64 i = 0; i < 8 * w { pix[i]% = 0; i += 1; }

   n64 rstride = ((w + 7) / 8) * 8;
   n64 at = P4_HEADER;
   n64 end = P4_HEADER + stream_byte_count;
   n64 acc = 0;
   n64 nb = 0;
   n64 ok = 1;

   dum n64 y = 0; y < h {
      n64 cb = (y & 1) * (4 * w);
      n64 pb = (1 - (y & 1)) * (4 * w);

      dum n64 p = 0; p < 4 {
         n64 co = p * rstride;
         n64 c0 = cb + p * w;
         n64 p0 = pb + p * w;

         n64 rok;
         (rok, at, acc, nb,) = p4a_dec_rec_row(src.i, at, end, acc, nb,
                                               pix.i + (@n8)c0,
                                               pix.i + (@n8)p0, w,
                                               (@n64)p4f_root,
                                               (@n64)p4f_sub,
                                               0, 0, 0, 0, 0, 0, 0, 0, 0, 0,);
         sī rok == 0 { ok = 0; #dēsine; }
         p += 1;
      }
      sī ok == 0 { #dēsine; }

      n64 rowoff = (y * w) * 4;
      p4a_ycocg_row(pix.i + (@n8)cb, pix.i + (@n8)(cb + w),
                    pix.i + (@n8)(cb + 2 * w), pix.i + (@n8)(cb + 3 * w),
                    dst.i + (@n8)rowoff, w, 0, 0, 0, 0, 0, 0, 0, 0, 0,);
      y += 1;
   }

   sī at > end + 16 { ok = 0; }
   sī ok == 0 { #refer (none, 0, 0, 0,); }
   #refer (dst, w, h, 1,);
}

// One encode pass into dst, returning the write position it reached. The
// asm writer counts the bytes it could not store, so a return past dst.m
// says exactly how large the buffer has to be.
prōcēdūra p4a_encode_into([]n8 dst; n64 cap; []n8 px; n64 w; n64 h;
                          n64 pitch; []n8 pix; []s8 rr; -> n64;) {
   n64 rstride = ((w + 7) / 8) * 8;
   n64 at = P4_HEADER;
   n64 acc = 0;
   n64 nb = 0;

   dum n64 y = 0; y < h {
      n64 rowoff = y * pitch;
      n64 cb = (y & 1) * (4 * w);
      n64 pb = (1 - (y & 1)) * (4 * w);

      // Row 0 needs no case of its own: prv is the zeroed half of pix on
      // the first pass and MED against zero is the left predictor.
      p4a_ycocg_resid_row(px.i + (@n8)rowoff, pix.i + (@n8)cb,
                          pix.i + (@n8)pb, rr.i, rr.i + (@s8)rstride,
                          rr.i + (@s8)(2 * rstride),
                          rr.i + (@s8)(3 * rstride), w,
                          0, 0, 0, 0, 0, 0, 0, 0,
                          0, 0, 0, 0, 0, 0, 0, 0,);

      dum n64 p = 0; p < 4 {
         n64 co = p * rstride;
         (at, acc, nb,) = p4a_encode_row(dst.i, at, acc, nb, rr.i + (@s8)co, w,
                                         (@n64)p4f_res, (@n64)p4f_enc, cap,
                                         0, 0, 0, 0, 0, 0, 0, 0,);
         p += 1;
      }
      y += 1;
   }

   sī nb != 0 {
      sī at < cap { dst[at]% = (n8)((acc << (8 - nb)) & 0xFF); }
      at += 1;
   }
   #refer at;
}

// pitch is the source's row stride, so a crop of a framebuffer can be
// encoded where it lies.
#vulgā prōcēdūra bng_encode([]n8 px; n64 w; n64 h; n64 pitch;
                                -> []n8; n64;) {
   #situla trānsitōria: temp_sit;
   []n8 none;
   sī w == 0 || h == 0 { #refer (none, 0,); }
   n64 n = w * h;
   sī pitch < w * 4 { #refer (none, 0,); }
   sī px.m < (h - 1) * pitch + w * 4 { #refer (none, 0,); }

   // Capped at what raw would cost: a body that reaches that has lost.
   n64 cap = P4_HEADER + 4 * n;
   []n8 dst = situlā_adlocā<n8,>(circum.situla_data%, cap,);
   []n8 pix = situlā_adlocā<n8,>(temp_sit, 8 * w,);
   n64 rstride = ((w + 7) / 8) * 8;        // 8-aligned rows for the wide scan
   []s8 rr  = situlā_adlocā<s8,>(temp_sit, 4 * rstride + 8,);
   dum n64 i = 0; i < 8 * w { pix[i]% = 0; i += 1; }

   n64 at = p4a_encode_into(dst, cap, px, w, h, pitch, pix, rr,);
   p4_put_magic(dst,);
   p4_put_u32(dst, 8, w,);
   p4_put_u32(dst, 12, h,);
   sī at - P4_HEADER >= 4 * n {
      // The pixels themselves: only noise reaches this, and it bounds
      // every file at 20 + 4wh.
      dum n64 y = 0; y < h {
         dum n64 i = 0; i < w * 4 {
            dst[P4_HEADER + y * w * 4 + i]% = px[y * pitch + i]%;
            i += 1;
         }
         y += 1;
      }
      p4_put_u32(dst, 16, (4 * n) | P4_RAW_FLAG,);
      #refer (dst[0:P4_HEADER + 4 * n], 1,);
   }
   p4_put_u32(dst, 16, at - P4_HEADER,);   // stream_byte_count
   #refer (dst[0:at], 1,);
}

#fīnis

#sī (TARGET_CPU_RV_SRISA2 & ^NO_ASM)

// ====================== SRISA2: the VisionFive 2 Lite (U74)
//
// The two machines disagree about what the decoder should look like, and
// the disagreement is measured rather than assumed -- which is why this
// section and the next are not one body with a flag in it.
//
//   A TWELVE-BIT DIRECT table: 4096 entries of 32 bits, 16 KiB. One load
// per symbol and no escape branch in the loop-carried chain, which this
// core pays for happily -- it is 1.7% faster than ten bits and 2% faster
// than eight.
//
// The bytes are identical to the reference above; only the shape of the
// work differs.
//
// Measured on the board at 768x512, best of three:
//                  encode   decode
//   photograph      8662     8287  KP/s
//   screenshot     15171    14438

// The tables are carried, not built: cōdex/tools/bng_tables.py derives them
// from the 144 canonical code lengths and prints what is below. Nothing
// runs before the first image and there is no state to race.
//
// A table entry is
//   bits 0..13  base   14..17 nbits   18..21 len   22..23 kind
//
// Measured on this core: 12-bit direct 5785 KP/s, 10-bit 5739, 8-bit
// 5686. The U74 pays for 16 KiB of table and takes back the escape
// branch and its dependent load -- the opposite of what the C906 wants.
commūnis [4096]n32 p4f_root = n32.[
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000, 0x000C0000,
   0x000C0000, 0x000C0000, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001,
   0x000C0001, 0x000C0001, 0x000C0001, 0x000C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001, 0x004C0001,
   0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002,
   0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002,
   0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002,
   0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002,
   0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002,
   0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002,
   0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002,
   0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002,
   0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002,
   0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002,
   0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002,
   0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002,
   0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002,
   0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002,
   0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002,
   0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002,
   0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002,
   0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002,
   0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002,
   0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002,
   0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002,
   0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002,
   0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002,
   0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002,
   0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002,
   0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002,
   0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002,
   0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002,
   0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002,
   0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002,
   0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002,
   0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002,
   0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002,
   0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002,
   0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002,
   0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002,
   0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002,
   0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002,
   0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002,
   0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002,
   0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002,
   0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00100002,
   0x00100002, 0x00100002, 0x00100002, 0x00100002, 0x00500002, 0x00500002,
   0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002,
   0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002,
   0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002,
   0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002,
   0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002,
   0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002,
   0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002,
   0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002,
   0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002,
   0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002,
   0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002,
   0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002,
   0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002,
   0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002,
   0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002,
   0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002,
   0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002,
   0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002,
   0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002,
   0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002,
   0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002,
   0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002,
   0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002,
   0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002,
   0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002,
   0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002,
   0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002,
   0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002,
   0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002,
   0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002,
   0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002,
   0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002,
   0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002,
   0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002,
   0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002,
   0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002,
   0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002,
   0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002,
   0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002,
   0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002,
   0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002,
   0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002, 0x00500002,
   0x00500002, 0x00500002, 0x00100003, 0x00100003, 0x00100003, 0x00100003,
   0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003,
   0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003,
   0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003,
   0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003,
   0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003,
   0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003,
   0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003,
   0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003,
   0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003,
   0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003,
   0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003,
   0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003,
   0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003,
   0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003,
   0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003,
   0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003,
   0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003,
   0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003,
   0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003,
   0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003,
   0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003,
   0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003,
   0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003,
   0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003,
   0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003,
   0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003,
   0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003,
   0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003,
   0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003,
   0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003,
   0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003,
   0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003,
   0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003,
   0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003,
   0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003,
   0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003,
   0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003,
   0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003,
   0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003,
   0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003,
   0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003,
   0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003, 0x00100003,
   0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003,
   0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003,
   0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003,
   0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003,
   0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003,
   0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003,
   0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003,
   0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003,
   0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003,
   0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003,
   0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003,
   0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003,
   0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003,
   0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003,
   0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003,
   0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003,
   0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003,
   0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003,
   0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003,
   0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003,
   0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003,
   0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003,
   0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003,
   0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003,
   0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003,
   0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003,
   0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003,
   0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003,
   0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003,
   0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003,
   0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003,
   0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003,
   0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003,
   0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003,
   0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003,
   0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003,
   0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003,
   0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003,
   0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003,
   0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003,
   0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003,
   0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00500003,
   0x00500003, 0x00500003, 0x00500003, 0x00500003, 0x00D04002, 0x00D04002,
   0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002,
   0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002,
   0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002,
   0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002,
   0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002,
   0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002,
   0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002,
   0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002,
   0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002,
   0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002,
   0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002,
   0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002,
   0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002,
   0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002,
   0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002,
   0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002,
   0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002,
   0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002,
   0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002,
   0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002,
   0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002,
   0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002,
   0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002,
   0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002,
   0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002,
   0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002,
   0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002,
   0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002,
   0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002,
   0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002,
   0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002,
   0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002,
   0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002,
   0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002,
   0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002,
   0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002,
   0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002,
   0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002,
   0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002,
   0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002,
   0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002,
   0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002, 0x00D04002,
   0x00D04002, 0x00D04002, 0x00140004, 0x00140004, 0x00140004, 0x00140004,
   0x00140004, 0x00140004, 0x00140004, 0x00140004, 0x00140004, 0x00140004,
   0x00140004, 0x00140004, 0x00140004, 0x00140004, 0x00140004, 0x00140004,
   0x00140004, 0x00140004, 0x00140004, 0x00140004, 0x00140004, 0x00140004,
   0x00140004, 0x00140004, 0x00140004, 0x00140004, 0x00140004, 0x00140004,
   0x00140004, 0x00140004, 0x00140004, 0x00140004, 0x00140004, 0x00140004,
   0x00140004, 0x00140004, 0x00140004, 0x00140004, 0x00140004, 0x00140004,
   0x00140004, 0x00140004, 0x00140004, 0x00140004, 0x00140004, 0x00140004,
   0x00140004, 0x00140004, 0x00140004, 0x00140004, 0x00140004, 0x00140004,
   0x00140004, 0x00140004, 0x00140004, 0x00140004, 0x00140004, 0x00140004,
   0x00140004, 0x00140004, 0x00140004, 0x00140004, 0x00140004, 0x00140004,
   0x00140004, 0x00140004, 0x00140004, 0x00140004, 0x00140004, 0x00140004,
   0x00140004, 0x00140004, 0x00140004, 0x00140004, 0x00140004, 0x00140004,
   0x00140004, 0x00140004, 0x00140004, 0x00140004, 0x00140004, 0x00140004,
   0x00140004, 0x00140004, 0x00140004, 0x00140004, 0x00140004, 0x00140004,
   0x00140004, 0x00140004, 0x00140004, 0x00140004, 0x00140004, 0x00140004,
   0x00140004, 0x00140004, 0x00140004, 0x00140004, 0x00140004, 0x00140004,
   0x00140004, 0x00140004, 0x00140004, 0x00140004, 0x00140004, 0x00140004,
   0x00140004, 0x00140004, 0x00140004, 0x00140004, 0x00140004, 0x00140004,
   0x00140004, 0x00140004, 0x00140004, 0x00140004, 0x00140004, 0x00140004,
   0x00140004, 0x00140004, 0x00140004, 0x00140004, 0x00140004, 0x00140004,
   0x00140004, 0x00140004, 0x00140004, 0x00140004, 0x00540004, 0x00540004,
   0x00540004, 0x00540004, 0x00540004, 0x00540004, 0x00540004, 0x00540004,
   0x00540004, 0x00540004, 0x00540004, 0x00540004, 0x00540004, 0x00540004,
   0x00540004, 0x00540004, 0x00540004, 0x00540004, 0x00540004, 0x00540004,
   0x00540004, 0x00540004, 0x00540004, 0x00540004, 0x00540004, 0x00540004,
   0x00540004, 0x00540004, 0x00540004, 0x00540004, 0x00540004, 0x00540004,
   0x00540004, 0x00540004, 0x00540004, 0x00540004, 0x00540004, 0x00540004,
   0x00540004, 0x00540004, 0x00540004, 0x00540004, 0x00540004, 0x00540004,
   0x00540004, 0x00540004, 0x00540004, 0x00540004, 0x00540004, 0x00540004,
   0x00540004, 0x00540004, 0x00540004, 0x00540004, 0x00540004, 0x00540004,
   0x00540004, 0x00540004, 0x00540004, 0x00540004, 0x00540004, 0x00540004,
   0x00540004, 0x00540004, 0x00540004, 0x00540004, 0x00540004, 0x00540004,
   0x00540004, 0x00540004, 0x00540004, 0x00540004, 0x00540004, 0x00540004,
   0x00540004, 0x00540004, 0x00540004, 0x00540004, 0x00540004, 0x00540004,
   0x00540004, 0x00540004, 0x00540004, 0x00540004, 0x00540004, 0x00540004,
   0x00540004, 0x00540004, 0x00540004, 0x00540004, 0x00540004, 0x00540004,
   0x00540004, 0x00540004, 0x00540004, 0x00540004, 0x00540004, 0x00540004,
   0x00540004, 0x00540004, 0x00540004, 0x00540004, 0x00540004, 0x00540004,
   0x00540004, 0x00540004, 0x00540004, 0x00540004, 0x00540004, 0x00540004,
   0x00540004, 0x00540004, 0x00540004, 0x00540004, 0x00540004, 0x00540004,
   0x00540004, 0x00540004, 0x00540004, 0x00540004, 0x00540004, 0x00540004,
   0x00540004, 0x00540004, 0x00540004, 0x00540004, 0x00540004, 0x00540004,
   0x00180005, 0x00180005, 0x00180005, 0x00180005, 0x00180005, 0x00180005,
   0x00180005, 0x00180005, 0x00180005, 0x00180005, 0x00180005, 0x00180005,
   0x00180005, 0x00180005, 0x00180005, 0x00180005, 0x00180005, 0x00180005,
   0x00180005, 0x00180005, 0x00180005, 0x00180005, 0x00180005, 0x00180005,
   0x00180005, 0x00180005, 0x00180005, 0x00180005, 0x00180005, 0x00180005,
   0x00180005, 0x00180005, 0x00180005, 0x00180005, 0x00180005, 0x00180005,
   0x00180005, 0x00180005, 0x00180005, 0x00180005, 0x00180005, 0x00180005,
   0x00180005, 0x00180005, 0x00180005, 0x00180005, 0x00180005, 0x00180005,
   0x00180005, 0x00180005, 0x00180005, 0x00180005, 0x00180005, 0x00180005,
   0x00180005, 0x00180005, 0x00180005, 0x00180005, 0x00180005, 0x00180005,
   0x00180005, 0x00180005, 0x00180005, 0x00180005, 0x00580005, 0x00580005,
   0x00580005, 0x00580005, 0x00580005, 0x00580005, 0x00580005, 0x00580005,
   0x00580005, 0x00580005, 0x00580005, 0x00580005, 0x00580005, 0x00580005,
   0x00580005, 0x00580005, 0x00580005, 0x00580005, 0x00580005, 0x00580005,
   0x00580005, 0x00580005, 0x00580005, 0x00580005, 0x00580005, 0x00580005,
   0x00580005, 0x00580005, 0x00580005, 0x00580005, 0x00580005, 0x00580005,
   0x00580005, 0x00580005, 0x00580005, 0x00580005, 0x00580005, 0x00580005,
   0x00580005, 0x00580005, 0x00580005, 0x00580005, 0x00580005, 0x00580005,
   0x00580005, 0x00580005, 0x00580005, 0x00580005, 0x00580005, 0x00580005,
   0x00580005, 0x00580005, 0x00580005, 0x00580005, 0x00580005, 0x00580005,
   0x00580005, 0x00580005, 0x00580005, 0x00580005, 0x00580005, 0x00580005,
   0x00580005, 0x00580005, 0x00180006, 0x00180006, 0x00180006, 0x00180006,
   0x00180006, 0x00180006, 0x00180006, 0x00180006, 0x00180006, 0x00180006,
   0x00180006, 0x00180006, 0x00180006, 0x00180006, 0x00180006, 0x00180006,
   0x00180006, 0x00180006, 0x00180006, 0x00180006, 0x00180006, 0x00180006,
   0x00180006, 0x00180006, 0x00180006, 0x00180006, 0x00180006, 0x00180006,
   0x00180006, 0x00180006, 0x00180006, 0x00180006, 0x00180006, 0x00180006,
   0x00180006, 0x00180006, 0x00180006, 0x00180006, 0x00180006, 0x00180006,
   0x00180006, 0x00180006, 0x00180006, 0x00180006, 0x00180006, 0x00180006,
   0x00180006, 0x00180006, 0x00180006, 0x00180006, 0x00180006, 0x00180006,
   0x00180006, 0x00180006, 0x00180006, 0x00180006, 0x00180006, 0x00180006,
   0x00180006, 0x00180006, 0x00180006, 0x00180006, 0x00180006, 0x00180006,
   0x00580006, 0x00580006, 0x00580006, 0x00580006, 0x00580006, 0x00580006,
   0x00580006, 0x00580006, 0x00580006, 0x00580006, 0x00580006, 0x00580006,
   0x00580006, 0x00580006, 0x00580006, 0x00580006, 0x00580006, 0x00580006,
   0x00580006, 0x00580006, 0x00580006, 0x00580006, 0x00580006, 0x00580006,
   0x00580006, 0x00580006, 0x00580006, 0x00580006, 0x00580006, 0x00580006,
   0x00580006, 0x00580006, 0x00580006, 0x00580006, 0x00580006, 0x00580006,
   0x00580006, 0x00580006, 0x00580006, 0x00580006, 0x00580006, 0x00580006,
   0x00580006, 0x00580006, 0x00580006, 0x00580006, 0x00580006, 0x00580006,
   0x00580006, 0x00580006, 0x00580006, 0x00580006, 0x00580006, 0x00580006,
   0x00580006, 0x00580006, 0x00580006, 0x00580006, 0x00580006, 0x00580006,
   0x00580006, 0x00580006, 0x00580006, 0x00580006, 0x00D88004, 0x00D88004,
   0x00D88004, 0x00D88004, 0x00D88004, 0x00D88004, 0x00D88004, 0x00D88004,
   0x00D88004, 0x00D88004, 0x00D88004, 0x00D88004, 0x00D88004, 0x00D88004,
   0x00D88004, 0x00D88004, 0x00D88004, 0x00D88004, 0x00D88004, 0x00D88004,
   0x00D88004, 0x00D88004, 0x00D88004, 0x00D88004, 0x00D88004, 0x00D88004,
   0x00D88004, 0x00D88004, 0x00D88004, 0x00D88004, 0x00D88004, 0x00D88004,
   0x00D88004, 0x00D88004, 0x00D88004, 0x00D88004, 0x00D88004, 0x00D88004,
   0x00D88004, 0x00D88004, 0x00D88004, 0x00D88004, 0x00D88004, 0x00D88004,
   0x00D88004, 0x00D88004, 0x00D88004, 0x00D88004, 0x00D88004, 0x00D88004,
   0x00D88004, 0x00D88004, 0x00D88004, 0x00D88004, 0x00D88004, 0x00D88004,
   0x00D88004, 0x00D88004, 0x00D88004, 0x00D88004, 0x00D88004, 0x00D88004,
   0x00D88004, 0x00D88004, 0x001C0007, 0x001C0007, 0x001C0007, 0x001C0007,
   0x001C0007, 0x001C0007, 0x001C0007, 0x001C0007, 0x001C0007, 0x001C0007,
   0x001C0007, 0x001C0007, 0x001C0007, 0x001C0007, 0x001C0007, 0x001C0007,
   0x001C0007, 0x001C0007, 0x001C0007, 0x001C0007, 0x001C0007, 0x001C0007,
   0x001C0007, 0x001C0007, 0x001C0007, 0x001C0007, 0x001C0007, 0x001C0007,
   0x001C0007, 0x001C0007, 0x001C0007, 0x001C0007, 0x005C0007, 0x005C0007,
   0x005C0007, 0x005C0007, 0x005C0007, 0x005C0007, 0x005C0007, 0x005C0007,
   0x005C0007, 0x005C0007, 0x005C0007, 0x005C0007, 0x005C0007, 0x005C0007,
   0x005C0007, 0x005C0007, 0x005C0007, 0x005C0007, 0x005C0007, 0x005C0007,
   0x005C0007, 0x005C0007, 0x005C0007, 0x005C0007, 0x005C0007, 0x005C0007,
   0x005C0007, 0x005C0007, 0x005C0007, 0x005C0007, 0x005C0007, 0x005C0007,
   0x001C0008, 0x001C0008, 0x001C0008, 0x001C0008, 0x001C0008, 0x001C0008,
   0x001C0008, 0x001C0008, 0x001C0008, 0x001C0008, 0x001C0008, 0x001C0008,
   0x001C0008, 0x001C0008, 0x001C0008, 0x001C0008, 0x001C0008, 0x001C0008,
   0x001C0008, 0x001C0008, 0x001C0008, 0x001C0008, 0x001C0008, 0x001C0008,
   0x001C0008, 0x001C0008, 0x001C0008, 0x001C0008, 0x001C0008, 0x001C0008,
   0x001C0008, 0x001C0008, 0x005C0008, 0x005C0008, 0x005C0008, 0x005C0008,
   0x005C0008, 0x005C0008, 0x005C0008, 0x005C0008, 0x005C0008, 0x005C0008,
   0x005C0008, 0x005C0008, 0x005C0008, 0x005C0008, 0x005C0008, 0x005C0008,
   0x005C0008, 0x005C0008, 0x005C0008, 0x005C0008, 0x005C0008, 0x005C0008,
   0x005C0008, 0x005C0008, 0x005C0008, 0x005C0008, 0x005C0008, 0x005C0008,
   0x005C0008, 0x005C0008, 0x005C0008, 0x005C0008, 0x001C0009, 0x001C0009,
   0x001C0009, 0x001C0009, 0x001C0009, 0x001C0009, 0x001C0009, 0x001C0009,
   0x001C0009, 0x001C0009, 0x001C0009, 0x001C0009, 0x001C0009, 0x001C0009,
   0x001C0009, 0x001C0009, 0x001C0009, 0x001C0009, 0x001C0009, 0x001C0009,
   0x001C0009, 0x001C0009, 0x001C0009, 0x001C0009, 0x001C0009, 0x001C0009,
   0x001C0009, 0x001C0009, 0x001C0009, 0x001C0009, 0x001C0009, 0x001C0009,
   0x005C0009, 0x005C0009, 0x005C0009, 0x005C0009, 0x005C0009, 0x005C0009,
   0x005C0009, 0x005C0009, 0x005C0009, 0x005C0009, 0x005C0009, 0x005C0009,
   0x005C0009, 0x005C0009, 0x005C0009, 0x005C0009, 0x005C0009, 0x005C0009,
   0x005C0009, 0x005C0009, 0x005C0009, 0x005C0009, 0x005C0009, 0x005C0009,
   0x005C0009, 0x005C0009, 0x005C0009, 0x005C0009, 0x005C0009, 0x005C0009,
   0x005C0009, 0x005C0009, 0x001D8040, 0x001D8040, 0x001D8040, 0x001D8040,
   0x001D8040, 0x001D8040, 0x001D8040, 0x001D8040, 0x001D8040, 0x001D8040,
   0x001D8040, 0x001D8040, 0x001D8040, 0x001D8040, 0x001D8040, 0x001D8040,
   0x001D8040, 0x001D8040, 0x001D8040, 0x001D8040, 0x001D8040, 0x001D8040,
   0x001D8040, 0x001D8040, 0x001D8040, 0x001D8040, 0x001D8040, 0x001D8040,
   0x001D8040, 0x001D8040, 0x001D8040, 0x001D8040, 0x005D8040, 0x005D8040,
   0x005D8040, 0x005D8040, 0x005D8040, 0x005D8040, 0x005D8040, 0x005D8040,
   0x005D8040, 0x005D8040, 0x005D8040, 0x005D8040, 0x005D8040, 0x005D8040,
   0x005D8040, 0x005D8040, 0x005D8040, 0x005D8040, 0x005D8040, 0x005D8040,
   0x005D8040, 0x005D8040, 0x005D8040, 0x005D8040, 0x005D8040, 0x005D8040,
   0x005D8040, 0x005D8040, 0x005D8040, 0x005D8040, 0x005D8040, 0x005D8040,
   0x00DCC008, 0x00DCC008, 0x00DCC008, 0x00DCC008, 0x00DCC008, 0x00DCC008,
   0x00DCC008, 0x00DCC008, 0x00DCC008, 0x00DCC008, 0x00DCC008, 0x00DCC008,
   0x00DCC008, 0x00DCC008, 0x00DCC008, 0x00DCC008, 0x00DCC008, 0x00DCC008,
   0x00DCC008, 0x00DCC008, 0x00DCC008, 0x00DCC008, 0x00DCC008, 0x00DCC008,
   0x00DCC008, 0x00DCC008, 0x00DCC008, 0x00DCC008, 0x00DCC008, 0x00DCC008,
   0x00DCC008, 0x00DCC008, 0x0020000A, 0x0020000A, 0x0020000A, 0x0020000A,
   0x0020000A, 0x0020000A, 0x0020000A, 0x0020000A, 0x0020000A, 0x0020000A,
   0x0020000A, 0x0020000A, 0x0020000A, 0x0020000A, 0x0020000A, 0x0020000A,
   0x0060000A, 0x0060000A, 0x0060000A, 0x0060000A, 0x0060000A, 0x0060000A,
   0x0060000A, 0x0060000A, 0x0060000A, 0x0060000A, 0x0060000A, 0x0060000A,
   0x0060000A, 0x0060000A, 0x0060000A, 0x0060000A, 0x0020000B, 0x0020000B,
   0x0020000B, 0x0020000B, 0x0020000B, 0x0020000B, 0x0020000B, 0x0020000B,
   0x0020000B, 0x0020000B, 0x0020000B, 0x0020000B, 0x0020000B, 0x0020000B,
   0x0020000B, 0x0020000B, 0x0060000B, 0x0060000B, 0x0060000B, 0x0060000B,
   0x0060000B, 0x0060000B, 0x0060000B, 0x0060000B, 0x0060000B, 0x0060000B,
   0x0060000B, 0x0060000B, 0x0060000B, 0x0060000B, 0x0060000B, 0x0060000B,
   0x0020000C, 0x0020000C, 0x0020000C, 0x0020000C, 0x0020000C, 0x0020000C,
   0x0020000C, 0x0020000C, 0x0020000C, 0x0020000C, 0x0020000C, 0x0020000C,
   0x0020000C, 0x0020000C, 0x0020000C, 0x0020000C, 0x0060000C, 0x0060000C,
   0x0060000C, 0x0060000C, 0x0060000C, 0x0060000C, 0x0060000C, 0x0060000C,
   0x0060000C, 0x0060000C, 0x0060000C, 0x0060000C, 0x0060000C, 0x0060000C,
   0x0060000C, 0x0060000C, 0x0020000D, 0x0020000D, 0x0020000D, 0x0020000D,
   0x0020000D, 0x0020000D, 0x0020000D, 0x0020000D, 0x0020000D, 0x0020000D,
   0x0020000D, 0x0020000D, 0x0020000D, 0x0020000D, 0x0020000D, 0x0020000D,
   0x0060000D, 0x0060000D, 0x0060000D, 0x0060000D, 0x0060000D, 0x0060000D,
   0x0060000D, 0x0060000D, 0x0060000D, 0x0060000D, 0x0060000D, 0x0060000D,
   0x0060000D, 0x0060000D, 0x0060000D, 0x0060000D, 0x00E10010, 0x00E10010,
   0x00E10010, 0x00E10010, 0x00E10010, 0x00E10010, 0x00E10010, 0x00E10010,
   0x00E10010, 0x00E10010, 0x00E10010, 0x00E10010, 0x00E10010, 0x00E10010,
   0x00E10010, 0x00E10010, 0x0024000E, 0x0024000E, 0x0024000E, 0x0024000E,
   0x0024000E, 0x0024000E, 0x0024000E, 0x0024000E, 0x0064000E, 0x0064000E,
   0x0064000E, 0x0064000E, 0x0064000E, 0x0064000E, 0x0064000E, 0x0064000E,
   0x0024000F, 0x0024000F, 0x0024000F, 0x0024000F, 0x0024000F, 0x0024000F,
   0x0024000F, 0x0024000F, 0x0064000F, 0x0064000F, 0x0064000F, 0x0064000F,
   0x0064000F, 0x0064000F, 0x0064000F, 0x0064000F, 0x00240010, 0x00240010,
   0x00240010, 0x00240010, 0x00240010, 0x00240010, 0x00240010, 0x00240010,
   0x00640010, 0x00640010, 0x00640010, 0x00640010, 0x00640010, 0x00640010,
   0x00640010, 0x00640010, 0x00240011, 0x00240011, 0x00240011, 0x00240011,
   0x00240011, 0x00240011, 0x00240011, 0x00240011, 0x00640011, 0x00640011,
   0x00640011, 0x00640011, 0x00640011, 0x00640011, 0x00640011, 0x00640011,
   0x00240012, 0x00240012, 0x00240012, 0x00240012, 0x00240012, 0x00240012,
   0x00240012, 0x00240012, 0x00640012, 0x00640012, 0x00640012, 0x00640012,
   0x00640012, 0x00640012, 0x00640012, 0x00640012, 0x00A42000, 0x00A42000,
   0x00A42000, 0x00A42000, 0x00A42000, 0x00A42000, 0x00A42000, 0x00A42000,
   0x00E54020, 0x00E54020, 0x00E54020, 0x00E54020, 0x00E54020, 0x00E54020,
   0x00E54020, 0x00E54020, 0x00280013, 0x00280013, 0x00280013, 0x00280013,
   0x00680013, 0x00680013, 0x00680013, 0x00680013, 0x00280014, 0x00280014,
   0x00280014, 0x00280014, 0x00680014, 0x00680014, 0x00680014, 0x00680014,
   0x00280015, 0x00280015, 0x00280015, 0x00280015, 0x00680015, 0x00680015,
   0x00680015, 0x00680015, 0x00280016, 0x00280016, 0x00280016, 0x00280016,
   0x00680016, 0x00680016, 0x00680016, 0x00680016, 0x00280017, 0x00280017,
   0x00280017, 0x00280017, 0x00680017, 0x00680017, 0x00680017, 0x00680017,
   0x00280018, 0x00280018, 0x00280018, 0x00280018, 0x00680018, 0x00680018,
   0x00680018, 0x00680018, 0x00280019, 0x00280019, 0x00280019, 0x00280019,
   0x00680019, 0x00680019, 0x00680019, 0x00680019, 0x0028001A, 0x0028001A,
   0x0028001A, 0x0028001A, 0x0068001A, 0x0068001A, 0x0068001A, 0x0068001A,
   0x00E98040, 0x00E98040, 0x00E98040, 0x00E98040, 0x00E9C080, 0x00E9C080,
   0x00E9C080, 0x00E9C080, 0x002C001B, 0x002C001B, 0x006C001B, 0x006C001B,
   0x002C001C, 0x002C001C, 0x006C001C, 0x006C001C, 0x002C001D, 0x002C001D,
   0x006C001D, 0x006C001D, 0x002C001E, 0x002C001E, 0x006C001E, 0x006C001E,
   0x002C001F, 0x002C001F, 0x006C001F, 0x006C001F, 0x002C0020, 0x002C0020,
   0x006C0020, 0x006C0020, 0x002C0021, 0x002C0021, 0x006C0021, 0x006C0021,
   0x002C0022, 0x002C0022, 0x006C0022, 0x006C0022, 0x002C0023, 0x002C0023,
   0x006C0023, 0x006C0023, 0x002C0024, 0x002C0024, 0x006C0024, 0x006C0024,
   0x002C003F, 0x002C003F, 0x006DC080, 0x006DC080, 0x00EE0100, 0x00EE0100,
   0x00300025, 0x00700025, 0x00300026, 0x00700026, 0x00300027, 0x00700027,
   0x00300028, 0x00700028, 0x00300029, 0x00700029, 0x0030002A, 0x0070002A,
   0x0030002B, 0x0070002B, 0x0030002C, 0x0070002C, 0x0030002D, 0x0070002D,
   0x0030002E, 0x0070002E, 0x0030002F, 0x0070002F, 0x00300030, 0x00700030,
   0x00300031, 0x00700031, 0x00300032, 0x00700032, 0x00300033, 0x00700033,
   0x00300034, 0x00700034, 0x00300035, 0x00700035, 0x00300036, 0x00700036,
   0x00300037, 0x00700037, 0x00300038, 0x00700038, 0x00300039, 0x00700039,
   0x0030003A, 0x0070003A, 0x0030003B, 0x0070003B, 0x0030003C, 0x0070003C,
   0x0030003D, 0x0070003D, 0x0030003E, 0x0070003E, 0x0070003F, 0x0031C080,
   0x00F24200, 0x00F28400, 0x00F2C800, 0x00F31000,
];
commūnis [144]n64 p4f_enc = n64.[
   0x0300000000, 0x0300000001, 0x0300000002, 0x0400000006, 0x0400000007, 0x0400000008,
   0x0400000009, 0x0500000016, 0x0500000017, 0x0600000030, 0x0600000031, 0x0600000032,
   0x0600000033, 0x070000006A, 0x070000006B, 0x070000006C, 0x070000006D, 0x070000006E,
   0x070000006F, 0x08000000E6, 0x08000000E7, 0x08000000E8, 0x08000000E9, 0x08000000EA,
   0x08000000EB, 0x08000000EC, 0x08000000ED, 0x09000001DE, 0x09000001DF, 0x09000001E0,
   0x09000001E1, 0x09000001E2, 0x09000001E3, 0x09000001E4, 0x09000001E5, 0x09000001E6,
   0x09000001E7, 0x0A000003D4, 0x0A000003D5, 0x0A000003D6, 0x0A000003D7, 0x0A000003D8,
   0x0A000003D9, 0x0A000003DA, 0x0A000003DB, 0x0A000003DC, 0x0A000003DD, 0x0A000003DE,
   0x0A000003DF, 0x0A000003E0, 0x0A000003E1, 0x0A000003E2, 0x0A000003E3, 0x0B000007CC,
   0x0B000007CD, 0x0B000007CE, 0x0B000007CF, 0x0B000007D0, 0x0B000007D1, 0x0B000007D2,
   0x0B000007D3, 0x0B000007D4, 0x0B000007D5, 0x0B000007D6, 0x0B000007D7, 0x0B000007D8,
   0x0B000007D9, 0x0B000007DA, 0x0B000007DB, 0x0B000007DC, 0x0B000007DD, 0x0B000007DE,
   0x0B000007DF, 0x0C00000FC6, 0x0C00000FC7, 0x0C00000FC8, 0x0C00000FC9, 0x0C00000FCA,
   0x0C00000FCB, 0x0C00000FCC, 0x0C00000FCD, 0x0C00000FCE, 0x0C00000FCF, 0x0C00000FD0,
   0x0C00000FD1, 0x0C00000FD2, 0x0C00000FD3, 0x0C00000FD4, 0x0C00000FD5, 0x0C00000FD6,
   0x0C00000FD7, 0x0C00000FD8, 0x0C00000FD9, 0x0C00000FDA, 0x0C00000FDB, 0x0C00000FDC,
   0x0C00000FDD, 0x0C00000FDE, 0x0C00000FDF, 0x0C00000FE0, 0x0C00000FE1, 0x0C00000FE2,
   0x0C00000FE3, 0x0C00000FE4, 0x0C00000FE5, 0x0C00000FE6, 0x0C00000FE7, 0x0C00000FE8,
   0x0C00000FE9, 0x0C00000FEA, 0x0C00000FEB, 0x0C00000FEC, 0x0C00000FED, 0x0C00000FEE,
   0x0C00000FEF, 0x0C00000FF0, 0x0C00000FF1, 0x0C00000FF2, 0x0C00000FF3, 0x0C00000FF4,
   0x0C00000FF5, 0x0C00000FF6, 0x0C00000FF7, 0x0C00000FF8, 0x0C00000FF9, 0x0B000007E0,
   0x0C00000FFA, 0x0700000070, 0x0700000071, 0x0C00000FFB, 0x0B000007E1, 0x09000001E8,
   0x040000000A, 0x0600000034, 0x0700000072, 0x08000000EE, 0x09000001E9, 0x0A000003E4,
   0x0A000003E5, 0x0B000007E2, 0x0C00000FFC, 0x0C00000FFD, 0x0C00000FFE, 0x0C00000FFF,
];
// A residual byte decides everything the encoder emits for it: which
// token, and the mantissa that follows. The table holds the finished
// emission, codeword and mantissa already concatenated.
//   bits 0..18  the bits to emit, MSB-first in the low bits
//   bits 19..23 how many of them
commūnis [256]n32 p4f_res = n32.[
   0x00000000, 0x00180001, 0x00200006, 0x00200008, 0x00280016, 0x00300030,
   0x00300032, 0x0038006A, 0x0038006C, 0x0038006E, 0x004000E6, 0x004000E8,
   0x004000EA, 0x004000EC, 0x004801DE, 0x004801E0, 0x004801E2, 0x004801E4,
   0x004801E6, 0x005003D4, 0x005003D6, 0x005003D8, 0x005003DA, 0x005003DC,
   0x005003DE, 0x005003E0, 0x005003E2, 0x005807CC, 0x005807CE, 0x005807D0,
   0x005807D2, 0x005807D4, 0x005807D6, 0x005807D8, 0x005807DA, 0x005807DC,
   0x005807DE, 0x00600FC6, 0x00600FC8, 0x00600FCA, 0x00600FCC, 0x00600FCE,
   0x00600FD0, 0x00600FD2, 0x00600FD4, 0x00600FD6, 0x00600FD8, 0x00600FDA,
   0x00600FDC, 0x00600FDE, 0x00600FE0, 0x00600FE2, 0x00600FE4, 0x00600FE6,
   0x00600FE8, 0x00600FEA, 0x00600FEC, 0x00600FEE, 0x00600FF0, 0x00600FF2,
   0x00600FF4, 0x00600FF6, 0x00600FF8, 0x005807E0, 0x00681C00, 0x00681C01,
   0x00681C02, 0x00681C03, 0x00681C04, 0x00681C05, 0x00681C06, 0x00681C07,
   0x00681C08, 0x00681C09, 0x00681C0A, 0x00681C0B, 0x00681C0C, 0x00681C0D,
   0x00681C0E, 0x00681C0F, 0x00681C10, 0x00681C11, 0x00681C12, 0x00681C13,
   0x00681C14, 0x00681C15, 0x00681C16, 0x00681C17, 0x00681C18, 0x00681C19,
   0x00681C1A, 0x00681C1B, 0x00681C1C, 0x00681C1D, 0x00681C1E, 0x00681C1F,
   0x00681C20, 0x00681C21, 0x00681C22, 0x00681C23, 0x00681C24, 0x00681C25,
   0x00681C26, 0x00681C27, 0x00681C28, 0x00681C29, 0x00681C2A, 0x00681C2B,
   0x00681C2C, 0x00681C2D, 0x00681C2E, 0x00681C2F, 0x00681C30, 0x00681C31,
   0x00681C32, 0x00681C33, 0x00681C34, 0x00681C35, 0x00681C36, 0x00681C37,
   0x00681C38, 0x00681C39, 0x00681C3A, 0x00681C3B, 0x00681C3C, 0x00681C3D,
   0x00681C3E, 0x00681C3F, 0x0093F080, 0x00681C7F, 0x00681C7E, 0x00681C7D,
   0x00681C7C, 0x00681C7B, 0x00681C7A, 0x00681C79, 0x00681C78, 0x00681C77,
   0x00681C76, 0x00681C75, 0x00681C74, 0x00681C73, 0x00681C72, 0x00681C71,
   0x00681C70, 0x00681C6F, 0x00681C6E, 0x00681C6D, 0x00681C6C, 0x00681C6B,
   0x00681C6A, 0x00681C69, 0x00681C68, 0x00681C67, 0x00681C66, 0x00681C65,
   0x00681C64, 0x00681C63, 0x00681C62, 0x00681C61, 0x00681C60, 0x00681C5F,
   0x00681C5E, 0x00681C5D, 0x00681C5C, 0x00681C5B, 0x00681C5A, 0x00681C59,
   0x00681C58, 0x00681C57, 0x00681C56, 0x00681C55, 0x00681C54, 0x00681C53,
   0x00681C52, 0x00681C51, 0x00681C50, 0x00681C4F, 0x00681C4E, 0x00681C4D,
   0x00681C4C, 0x00681C4B, 0x00681C4A, 0x00681C49, 0x00681C48, 0x00681C47,
   0x00681C46, 0x00681C45, 0x00681C44, 0x00681C43, 0x00681C42, 0x00681C41,
   0x00681C40, 0x00600FFA, 0x00600FF9, 0x00600FF7, 0x00600FF5, 0x00600FF3,
   0x00600FF1, 0x00600FEF, 0x00600FED, 0x00600FEB, 0x00600FE9, 0x00600FE7,
   0x00600FE5, 0x00600FE3, 0x00600FE1, 0x00600FDF, 0x00600FDD, 0x00600FDB,
   0x00600FD9, 0x00600FD7, 0x00600FD5, 0x00600FD3, 0x00600FD1, 0x00600FCF,
   0x00600FCD, 0x00600FCB, 0x00600FC9, 0x00600FC7, 0x005807DF, 0x005807DD,
   0x005807DB, 0x005807D9, 0x005807D7, 0x005807D5, 0x005807D3, 0x005807D1,
   0x005807CF, 0x005807CD, 0x005003E3, 0x005003E1, 0x005003DF, 0x005003DD,
   0x005003DB, 0x005003D9, 0x005003D7, 0x005003D5, 0x004801E7, 0x004801E5,
   0x004801E3, 0x004801E1, 0x004801DF, 0x004000ED, 0x004000EB, 0x004000E9,
   0x004000E7, 0x0038006F, 0x0038006D, 0x0038006B, 0x00300033, 0x00300031,
   0x00280017, 0x00200009, 0x00200007, 0x00180002,
];

// pictor4_asm.lbc -- the BTPNGF1 symbol loop in hand-written RISC-V.
//
// Same format, same bytes. What is in assembly is the part that dominates
// both directions: the per-symbol loop, where every instruction sits in a
// loop-carried chain and the compiler's register allocation has to be
// exactly right or the bit cursor spills.
//
// ABI, from compiler/no_tree_rv.lbc and bootloader/rv_atomic_queues.lbc:
// Brevis passes arguments in x8..x31 and returns in x8, x9, x10, ... A
// compīlāta body is entered with the frame already banked (ra and tp); it
// leaves with `c.mv sp tp` then `c.ret`. Registers that carry parameters
// are the callee's to clobber, which is why the trailing z0..z5 exist:
// declaring them as parameters is how this file claims x17..x22 as
// scratch without guessing what the allocator considers volatile.
//
// The instructions are plain RV64GC. The C906 has T-Head custom opcodes
// and RVV 0.7, the U74 has neither, and there is no macro that tells them
// apart -- both targets report TARGET_CPU_RV64GCV0_7 and the VF2L
// restriction is only a ban on what the compiler itself may emit. Hand
// assembly bypasses that ban, so anything board-specific has to be a
// separate procedure that the board-specific driver alone calls.



/*  One row of one plane: residuals to tokens. The mirror of the decode
    loop, and the same shape -- state in registers for the whole row, one
    table load per symbol, bytes leaving the accumulator as they fill.

    x8  dst base        x15 enc table (len<<32 | code)
    x9  at              x16 one past the last storable byte
    x10 acc             x17 x (column)
    x11 nb              x18 e (residual byte)
    x12 rc row          x19 token / length
    x13 w               x20 x21 x22 scratch
    x14 residual -> emitted bits, 256 entries
    x23 write pointer   x24 the constant 8

    Returns (at, acc, nb) in x8, x9, x10.
*/
prōcēdūra compīlāta p4a_encode_row(@n8 dst; n64 at; n64 acc; n64 nb; @s8 rc;
                                   n64 w; @n64 res; @n64 enc; n64 cap;
                                   n64 z0; n64 z1; n64 z2; n64 z3; n64 z4;
                                   n64 z5; n64 z6; n64 z7; -> n64; n64; n64;)
***
   li x17 0
   add x16 x8 x16                 // one past the last byte that may be stored
   add x23 x8 x9                  // the write pointer, so a byte costs no add
   li x24 8

p4e_row:
   bgeu x17 x13 p4e_done
   add x20 x12 x17
   lbu x18 0(x20)
   beqz x18 p4e_zero

   // ---- nonzero residual: the byte indexes its own emission. Which
   // token it is, and the mantissa that follows, are both decided by the
   // residual byte alone -- so the table holds the finished bits and the
   // hot path loses a magnitude, a compare ladder and three branches.
   slli x21 x18 2
   add x21 x14 x21
   lwu x21 0(x21)
   srli x20 x21 19                // how many bits
   slli x19 x21 45
   srli x19 x19 45                // the bits themselves
   sll x10 x10 x20
   or x10 x10 x19
   add x11 x11 x20
   addi x17 x17 1
   j p4e_drain

p4e_zero:
   // ---- a zero: scan the run, then EOL, single zero, or a run token
   addi x20 x17 1
p4e_scan:
   // to the next 8-byte boundary one byte at a time
   bgeu x20 x13 p4e_scan_end
   add x21 x12 x20
   andi x22 x21 7
   beqz x22 p4e_scan_word
   lb x21 0(x21)
   bnez x21 p4e_scan_end
   addi x20 x20 1
   j p4e_scan
p4e_scan_word:
   // eight zero bytes at a time; the row's stride is 8-aligned so this
   // load never straddles
   addi x22 x20 8
   bltu x13 x22 p4e_scan_tail
   add x21 x12 x20
   ld x21 0(x21)
   bnez x21 p4e_scan_tail
   mv x20 x22
   j p4e_scan_word
p4e_scan_tail:
   bgeu x20 x13 p4e_scan_end
   add x21 x12 x20
   lb x21 0(x21)
   bnez x21 p4e_scan_end
   addi x20 x20 1
   j p4e_scan_tail
p4e_scan_end:
   sub x21 x20 x17                // run length
   bltu x20 x13 p4e_notend

   // reaches the end of the row: one EOL token, and the row is finished
   li x19 131
   li x20 0
   li x21 0
   mv x17 x13
   j p4e_emit

p4e_notend:
   li x22 1
   bne x21 x22 p4e_runtok
   li x19 0                       // the single-zero token
   li x20 0
   li x21 0
   addi x17 x17 1
   j p4e_emit

p4e_runtok:
   add x17 x17 x21                // advance by the whole run
   li x22 8191
   bgeu x22 x21 p4e_runok
   mv x21 x22
p4e_runok:
   // j = floor(log2 run), by shifting down; runs are short so this is
   // cheaper than any table and has no memory in the chain
   li x20 0
   mv x22 x21
p4e_log:
   srli x22 x22 1
   beqz x22 p4e_logdone
   addi x20 x20 1
   j p4e_log
p4e_logdone:
   li x19 132
   add x19 x19 x20
   addi x19 x19 -1                // token = RUN + j - 1
   li x22 1
   sll x22 x22 x20
   sub x21 x21 x22                // mantissa = run - (1 << j)
   j p4e_emit

p4e_emit:
   // x19 token, x20 mantissa width, x21 mantissa
   slli x22 x19 3
   add x22 x15 x22
   ld x22 0(x22)                  // enc[token]
   srli x19 x22 32
   andi x19 x19 255               // code length
   slli x22 x22 48
   srli x22 x22 48                // codeword
   sll x10 x10 x19
   or x10 x10 x22
   add x11 x11 x19
   beqz x20 p4e_drain
   sll x10 x10 x20
   or x10 x10 x21
   add x11 x11 x20

p4e_drain:
   bltu x11 x24 p4e_row
   addi x11 x11 -8
   bgeu x23 x16 p4e_nostore
   srl x22 x10 x11                // sb keeps the low byte: no mask
   sb x22 0(x23)
p4e_nostore:
   addi x23 x23 1
   j p4e_drain

p4e_done:
   sub x8 x23 x8                  // the write position it reached
   mv x9 x10
   mv x10 x11
   c.mv sp tp
   c.ret
***

/*  The inverse colour transform and the RGBA interleave for one row.

    Every pixel here is independent -- no prediction, no neighbours -- so
    this is the one part of decode that is pure straight-line work. It
    stays scalar because RVV 0.7 exists only on the C906 and a single
    image has to run on both boards.

    x8 y row  x9 co row  x10 cg row  x11 a row  x12 out  x13 w
*/
prōcēdūra compīlāta p4a_ycocg_row(@n8 yr; @n8 cor; @n8 cgr; @n8 ar; @n8 out;
                                  n64 w; n64 z0; n64 z1; n64 z2; n64 z3;
                                  n64 z4; n64 z5; n64 z6; n64 z7; n64 z8;
                                  -> n64;)
***
   li x14 0

p4y_loop:
   bgeu x14 x13 p4y_done
   add x15 x8 x14
   lbu x15 0(x15)                 // y
   add x16 x9 x14
   lbu x16 0(x16)                 // co
   add x17 x10 x14
   lbu x17 0(x17)                 // cg

   // t = (y - (cg as int8 >> 1)) & 255
   slli x18 x17 56
   srai x18 x18 56
   srai x18 x18 1
   sub x18 x15 x18
   andi x18 x18 255               // t
   add x19 x17 x18
   andi x19 x19 255               // g
   slli x20 x16 56
   srai x20 x20 56
   srai x20 x20 1
   sub x20 x18 x20
   andi x20 x20 255               // b
   add x21 x20 x16
   andi x21 x21 255               // r

   slli x22 x14 2
   add x22 x12 x22
   sb x20 0(x22)                  // b
   sb x19 1(x22)                  // g
   sb x21 2(x22)                  // r
   add x15 x11 x14
   lbu x15 0(x15)
   sb x15 3(x22)                  // x
   addi x14 x14 1
   j p4y_loop

p4y_done:
   li x8 0
   c.mv sp tp
   c.ret
***

/*  Symbols straight to samples, in one pass.

    The two-pass shape writes a residual row, reads it back and adds the
    prediction. At 768 wide that is a memset, a store and a load per
    sample per plane -- three passes over memory for data that is
    consumed immediately. Here a token becomes a pixel before the next
    token is read, and the residual row never exists.

    A run still predicts every pixel, but not the hard way: where T equals
    TL the clamp collapses to L exactly, so the sample is the one already
    in hand and nothing but the store has to happen. That is the whole of
    a flat region, and row 0 as well -- its row above reads as zeros, so
    T = TL = 0 and the prediction is L, which is what row 0 wants.

    x8  src base      x16 decode table     x22 T
    x9  at            x18 x (column)       x23 entry
    x10 end           x19 L                x24 scratch
    x11 acc           x20 TL               x25 scratch
    x12 nb            x21 scratch
    x13 cur row
    x14 prv row
    x15 w

    Returns (ok, at, acc, nb) in x8, x9, x10, x11.
*/
prōcēdūra compīlāta p4a_dec_rec_row(@n8 src; n64 at; n64 end; n64 acc; n64 nb;
                                    @n8 cur; @n8 prv; n64 w; @n64 root;
                                    n64 z0; n64 z1; n64 z2; n64 z3; n64 z4;
                                    n64 z5; n64 z6; n64 z7; n64 z8;
                                    -> n64; n64; n64; n64;)
***
   li x18 0
   li x19 0                       // L, zero before the first pixel
   li x20 0                       // TL

p4f_row:
   bgeu x18 x15 p4f_done

p4f_refill:
   li x21 56
   bltu x21 x12 p4f_have
   add x24 x8 x9
   bgeu x9 x10 p4f_pad
   lbu x21 0(x24)
   j p4f_shift
p4f_pad:
   li x21 0
p4f_shift:
   addi x9 x9 1
   li x24 56
   sub x24 x24 x12
   sll x21 x21 x24
   or x11 x11 x21
   addi x12 x12 8
   j p4f_refill

p4f_have:
   srli x21 x11 52
   slli x21 x21 2
   add x21 x16 x21
   lwu x23 0(x21)
   srli x24 x23 18
   andi x24 x24 15                // len
   beqz x24 p4f_fail
   sll x11 x11 x24
   sub x12 x12 x24

   slli x21 x23 50
   srli x21 x21 50                // base
   srli x24 x23 14
   andi x24 x24 15                // mantissa width
   beqz x24 p4f_nomant
   li x25 64
   sub x25 x25 x24
   srl x25 x11 x25
   add x21 x21 x25
   sll x11 x11 x24
   sub x12 x12 x24
p4f_nomant:
   srli x24 x23 22
   andi x24 x24 3                 // kind
   li x25 2
   bgeu x24 x25 p4f_run

   // ---- one residual, one pixel
   beqz x24 p4f_pos
   sub x21 x0 x21
p4f_pos:
   // prediction
   add x22 x14 x18
   lbu x22 0(x22)                 // T
   beq x22 x20 p4f_flat           // T == TL: the clamp can only give L
   xor x24 x19 x22
   sltu x25 x22 x19
   sub x25 x0 x25
   and x25 x24 x25
   xor x24 x19 x25                // mn
   xor x25 x22 x25                // mx
   add x23 x19 x22
   sub x23 x23 x20                // g = L + T - TL
   bge x23 x24 p4f_ge
   mv x23 x24
p4f_ge:
   bge x25 x23 p4f_le
   mv x23 x25
p4f_le:
   mv x20 x22                     // TL = T
   j p4f_add
p4f_flat:
   mv x23 x19
p4f_add:
   add x21 x23 x21
   andi x21 x21 255
   add x24 x13 x18
   sb x21 0(x24)
   mv x19 x21                     // L
   addi x18 x18 1
   j p4f_row

p4f_run:
   // a span of zero residuals: every pixel is its own prediction
   sub x25 x15 x18
   bltu x21 x25 p4f_runok
   mv x21 x25
p4f_runok:
   beqz x21 p4f_fail
   add x25 x18 x21                // end of the span
p4f_runloop:
   bgeu x18 x25 p4f_row
   add x22 x14 x18
   lbu x22 0(x22)
   bne x22 x20 p4f_rmed           // the flat case: L again, and TL is T
   add x24 x13 x18
   sb x19 0(x24)
   addi x18 x18 1
   j p4f_runloop
p4f_rmed:
   xor x24 x19 x22
   sltu x23 x22 x19
   sub x23 x0 x23
   and x23 x24 x23
   xor x24 x19 x23                // mn
   xor x23 x22 x23                // mx
   add x21 x19 x22
   sub x21 x21 x20
   bge x21 x24 p4f_rge
   mv x21 x24
p4f_rge:
   bge x23 x21 p4f_rle
   mv x21 x23
p4f_rle:
   mv x20 x22
   andi x21 x21 255
   add x24 x13 x18
   sb x21 0(x24)
   mv x19 x21
   addi x18 x18 1
   j p4f_runloop

p4f_fail:
   mv x10 x11
   mv x11 x12
   li x8 0
   c.mv sp tp
   c.ret

p4f_done:
   mv x10 x11
   mv x11 x12
   li x8 1
   c.mv sp tp
   c.ret
***

// MEASURED DEAD ENDS, kept here so they are not tried twice.
//
//   Fusing the residual pass into the SYMBOL pass on the encode side --
// computing a residual, using it and dropping it, with the zero-run scan
// becoming "keep predicting until a pixel disagrees" -- is worth +1.3% on
// photographic content and -8% on a screenshot. The scan is why: the
// two-pass encoder finds a run with one aligned 8-byte load per eight
// pixels, and the fused one has to run MED for every pixel it skips.
// Fusing the COLOUR pass into the residual pass, which is what this file
// does below, is a different trade and wins on both.
//
//   Writing MED without branches -- min and max from k = min(L - T, 0),
// both clamps from the sign bit -- costs one instruction more per sample
// and measures -15.4% here and -4.2% on the C906. This core predicts the
// branches it removes almost perfectly.

/*  Colour transform and residuals for one row, in one pass.

    The two-pass shape writes four plane rows and reads them straight back
    to predict from them. Here a pixel is transformed and its four
    residuals fall out while the samples are still in registers; cur is
    written only because the NEXT row predicts from it, and is never read
    again.

    cur and prv hold the four samples INTERLEAVED -- Y, Co, Cg, X per
    pixel -- so the row above costs four loads off one line and no stride
    arithmetic. The residual rows stay planar: that is what the emitter
    scans.

    L and TL start at zero, which is exactly what row 0 and column 0 want.
    MED with T = TL = 0 clamps to L, and with L = TL = 0 clamps to T, so
    the two edge rules are the general rule here and cost no branch.

    x8  src    x11..x14 rr per plane   x16..x19 L per plane
    x9  cur    x15 src end             x20..x23 TL per plane
    x10 prv                            x24..x31 scratch
*/
prōcēdūra compīlāta p4a_ycocg_resid_row(@n8 src; @n8 cur; @n8 prv; @s8 rr0;
                                        @s8 rr1; @s8 rr2; @s8 rr3; n64 w;
                                        n64 z0; n64 z1; n64 z2; n64 z3;
                                        n64 z4; n64 z5; n64 z6; n64 z7;
                                        n64 z8; n64 z9; n64 z10; n64 z11;
                                        n64 z12; n64 z13; n64 z14; n64 z15;
                                        -> n64;)
***
   slli x15 x15 2
   add x15 x8 x15                 // one past the last pixel
   li x16 0
   li x17 0
   li x18 0
   li x19 0
   li x20 0
   li x21 0
   li x22 0
   li x23 0

p4c_loop:
   bgeu x8 x15 p4c_done

   lbu x24 0(x8)                  // b   XRGB8888 in memory is B,G,R,X
   lbu x25 1(x8)                  // g
   lbu x26 2(x8)                  // r
   lbu x27 3(x8)                  // x
   sub x28 x26 x24
   andi x28 x28 255               // co = r - b
   slli x29 x28 56
   srai x29 x29 56
   srai x29 x29 1
   add x29 x24 x29                // t = b + (co >> 1), left unwrapped:
   sub x30 x25 x29                // everything downstream of it is mod 256
   andi x30 x30 255               // cg = g - t
   slli x31 x30 56
   srai x31 x31 56
   srai x31 x31 1
   add x31 x29 x31
   andi x31 x31 255               // y = t + (cg >> 1)
   sb x31 0(x9)
   sb x28 1(x9)
   sb x30 2(x9)
   sb x27 3(x9)

   lbu x24 0(x10)                 // T
   bne x24 x20 p4c_ymed           // T == TL: the MED is L
   sub x29 x31 x16
   sb x29 0(x11)                   // sb keeps the low byte: no mask
   mv x16 x31
   j p4c_yend
p4c_ymed:
   mv x25 x16
   bgeu x24 x16 p4c_y1
   mv x25 x24                     // mn = min(L, T)
p4c_y1:
   mv x26 x24
   bgeu x24 x16 p4c_y2
   mv x26 x16                     // mx = max(L, T)
p4c_y2:
   add x29 x16 x24
   sub x29 x29 x20                // L + T - TL
   mv x20 x24
   bge x29 x25 p4c_y3
   mv x29 x25
p4c_y3:
   bge x26 x29 p4c_y4
   mv x29 x26
p4c_y4:
   sub x29 x31 x29
   sb x29 0(x11)
   mv x16 x31
p4c_yend:

   lbu x24 1(x10)                 // T
   bne x24 x21 p4c_omed           // T == TL: the MED is L
   sub x29 x28 x17
   sb x29 0(x12)                   // sb keeps the low byte: no mask
   mv x17 x28
   j p4c_oend
p4c_omed:
   mv x25 x17
   bgeu x24 x17 p4c_o1
   mv x25 x24                     // mn = min(L, T)
p4c_o1:
   mv x26 x24
   bgeu x24 x17 p4c_o2
   mv x26 x17                     // mx = max(L, T)
p4c_o2:
   add x29 x17 x24
   sub x29 x29 x21                // L + T - TL
   mv x21 x24
   bge x29 x25 p4c_o3
   mv x29 x25
p4c_o3:
   bge x26 x29 p4c_o4
   mv x29 x26
p4c_o4:
   sub x29 x28 x29
   sb x29 0(x12)
   mv x17 x28
p4c_oend:

   lbu x24 2(x10)                 // T
   bne x24 x22 p4c_gmed           // T == TL: the MED is L
   sub x29 x30 x18
   sb x29 0(x13)                   // sb keeps the low byte: no mask
   mv x18 x30
   j p4c_gend
p4c_gmed:
   mv x25 x18
   bgeu x24 x18 p4c_g1
   mv x25 x24                     // mn = min(L, T)
p4c_g1:
   mv x26 x24
   bgeu x24 x18 p4c_g2
   mv x26 x18                     // mx = max(L, T)
p4c_g2:
   add x29 x18 x24
   sub x29 x29 x22                // L + T - TL
   mv x22 x24
   bge x29 x25 p4c_g3
   mv x29 x25
p4c_g3:
   bge x26 x29 p4c_g4
   mv x29 x26
p4c_g4:
   sub x29 x30 x29
   sb x29 0(x13)
   mv x18 x30
p4c_gend:

   lbu x24 3(x10)                 // T
   bne x24 x23 p4c_xmed           // T == TL: the MED is L
   sub x29 x27 x19
   sb x29 0(x14)                   // sb keeps the low byte: no mask
   mv x19 x27
   j p4c_xend
p4c_xmed:
   mv x25 x19
   bgeu x24 x19 p4c_x1
   mv x25 x24                     // mn = min(L, T)
p4c_x1:
   mv x26 x24
   bgeu x24 x19 p4c_x2
   mv x26 x19                     // mx = max(L, T)
p4c_x2:
   add x29 x19 x24
   sub x29 x29 x23                // L + T - TL
   mv x23 x24
   bge x29 x25 p4c_x3
   mv x29 x25
p4c_x3:
   bge x26 x29 p4c_x4
   mv x29 x26
p4c_x4:
   sub x29 x27 x29
   sb x29 0(x14)
   mv x19 x27
p4c_xend:

   addi x8 x8 4
   addi x9 x9 4
   addi x10 x10 4
   addi x11 x11 1
   addi x12 x12 1
   addi x13 x13 1
   addi x14 x14 1
   j p4c_loop

p4c_done:
   li x8 0
   c.mv sp tp
   c.ret
***

// ================================================================= decode
//
// Everything outside the symbol loop stays in Brevis: it is row work with
// no loop-carried dependency worth hand-scheduling, and the compiler
// already vectorises none of it either way.

#vulgā prōcēdūra bng_decode([]n8 src; -> []n8; n64; n64; n64;) {
   #situla trānsitōria: temp_sit;
   []n8 none;
   sī p4_magic_ok(src,) == 0 { #refer (none, 0, 0, 0,); }
   n64 w = p4_u32(src, 8,);
   n64 h = p4_u32(src, 12,);
   n64 count_field = p4_u32(src, 16,);
   n64 raw = count_field & P4_RAW_FLAG;
   n64 stream_byte_count = count_field & P4_COUNT_MASK;
   sī w == 0 || h == 0 || w > 65535 || h > 65535 { #refer (none, 0, 0, 0,); }
   n64 n = w * h;
   sī stream_byte_count > src.m - P4_HEADER { #refer (none, 0, 0, 0,); }
   sī raw != 0 {
      // Bit 31: the body is the XRGB8888 pixels themselves, packed.
      sī stream_byte_count != 4 * n { #refer (none, 0, 0, 0,); }
      []n8 rawpx = situlā_adlocā<n8,>(circum.situla_data%, 4 * n,);
      dum n64 i = 0; i < 4 * n { rawpx[i]% = src[P4_HEADER + i]%; i += 1; }
      #refer (rawpx, w, h, 1,);
   }
   sī stream_byte_count * 8 < h { #refer (none, 0, 0, 0,); }

   []n8 dst = situlā_adlocā<n8,>(circum.situla_data%, 4 * n,);
   []n8 pix = situlā_adlocā<n8,>(temp_sit, 8 * w,);
   n64 rstride = ((w + 7) / 8) * 8;        // 8-aligned rows for the wide scan
   []s8 rr  = situlā_adlocā<s8,>(temp_sit, 4 * rstride + 8,);
   dum n64 i = 0; i < 8 * w { pix[i]% = 0; i += 1; }

   n64 rstride = ((w + 7) / 8) * 8;
   n64 at = P4_HEADER;
   n64 end = P4_HEADER + stream_byte_count;
   n64 acc = 0;
   n64 nb = 0;
   n64 ok = 1;

   dum n64 y = 0; y < h {
      n64 cb = (y & 1) * (4 * w);
      n64 pb = (1 - (y & 1)) * (4 * w);

      dum n64 p = 0; p < 4 {
         n64 co = p * rstride;
         n64 c0 = cb + p * w;
         n64 p0 = pb + p * w;

         n64 rok;
         (rok, at, acc, nb,) = p4a_dec_rec_row(src.i, at, end, acc, nb,
                                               pix.i + (@n8)c0,
                                               pix.i + (@n8)p0, w,
                                               (@n64)p4f_root,
                                               0, 0, 0, 0, 0, 0, 0, 0, 0,);
         sī rok == 0 { ok = 0; #dēsine; }
         p += 1;
      }
      sī ok == 0 { #dēsine; }

      n64 rowoff = (y * w) * 4;
      p4a_ycocg_row(pix.i + (@n8)cb, pix.i + (@n8)(cb + w),
                    pix.i + (@n8)(cb + 2 * w), pix.i + (@n8)(cb + 3 * w),
                    dst.i + (@n8)rowoff, w, 0, 0, 0, 0, 0, 0, 0, 0, 0,);
      y += 1;
   }

   sī at > end + 16 { ok = 0; }
   sī ok == 0 { #refer (none, 0, 0, 0,); }
   #refer (dst, w, h, 1,);
}

// One encode pass into dst, returning the write position it reached. The
// asm writer counts the bytes it could not store, so a return past dst.m
// says exactly how large the buffer has to be.
prōcēdūra p4a_encode_into([]n8 dst; n64 cap; []n8 px; n64 w; n64 h;
                          n64 pitch; []n8 pix; []s8 rr; -> n64;) {
   n64 rstride = ((w + 7) / 8) * 8;
   n64 at = P4_HEADER;
   n64 acc = 0;
   n64 nb = 0;

   dum n64 y = 0; y < h {
      n64 rowoff = y * pitch;
      n64 cb = (y & 1) * (4 * w);
      n64 pb = (1 - (y & 1)) * (4 * w);

      // Row 0 needs no case of its own: prv is the zeroed half of pix on
      // the first pass and MED against zero is the left predictor.
      p4a_ycocg_resid_row(px.i + (@n8)rowoff, pix.i + (@n8)cb,
                          pix.i + (@n8)pb, rr.i, rr.i + (@s8)rstride,
                          rr.i + (@s8)(2 * rstride),
                          rr.i + (@s8)(3 * rstride), w,
                          0, 0, 0, 0, 0, 0, 0, 0,
                          0, 0, 0, 0, 0, 0, 0, 0,);

      dum n64 p = 0; p < 4 {
         n64 co = p * rstride;
         (at, acc, nb,) = p4a_encode_row(dst.i, at, acc, nb, rr.i + (@s8)co, w,
                                         (@n64)p4f_res, (@n64)p4f_enc, cap,
                                         0, 0, 0, 0, 0, 0, 0, 0,);
         p += 1;
      }
      y += 1;
   }

   sī nb != 0 {
      sī at < cap { dst[at]% = (n8)((acc << (8 - nb)) & 0xFF); }
      at += 1;
   }
   #refer at;
}

// pitch is the source's row stride, so a crop of a framebuffer can be
// encoded where it lies.
#vulgā prōcēdūra bng_encode([]n8 px; n64 w; n64 h; n64 pitch;
                                -> []n8; n64;) {
   #situla trānsitōria: temp_sit;
   []n8 none;
   sī w == 0 || h == 0 { #refer (none, 0,); }
   n64 n = w * h;
   sī pitch < w * 4 { #refer (none, 0,); }
   sī px.m < (h - 1) * pitch + w * 4 { #refer (none, 0,); }

   // Capped at what raw would cost: a body that reaches that has lost.
   n64 cap = P4_HEADER + 4 * n;
   []n8 dst = situlā_adlocā<n8,>(circum.situla_data%, cap,);
   []n8 pix = situlā_adlocā<n8,>(temp_sit, 8 * w,);
   n64 rstride = ((w + 7) / 8) * 8;        // 8-aligned rows for the wide scan
   []s8 rr  = situlā_adlocā<s8,>(temp_sit, 4 * rstride + 8,);
   dum n64 i = 0; i < 8 * w { pix[i]% = 0; i += 1; }

   n64 at = p4a_encode_into(dst, cap, px, w, h, pitch, pix, rr,);
   p4_put_magic(dst,);
   p4_put_u32(dst, 8, w,);
   p4_put_u32(dst, 12, h,);
   sī at - P4_HEADER >= 4 * n {
      // The pixels themselves: only noise reaches this, and it bounds
      // every file at 20 + 4wh.
      dum n64 y = 0; y < h {
         dum n64 i = 0; i < w * 4 {
            dst[P4_HEADER + y * w * 4 + i]% = px[y * pitch + i]%;
            i += 1;
         }
         y += 1;
      }
      p4_put_u32(dst, 16, (4 * n) | P4_RAW_FLAG,);
      #refer (dst[0:P4_HEADER + 4 * n], 1,);
   }
   p4_put_u32(dst, 16, at - P4_HEADER,);   // stream_byte_count
   #refer (dst[0:at], 1,);
}

#fīnis