| /* |
| * Copyright(c) 2019-2021 Qualcomm Innovation Center, Inc. All Rights Reserved. |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the License, or |
| * (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| */ |
| |
| #include <stdio.h> |
| #include <string.h> |
| |
| int err; |
| |
| #define NBITS 8 |
| #define SIZE (1 << NBITS) |
| |
| long long dbuf[SIZE] __attribute__((aligned(1 << 16))) = {0}; |
| int wbuf[SIZE] __attribute__((aligned(1 << 16))) = {0}; |
| short hbuf[SIZE] __attribute__((aligned(1 << 16))) = {0}; |
| unsigned char bbuf[SIZE] __attribute__((aligned(1 << 16))) = {0}; |
| |
| /* |
| * We use the C preporcessor to deal with the combinations of types |
| */ |
| |
| #define BREV_LOAD(SZ, RES, ADDR, INC) \ |
| __asm__( \ |
| "m0 = %2\n\t" \ |
| "%0 = mem" #SZ "(%1++m0:brev)\n\t" \ |
| : "=r"(RES), "+r"(ADDR) \ |
| : "r"(INC) \ |
| : "m0") |
| |
| #define BREV_LOAD_b(RES, ADDR, INC) \ |
| BREV_LOAD(b, RES, ADDR, INC) |
| #define BREV_LOAD_ub(RES, ADDR, INC) \ |
| BREV_LOAD(ub, RES, ADDR, INC) |
| #define BREV_LOAD_h(RES, ADDR, INC) \ |
| BREV_LOAD(h, RES, ADDR, INC) |
| #define BREV_LOAD_uh(RES, ADDR, INC) \ |
| BREV_LOAD(uh, RES, ADDR, INC) |
| #define BREV_LOAD_w(RES, ADDR, INC) \ |
| BREV_LOAD(w, RES, ADDR, INC) |
| #define BREV_LOAD_d(RES, ADDR, INC) \ |
| BREV_LOAD(d, RES, ADDR, INC) |
| |
| #define BREV_STORE(SZ, PART, ADDR, VAL, INC) \ |
| __asm__( \ |
| "m0 = %2\n\t" \ |
| "mem" #SZ "(%0++m0:brev) = %1" PART "\n\t" \ |
| : "+r"(ADDR) \ |
| : "r"(VAL), "r"(INC) \ |
| : "m0", "memory") |
| |
| #define BREV_STORE_b(ADDR, VAL, INC) \ |
| BREV_STORE(b, "", ADDR, VAL, INC) |
| #define BREV_STORE_h(ADDR, VAL, INC) \ |
| BREV_STORE(h, "", ADDR, VAL, INC) |
| #define BREV_STORE_f(ADDR, VAL, INC) \ |
| BREV_STORE(h, ".H", ADDR, VAL, INC) |
| #define BREV_STORE_w(ADDR, VAL, INC) \ |
| BREV_STORE(w, "", ADDR, VAL, INC) |
| #define BREV_STORE_d(ADDR, VAL, INC) \ |
| BREV_STORE(d, "", ADDR, VAL, INC) |
| |
| #define BREV_STORE_NEW(SZ, ADDR, VAL, INC) \ |
| __asm__( \ |
| "m0 = %2\n\t" \ |
| "{\n\t" \ |
| " r5 = %1\n\t" \ |
| " mem" #SZ "(%0++m0:brev) = r5.new\n\t" \ |
| "}\n\t" \ |
| : "+r"(ADDR) \ |
| : "r"(VAL), "r"(INC) \ |
| : "r5", "m0", "memory") |
| |
| #define BREV_STORE_bnew(ADDR, VAL, INC) \ |
| BREV_STORE_NEW(b, ADDR, VAL, INC) |
| #define BREV_STORE_hnew(ADDR, VAL, INC) \ |
| BREV_STORE_NEW(h, ADDR, VAL, INC) |
| #define BREV_STORE_wnew(ADDR, VAL, INC) \ |
| BREV_STORE_NEW(w, ADDR, VAL, INC) |
| |
| int bitreverse(int x) |
| { |
| int result = 0; |
| int i; |
| for (i = 0; i < NBITS; i++) { |
| result <<= 1; |
| result |= x & 1; |
| x >>= 1; |
| } |
| return result; |
| } |
| |
| int sext8(int x) |
| { |
| return (x << 24) >> 24; |
| } |
| |
| void check(int i, long long result, long long expect) |
| { |
| if (result != expect) { |
| printf("ERROR(%d): 0x%04llx != 0x%04llx\n", i, result, expect); |
| err++; |
| } |
| } |
| |
| #define TEST_BREV_LOAD(SZ, TYPE, BUF, SHIFT, EXP) \ |
| do { \ |
| p = BUF; \ |
| for (i = 0; i < SIZE; i++) { \ |
| TYPE result; \ |
| BREV_LOAD_##SZ(result, p, 1 << (SHIFT - NBITS)); \ |
| check(i, result, EXP); \ |
| } \ |
| } while (0) |
| |
| #define TEST_BREV_STORE(SZ, TYPE, BUF, VAL, SHIFT) \ |
| do { \ |
| p = BUF; \ |
| memset(BUF, 0xff, sizeof(BUF)); \ |
| for (i = 0; i < SIZE; i++) { \ |
| BREV_STORE_##SZ(p, (TYPE)(VAL), 1 << (SHIFT - NBITS)); \ |
| } \ |
| for (i = 0; i < SIZE; i++) { \ |
| check(i, BUF[i], bitreverse(i)); \ |
| } \ |
| } while (0) |
| |
| #define TEST_BREV_STORE_NEW(SZ, BUF, SHIFT) \ |
| do { \ |
| p = BUF; \ |
| memset(BUF, 0xff, sizeof(BUF)); \ |
| for (i = 0; i < SIZE; i++) { \ |
| BREV_STORE_##SZ(p, i, 1 << (SHIFT - NBITS)); \ |
| } \ |
| for (i = 0; i < SIZE; i++) { \ |
| check(i, BUF[i], bitreverse(i)); \ |
| } \ |
| } while (0) |
| |
| /* |
| * We'll set high_half[i] = i << 16 for use in the .H form of store |
| * which stores from the high half of the word. |
| */ |
| int high_half[SIZE]; |
| |
| int main() |
| { |
| void *p; |
| int i; |
| |
| for (i = 0; i < SIZE; i++) { |
| bbuf[i] = bitreverse(i); |
| hbuf[i] = bitreverse(i); |
| wbuf[i] = bitreverse(i); |
| dbuf[i] = bitreverse(i); |
| high_half[i] = i << 16; |
| } |
| |
| TEST_BREV_LOAD(b, int, bbuf, 16, sext8(i)); |
| TEST_BREV_LOAD(ub, int, bbuf, 16, i); |
| TEST_BREV_LOAD(h, int, hbuf, 15, i); |
| TEST_BREV_LOAD(uh, int, hbuf, 15, i); |
| TEST_BREV_LOAD(w, int, wbuf, 14, i); |
| TEST_BREV_LOAD(d, long long, dbuf, 13, i); |
| |
| TEST_BREV_STORE(b, int, bbuf, i, 16); |
| TEST_BREV_STORE(h, int, hbuf, i, 15); |
| TEST_BREV_STORE(f, int, hbuf, high_half[i], 15); |
| TEST_BREV_STORE(w, int, wbuf, i, 14); |
| TEST_BREV_STORE(d, long long, dbuf, i, 13); |
| |
| TEST_BREV_STORE_NEW(bnew, bbuf, 16); |
| TEST_BREV_STORE_NEW(hnew, hbuf, 15); |
| TEST_BREV_STORE_NEW(wnew, wbuf, 14); |
| |
| puts(err ? "FAIL" : "PASS"); |
| return err ? 1 : 0; |
| } |