/* * Copyright(c) 2019-2023 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 . */ #include #include int err; #include "hex_test.h" static uint32_t preg_alias(uint8_t v0, uint8_t v1, uint8_t v2, uint8_t v3) { uint32_t ret; asm volatile("p0 = %1\n\t" "p1 = %2\n\t" "p2 = %3\n\t" "p3 = %4\n\t" "%0 = C4\n" : "=r"(ret) : "r"(v0), "r"(v1), "r"(v2), "r"(v3) : "p0", "p1", "p2", "p3"); return ret; } static uint32_t preg_alias_pair(uint8_t v0, uint8_t v1, uint8_t v2, uint8_t v3) { uint64_t c54; asm volatile("p0 = %1\n\t" "p1 = %2\n\t" "p2 = %3\n\t" "p3 = %4\n\t" "%0 = C5:4\n" : "=r"(c54) : "r"(v0), "r"(v1), "r"(v2), "r"(v3) : "p0", "p1", "p2", "p3"); return (uint32_t)c54; } typedef union { uint32_t creg; struct { uint8_t p0; uint8_t p1; uint8_t p2; uint8_t p3; } pregs; } PRegs; static inline void creg_alias(uint32_t cval, PRegs *pregs) { asm("c4 = %4\n\t" "%0 = p0\n\t" "%1 = p1\n\t" "%2 = p2\n\t" "%3 = p3\n\t" : "=r"(pregs->pregs.p0), "=r"(pregs->pregs.p1), "=r"(pregs->pregs.p2), "=r"(pregs->pregs.p3) : "r"(cval) : "c4", "p0", "p1", "p2", "p3"); } static inline void creg_alias_pair(uint32_t cval, PRegs *pregs) { uint64_t cval_pair = (0xdeadbeefULL << 32) | cval; uint32_t c5; asm ("c5:4 = %5\n\t" "%0 = p0\n\t" "%1 = p1\n\t" "%2 = p2\n\t" "%3 = p3\n\t" "%4 = c5\n\t" : "=r"(pregs->pregs.p0), "=r"(pregs->pregs.p1), "=r"(pregs->pregs.p2), "=r"(pregs->pregs.p3), "=r"(c5) : "r"(cval_pair) : "c4", "c5", "p0", "p1", "p2", "p3"); check32(c5, 0xdeadbeef); } static void test_packet(void) { /* * Test that setting c4 inside a packet doesn't impact the predicates * that are read during the packet. */ uint32_t result; uint32_t old_val = 0x0000001c; /* Test a predicated register transfer */ result = old_val; asm ( "c4 = %1\n\t" "{\n\t" " c4 = %2\n\t" " if (!p2) %0 = %3\n\t" "}\n\t" : "+r"(result) : "r"(0xffffffff), "r"(0xff00ffff), "r"(0x837ed653) : "c4", "p0", "p1", "p2", "p3"); check32(result, old_val); /* Test a predicated store */ result = 0xffffffff; asm ("c4 = %0\n\t" "{\n\t" " c4 = %1\n\t" " if (!p2) memw(%2) = #0\n\t" "}\n\t" : : "r"(0), "r"(0xffffffff), "r"(&result) : "c4", "p0", "p1", "p2", "p3", "memory"); check32(result, 0x0); } int main() { uint32_t c4; PRegs pregs; c4 = preg_alias(0xff, 0x00, 0xff, 0x00); check32(c4, 0x00ff00ff); c4 = preg_alias(0xff, 0x00, 0x00, 0x00); check32(c4, 0x000000ff); c4 = preg_alias(0x00, 0xff, 0x00, 0x00); check32(c4, 0x0000ff00); c4 = preg_alias(0x00, 0x00, 0xff, 0x00); check32(c4, 0x00ff0000); c4 = preg_alias(0x00, 0x00, 0x00, 0xff); check32(c4, 0xff000000); c4 = preg_alias(0xff, 0xff, 0xff, 0xff); check32(c4, 0xffffffff); c4 = preg_alias_pair(0xff, 0x00, 0xff, 0x00); check32(c4, 0x00ff00ff); c4 = preg_alias_pair(0xff, 0x00, 0x00, 0x00); check32(c4, 0x000000ff); c4 = preg_alias_pair(0x00, 0xff, 0x00, 0x00); check32(c4, 0x0000ff00); c4 = preg_alias_pair(0x00, 0x00, 0xff, 0x00); check32(c4, 0x00ff0000); c4 = preg_alias_pair(0x00, 0x00, 0x00, 0xff); check32(c4, 0xff000000); c4 = preg_alias_pair(0xff, 0xff, 0xff, 0xff); check32(c4, 0xffffffff); creg_alias(0x00ff00ff, &pregs); check32(pregs.creg, 0x00ff00ff); creg_alias(0x00ffff00, &pregs); check32(pregs.creg, 0x00ffff00); creg_alias(0x00000000, &pregs); check32(pregs.creg, 0x00000000); creg_alias(0xff000000, &pregs); check32(pregs.creg, 0xff000000); creg_alias(0x00ff0000, &pregs); check32(pregs.creg, 0x00ff0000); creg_alias(0x0000ff00, &pregs); check32(pregs.creg, 0x0000ff00); creg_alias(0x000000ff, &pregs); check32(pregs.creg, 0x000000ff); creg_alias(0xffffffff, &pregs); check32(pregs.creg, 0xffffffff); creg_alias_pair(0x00ff00ff, &pregs); check32(pregs.creg, 0x00ff00ff); creg_alias_pair(0x00ffff00, &pregs); check32(pregs.creg, 0x00ffff00); creg_alias_pair(0x00000000, &pregs); check32(pregs.creg, 0x00000000); creg_alias_pair(0xff000000, &pregs); check32(pregs.creg, 0xff000000); creg_alias_pair(0x00ff0000, &pregs); check32(pregs.creg, 0x00ff0000); creg_alias_pair(0x0000ff00, &pregs); check32(pregs.creg, 0x0000ff00); creg_alias_pair(0x000000ff, &pregs); check32(pregs.creg, 0x000000ff); creg_alias_pair(0xffffffff, &pregs); check32(pregs.creg, 0xffffffff); test_packet(); puts(err ? "FAIL" : "PASS"); return err; }