qemu/tests/tcg/hexagon/load_unpack.c
<<
>>
Prefs
   1/*
   2 *  Copyright(c) 2019-2021 Qualcomm Innovation Center, Inc. All Rights Reserved.
   3 *
   4 *  This program is free software; you can redistribute it and/or modify
   5 *  it under the terms of the GNU General Public License as published by
   6 *  the Free Software Foundation; either version 2 of the License, or
   7 *  (at your option) any later version.
   8 *
   9 *  This program is distributed in the hope that it will be useful,
  10 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  11 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12 *  GNU General Public License for more details.
  13 *
  14 *  You should have received a copy of the GNU General Public License
  15 *  along with this program; if not, see <http://www.gnu.org/licenses/>.
  16 */
  17
  18/*
  19 * Test load unpack instructions
  20 *
  21 * Example
  22 *     r0 = memubh(r1+#0)
  23 * loads a half word from memory and zero-extends the 2 bytes to form a word
  24 *
  25 * For each addressing mode, there are 4 tests
  26 *     bzw2          unsigned     2 elements
  27 *     bsw2          signed       2 elements
  28 *     bzw4          unsigned     4 elements
  29 *     bsw4          signed       4 elements
  30 * There are 8 addressing modes, for a total of 32 instructions to test
  31 */
  32
  33#include <stdio.h>
  34#include <string.h>
  35
  36int err;
  37
  38char buf[16] __attribute__((aligned(1 << 16)));
  39
  40void init_buf(void)
  41{
  42    int i;
  43    for (i = 0; i < 16; i++) {
  44        int sign = i % 2 == 0 ? 0x80 : 0;
  45        buf[i] = sign | (i + 1);
  46    }
  47}
  48
  49void __check(int line, long long result, long long expect)
  50{
  51    if (result != expect) {
  52        printf("ERROR at line %d: 0x%08llx != 0x%08llx\n",
  53               line, result, expect);
  54        err++;
  55    }
  56}
  57
  58#define check(RES, EXP) __check(__LINE__, RES, EXP)
  59
  60void __checkp(int line, void *p, void *expect)
  61{
  62    if (p != expect) {
  63        printf("ERROR at line %d: 0x%p != 0x%p\n", line, p, expect);
  64        err++;
  65    }
  66}
  67
  68#define checkp(RES, EXP) __checkp(__LINE__, RES, EXP)
  69
  70/*
  71 ****************************************************************************
  72 * _io addressing mode (addr + offset)
  73 */
  74#define BxW_LOAD_io(SZ, RES, ADDR, OFF) \
  75    __asm__( \
  76        "%0 = mem" #SZ "(%1+#" #OFF ")\n\t" \
  77        : "=r"(RES) \
  78        : "r"(ADDR))
  79#define BxW_LOAD_io_Z(RES, ADDR, OFF) \
  80    BxW_LOAD_io(ubh, RES, ADDR, OFF)
  81#define BxW_LOAD_io_S(RES, ADDR, OFF) \
  82    BxW_LOAD_io(bh, RES, ADDR, OFF)
  83
  84#define TEST_io(NAME, TYPE, SIGN, SIZE, EXT, EXP1, EXP2, EXP3, EXP4) \
  85void test_##NAME(void) \
  86{ \
  87    TYPE result; \
  88    init_buf(); \
  89    BxW_LOAD_io_##SIGN(result, buf, 0 * (SIZE)); \
  90    check(result, (EXP1) | (EXT)); \
  91    BxW_LOAD_io_##SIGN(result, buf, 1 * (SIZE)); \
  92    check(result, (EXP2) | (EXT)); \
  93    BxW_LOAD_io_##SIGN(result, buf, 2 * (SIZE)); \
  94    check(result, (EXP3) | (EXT)); \
  95    BxW_LOAD_io_##SIGN(result, buf, 3 * (SIZE)); \
  96    check(result, (EXP4) | (EXT)); \
  97}
  98
  99
 100TEST_io(loadbzw2_io, int, Z, 2, 0x00000000,
 101        0x00020081, 0x00040083, 0x00060085, 0x00080087)
 102TEST_io(loadbsw2_io, int, S, 2, 0x0000ff00,
 103        0x00020081, 0x00040083, 0x00060085, 0x00080087)
 104TEST_io(loadbzw4_io, long long, Z,  4, 0x0000000000000000LL,
 105        0x0004008300020081LL, 0x0008008700060085LL,
 106        0x000c008b000a0089LL, 0x0010008f000e008dLL)
 107TEST_io(loadbsw4_io, long long, S,  4, 0x0000ff000000ff00LL,
 108        0x0004008300020081LL, 0x0008008700060085LL,
 109        0x000c008b000a0089LL, 0x0010008f000e008dLL)
 110
 111/*
 112 ****************************************************************************
 113 * _ur addressing mode (index << offset + base)
 114 */
 115#define BxW_LOAD_ur(SZ, RES, SHIFT, IDX) \
 116    __asm__( \
 117        "%0 = mem" #SZ "(%1<<#" #SHIFT " + ##buf)\n\t" \
 118        : "=r"(RES) \
 119        : "r"(IDX))
 120#define BxW_LOAD_ur_Z(RES, SHIFT, IDX) \
 121    BxW_LOAD_ur(ubh, RES, SHIFT, IDX)
 122#define BxW_LOAD_ur_S(RES, SHIFT, IDX) \
 123    BxW_LOAD_ur(bh, RES, SHIFT, IDX)
 124
 125#define TEST_ur(NAME, TYPE, SIGN, SHIFT, EXT, RES1, RES2, RES3, RES4) \
 126void test_##NAME(void) \
 127{ \
 128    TYPE result; \
 129    init_buf(); \
 130    BxW_LOAD_ur_##SIGN(result, (SHIFT), 0); \
 131    check(result, (RES1) | (EXT)); \
 132    BxW_LOAD_ur_##SIGN(result, (SHIFT), 1); \
 133    check(result, (RES2) | (EXT)); \
 134    BxW_LOAD_ur_##SIGN(result, (SHIFT), 2); \
 135    check(result, (RES3) | (EXT)); \
 136    BxW_LOAD_ur_##SIGN(result, (SHIFT), 3); \
 137    check(result, (RES4) | (EXT)); \
 138} \
 139
 140TEST_ur(loadbzw2_ur, int, Z, 1, 0x00000000,
 141        0x00020081, 0x00040083, 0x00060085, 0x00080087)
 142TEST_ur(loadbsw2_ur, int, S, 1, 0x0000ff00,
 143        0x00020081, 0x00040083, 0x00060085, 0x00080087)
 144TEST_ur(loadbzw4_ur, long long, Z, 2, 0x0000000000000000LL,
 145        0x0004008300020081LL, 0x0008008700060085LL,
 146        0x000c008b000a0089LL, 0x0010008f000e008dLL)
 147TEST_ur(loadbsw4_ur, long long, S, 2, 0x0000ff000000ff00LL,
 148        0x0004008300020081LL, 0x0008008700060085LL,
 149        0x000c008b000a0089LL, 0x0010008f000e008dLL)
 150
 151/*
 152 ****************************************************************************
 153 * _ap addressing mode (addr = base)
 154 */
 155#define BxW_LOAD_ap(SZ, RES, PTR, ADDR) \
 156    __asm__( \
 157        "%0 = mem" #SZ "(%1 = ##" #ADDR ")\n\t" \
 158        : "=r"(RES), "=r"(PTR))
 159#define BxW_LOAD_ap_Z(RES, PTR, ADDR) \
 160    BxW_LOAD_ap(ubh, RES, PTR, ADDR)
 161#define BxW_LOAD_ap_S(RES, PTR, ADDR) \
 162    BxW_LOAD_ap(bh, RES, PTR, ADDR)
 163
 164#define TEST_ap(NAME, TYPE, SIGN, SIZE, EXT, RES1, RES2, RES3, RES4) \
 165void test_##NAME(void) \
 166{ \
 167    TYPE result; \
 168    void *ptr; \
 169    init_buf(); \
 170    BxW_LOAD_ap_##SIGN(result, ptr, (buf + 0 * (SIZE))); \
 171    check(result, (RES1) | (EXT)); \
 172    checkp(ptr, &buf[0 * (SIZE)]); \
 173    BxW_LOAD_ap_##SIGN(result, ptr, (buf + 1 * (SIZE))); \
 174    check(result, (RES2) | (EXT)); \
 175    checkp(ptr, &buf[1 * (SIZE)]); \
 176    BxW_LOAD_ap_##SIGN(result, ptr, (buf + 2 * (SIZE))); \
 177    check(result, (RES3) | (EXT)); \
 178    checkp(ptr, &buf[2 * (SIZE)]); \
 179    BxW_LOAD_ap_##SIGN(result, ptr, (buf + 3 * (SIZE))); \
 180    check(result, (RES4) | (EXT)); \
 181    checkp(ptr, &buf[3 * (SIZE)]); \
 182}
 183
 184TEST_ap(loadbzw2_ap, int, Z, 2, 0x00000000,
 185        0x00020081, 0x00040083, 0x00060085, 0x00080087)
 186TEST_ap(loadbsw2_ap, int, S, 2, 0x0000ff00,
 187        0x00020081, 0x00040083, 0x00060085, 0x00080087)
 188TEST_ap(loadbzw4_ap, long long, Z, 4, 0x0000000000000000LL,
 189        0x0004008300020081LL, 0x0008008700060085LL,
 190        0x000c008b000a0089LL, 0x0010008f000e008dLL)
 191TEST_ap(loadbsw4_ap, long long, S, 4, 0x0000ff000000ff00LL,
 192        0x0004008300020081LL, 0x0008008700060085LL,
 193        0x000c008b000a0089LL, 0x0010008f000e008dLL)
 194
 195/*
 196 ****************************************************************************
 197 * _rp addressing mode (addr ++ modifer-reg)
 198 */
 199#define BxW_LOAD_pr(SZ, RES, PTR, INC) \
 200    __asm__( \
 201        "m0 = %2\n\t" \
 202        "%0 = mem" #SZ "(%1++m0)\n\t" \
 203        : "=r"(RES), "+r"(PTR) \
 204        : "r"(INC) \
 205        : "m0")
 206#define BxW_LOAD_pr_Z(RES, PTR, INC) \
 207    BxW_LOAD_pr(ubh, RES, PTR, INC)
 208#define BxW_LOAD_pr_S(RES, PTR, INC) \
 209    BxW_LOAD_pr(bh, RES, PTR, INC)
 210
 211#define TEST_pr(NAME, TYPE, SIGN, SIZE, EXT, RES1, RES2, RES3, RES4) \
 212void test_##NAME(void) \
 213{ \
 214    TYPE result; \
 215    void *ptr = buf; \
 216    init_buf(); \
 217    BxW_LOAD_pr_##SIGN(result, ptr, (SIZE)); \
 218    check(result, (RES1) | (EXT)); \
 219    checkp(ptr, &buf[1 * (SIZE)]); \
 220    BxW_LOAD_pr_##SIGN(result, ptr, (SIZE)); \
 221    check(result, (RES2) | (EXT)); \
 222    checkp(ptr, &buf[2 * (SIZE)]); \
 223    BxW_LOAD_pr_##SIGN(result, ptr, (SIZE)); \
 224    check(result, (RES3) | (EXT)); \
 225    checkp(ptr, &buf[3 * (SIZE)]); \
 226    BxW_LOAD_pr_##SIGN(result, ptr, (SIZE)); \
 227    check(result, (RES4) | (EXT)); \
 228    checkp(ptr, &buf[4 * (SIZE)]); \
 229}
 230
 231TEST_pr(loadbzw2_pr, int, Z, 2, 0x00000000,
 232    0x00020081, 0x0040083, 0x00060085, 0x00080087)
 233TEST_pr(loadbsw2_pr, int, S, 2, 0x0000ff00,
 234    0x00020081, 0x0040083, 0x00060085, 0x00080087)
 235TEST_pr(loadbzw4_pr, long long, Z, 4, 0x0000000000000000LL,
 236    0x0004008300020081LL, 0x0008008700060085LL,
 237    0x000c008b000a0089LL, 0x0010008f000e008dLL)
 238TEST_pr(loadbsw4_pr, long long, S, 4, 0x0000ff000000ff00LL,
 239    0x0004008300020081LL, 0x0008008700060085LL,
 240    0x000c008b000a0089LL, 0x0010008f000e008dLL)
 241
 242/*
 243 ****************************************************************************
 244 * _pbr addressing mode (addr ++ modifer-reg:brev)
 245 */
 246#define BxW_LOAD_pbr(SZ, RES, PTR) \
 247    __asm__( \
 248        "r4 = #(1 << (16 - 3))\n\t" \
 249        "m0 = r4\n\t" \
 250        "%0 = mem" #SZ "(%1++m0:brev)\n\t" \
 251        : "=r"(RES), "+r"(PTR) \
 252        : \
 253        : "r4", "m0")
 254#define BxW_LOAD_pbr_Z(RES, PTR) \
 255    BxW_LOAD_pbr(ubh, RES, PTR)
 256#define BxW_LOAD_pbr_S(RES, PTR) \
 257    BxW_LOAD_pbr(bh, RES, PTR)
 258
 259#define TEST_pbr(NAME, TYPE, SIGN, EXT, RES1, RES2, RES3, RES4) \
 260void test_##NAME(void) \
 261{ \
 262    TYPE result; \
 263    void *ptr = buf; \
 264    init_buf(); \
 265    BxW_LOAD_pbr_##SIGN(result, ptr); \
 266    check(result, (RES1) | (EXT)); \
 267    BxW_LOAD_pbr_##SIGN(result, ptr); \
 268    check(result, (RES2) | (EXT)); \
 269    BxW_LOAD_pbr_##SIGN(result, ptr); \
 270    check(result, (RES3) | (EXT)); \
 271    BxW_LOAD_pbr_##SIGN(result, ptr); \
 272    check(result, (RES4) | (EXT)); \
 273}
 274
 275TEST_pbr(loadbzw2_pbr, int, Z, 0x00000000,
 276    0x00020081, 0x00060085, 0x00040083, 0x00080087)
 277TEST_pbr(loadbsw2_pbr, int, S, 0x0000ff00,
 278    0x00020081, 0x00060085, 0x00040083, 0x00080087)
 279TEST_pbr(loadbzw4_pbr, long long, Z, 0x0000000000000000LL,
 280    0x0004008300020081LL, 0x0008008700060085LL,
 281    0x0006008500040083LL, 0x000a008900080087LL)
 282TEST_pbr(loadbsw4_pbr, long long, S, 0x0000ff000000ff00LL,
 283    0x0004008300020081LL, 0x0008008700060085LL,
 284    0x0006008500040083LL, 0x000a008900080087LL)
 285
 286/*
 287 ****************************************************************************
 288 * _pi addressing mode (addr ++ inc)
 289 */
 290#define BxW_LOAD_pi(SZ, RES, PTR, INC) \
 291    __asm__( \
 292        "%0 = mem" #SZ "(%1++#" #INC ")\n\t" \
 293        : "=r"(RES), "+r"(PTR))
 294#define BxW_LOAD_pi_Z(RES, PTR, INC) \
 295    BxW_LOAD_pi(ubh, RES, PTR, INC)
 296#define BxW_LOAD_pi_S(RES, PTR, INC) \
 297    BxW_LOAD_pi(bh, RES, PTR, INC)
 298
 299#define TEST_pi(NAME, TYPE, SIGN, INC, EXT, RES1, RES2, RES3, RES4) \
 300void test_##NAME(void) \
 301{ \
 302    TYPE result; \
 303    void *ptr = buf; \
 304    init_buf(); \
 305    BxW_LOAD_pi_##SIGN(result, ptr, (INC)); \
 306    check(result, (RES1) | (EXT)); \
 307    checkp(ptr, &buf[1 * (INC)]); \
 308    BxW_LOAD_pi_##SIGN(result, ptr, (INC)); \
 309    check(result, (RES2) | (EXT)); \
 310    checkp(ptr, &buf[2 * (INC)]); \
 311    BxW_LOAD_pi_##SIGN(result, ptr, (INC)); \
 312    check(result, (RES3) | (EXT)); \
 313    checkp(ptr, &buf[3 * (INC)]); \
 314    BxW_LOAD_pi_##SIGN(result, ptr, (INC)); \
 315    check(result, (RES4) | (EXT)); \
 316    checkp(ptr, &buf[4 * (INC)]); \
 317}
 318
 319TEST_pi(loadbzw2_pi, int, Z, 2, 0x00000000,
 320    0x00020081, 0x00040083, 0x00060085, 0x00080087)
 321TEST_pi(loadbsw2_pi, int, S, 2, 0x0000ff00,
 322    0x00020081, 0x00040083, 0x00060085, 0x00080087)
 323TEST_pi(loadbzw4_pi, long long, Z, 4, 0x0000000000000000LL,
 324    0x0004008300020081LL, 0x0008008700060085LL,
 325    0x000c008b000a0089LL, 0x0010008f000e008dLL)
 326TEST_pi(loadbsw4_pi, long long, S, 4, 0x0000ff000000ff00LL,
 327    0x0004008300020081LL, 0x0008008700060085LL,
 328    0x000c008b000a0089LL, 0x0010008f000e008dLL)
 329
 330/*
 331 ****************************************************************************
 332 * _pci addressing mode (addr ++ inc:circ)
 333 */
 334#define BxW_LOAD_pci(SZ, RES, PTR, START, LEN, INC) \
 335    __asm__( \
 336        "r4 = %3\n\t" \
 337        "m0 = r4\n\t" \
 338        "cs0 = %2\n\t" \
 339        "%0 = mem" #SZ "(%1++#" #INC ":circ(m0))\n\t" \
 340        : "=r"(RES), "+r"(PTR) \
 341        : "r"(START), "r"(LEN) \
 342        : "r4", "m0", "cs0")
 343#define BxW_LOAD_pci_Z(RES, PTR, START, LEN, INC) \
 344    BxW_LOAD_pci(ubh, RES, PTR, START, LEN, INC)
 345#define BxW_LOAD_pci_S(RES, PTR, START, LEN, INC) \
 346    BxW_LOAD_pci(bh, RES, PTR, START, LEN, INC)
 347
 348#define TEST_pci(NAME, TYPE, SIGN, LEN, INC, EXT, RES1, RES2, RES3, RES4) \
 349void test_##NAME(void) \
 350{ \
 351    TYPE result; \
 352    void *ptr = buf; \
 353    init_buf(); \
 354    BxW_LOAD_pci_##SIGN(result, ptr, buf, (LEN), (INC)); \
 355    check(result, (RES1) | (EXT)); \
 356    checkp(ptr, &buf[(1 * (INC)) % (LEN)]); \
 357    BxW_LOAD_pci_##SIGN(result, ptr, buf, (LEN), (INC)); \
 358    check(result, (RES2) | (EXT)); \
 359    checkp(ptr, &buf[(2 * (INC)) % (LEN)]); \
 360    BxW_LOAD_pci_##SIGN(result, ptr, buf, (LEN), (INC)); \
 361    check(result, (RES3) | (EXT)); \
 362    checkp(ptr, &buf[(3 * (INC)) % (LEN)]); \
 363    BxW_LOAD_pci_##SIGN(result, ptr, buf, (LEN), (INC)); \
 364    check(result, (RES4) | (EXT)); \
 365    checkp(ptr, &buf[(4 * (INC)) % (LEN)]); \
 366}
 367
 368TEST_pci(loadbzw2_pci, int, Z, 6, 2, 0x00000000,
 369    0x00020081, 0x00040083, 0x00060085, 0x00020081)
 370TEST_pci(loadbsw2_pci, int, S, 6, 2, 0x0000ff00,
 371    0x00020081, 0x00040083, 0x00060085, 0x00020081)
 372TEST_pci(loadbzw4_pci, long long, Z, 8, 4, 0x0000000000000000LL,
 373    0x0004008300020081LL, 0x0008008700060085LL,
 374    0x0004008300020081LL, 0x0008008700060085LL)
 375TEST_pci(loadbsw4_pci, long long, S, 8, 4, 0x0000ff000000ff00LL,
 376    0x0004008300020081LL, 0x0008008700060085LL,
 377    0x0004008300020081LL, 0x0008008700060085LL)
 378
 379/*
 380 ****************************************************************************
 381 * _pcr addressing mode (addr ++ I:circ(modifier-reg))
 382 */
 383#define BxW_LOAD_pcr(SZ, RES, PTR, START, LEN, INC) \
 384    __asm__( \
 385        "r4 = %2\n\t" \
 386        "m1 = r4\n\t" \
 387        "cs1 = %3\n\t" \
 388        "%0 = mem" #SZ "(%1++I:circ(m1))\n\t" \
 389        : "=r"(RES), "+r"(PTR) \
 390        : "r"((((INC) & 0x7f) << 17) | ((LEN) & 0x1ffff)), \
 391          "r"(START) \
 392        : "r4", "m1", "cs1")
 393#define BxW_LOAD_pcr_Z(RES, PTR, START, LEN, INC) \
 394    BxW_LOAD_pcr(ubh, RES, PTR, START, LEN, INC)
 395#define BxW_LOAD_pcr_S(RES, PTR, START, LEN, INC) \
 396    BxW_LOAD_pcr(bh, RES, PTR, START, LEN, INC)
 397
 398#define TEST_pcr(NAME, TYPE, SIGN, SIZE, LEN, INC, \
 399                 EXT, RES1, RES2, RES3, RES4) \
 400void test_##NAME(void) \
 401{ \
 402    TYPE result; \
 403    void *ptr = buf; \
 404    init_buf(); \
 405    BxW_LOAD_pcr_##SIGN(result, ptr, buf, (LEN), (INC)); \
 406    check(result, (RES1) | (EXT)); \
 407    checkp(ptr, &buf[(1 * (INC) * (SIZE)) % (LEN)]); \
 408    BxW_LOAD_pcr_##SIGN(result, ptr, buf, (LEN), (INC)); \
 409    check(result, (RES2) | (EXT)); \
 410    checkp(ptr, &buf[(2 * (INC) * (SIZE)) % (LEN)]); \
 411    BxW_LOAD_pcr_##SIGN(result, ptr, buf, (LEN), (INC)); \
 412    check(result, (RES3) | (EXT)); \
 413    checkp(ptr, &buf[(3 * (INC) * (SIZE)) % (LEN)]); \
 414    BxW_LOAD_pcr_##SIGN(result, ptr, buf, (LEN), (INC)); \
 415    check(result, (RES4) | (EXT)); \
 416    checkp(ptr, &buf[(4 * (INC) * (SIZE)) % (LEN)]); \
 417}
 418
 419TEST_pcr(loadbzw2_pcr, int, Z, 2, 8, 2, 0x00000000,
 420    0x00020081, 0x00060085, 0x00020081, 0x00060085)
 421TEST_pcr(loadbsw2_pcr, int, S, 2, 8, 2, 0x0000ff00,
 422    0x00020081, 0x00060085, 0x00020081, 0x00060085)
 423TEST_pcr(loadbzw4_pcr, long long, Z, 4, 8, 1, 0x0000000000000000LL,
 424    0x0004008300020081LL, 0x0008008700060085LL,
 425    0x0004008300020081LL, 0x0008008700060085LL)
 426TEST_pcr(loadbsw4_pcr, long long, S, 4, 8, 1, 0x0000ff000000ff00LL,
 427    0x0004008300020081LL, 0x0008008700060085LL,
 428    0x0004008300020081LL, 0x0008008700060085LL)
 429
 430int main()
 431{
 432    test_loadbzw2_io();
 433    test_loadbsw2_io();
 434    test_loadbzw4_io();
 435    test_loadbsw4_io();
 436
 437    test_loadbzw2_ur();
 438    test_loadbsw2_ur();
 439    test_loadbzw4_ur();
 440    test_loadbsw4_ur();
 441
 442    test_loadbzw2_ap();
 443    test_loadbsw2_ap();
 444    test_loadbzw4_ap();
 445    test_loadbsw4_ap();
 446
 447    test_loadbzw2_pr();
 448    test_loadbsw2_pr();
 449    test_loadbzw4_pr();
 450    test_loadbsw4_pr();
 451
 452    test_loadbzw2_pbr();
 453    test_loadbsw2_pbr();
 454    test_loadbzw4_pbr();
 455    test_loadbsw4_pbr();
 456
 457    test_loadbzw2_pi();
 458    test_loadbsw2_pi();
 459    test_loadbzw4_pi();
 460    test_loadbsw4_pi();
 461
 462    test_loadbzw2_pci();
 463    test_loadbsw2_pci();
 464    test_loadbzw4_pci();
 465    test_loadbsw4_pci();
 466
 467    test_loadbzw2_pcr();
 468    test_loadbsw2_pcr();
 469    test_loadbzw4_pcr();
 470    test_loadbsw4_pcr();
 471
 472    puts(err ? "FAIL" : "PASS");
 473    return err ? 1 : 0;
 474}
 475