// 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ā(temp_sit, 8 * w,); []s8 rr = situlā_adlocā(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ā(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ā(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ā(circum.situla_data%, 4 * n,); // Both row parities in one buffer; see the note in bng_encode. []n8 pix = situlā_adlocā(temp_sit, 8 * w,); []s8 rr = situlā_adlocā(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ā(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ā(circum.situla_data%, 4 * n,); []n8 pix = situlā_adlocā(temp_sit, 8 * w,); n64 rstride = ((w + 7) / 8) * 8; // 8-aligned rows for the wide scan []s8 rr = situlā_adlocā(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ā(circum.situla_data%, cap,); []n8 pix = situlā_adlocā(temp_sit, 8 * w,); n64 rstride = ((w + 7) / 8) * 8; // 8-aligned rows for the wide scan []s8 rr = situlā_adlocā(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ā(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ā(circum.situla_data%, 4 * n,); []n8 pix = situlā_adlocā(temp_sit, 8 * w,); n64 rstride = ((w + 7) / 8) * 8; // 8-aligned rows for the wide scan []s8 rr = situlā_adlocā(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ā(circum.situla_data%, cap,); []n8 pix = situlā_adlocā(temp_sit, 8 * w,); n64 rstride = ((w + 7) / 8) * 8; // 8-aligned rows for the wide scan []s8 rr = situlā_adlocā(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