1b9dd6ff9STaylor Simpson /*
2*0d57cd61STaylor Simpson * Copyright(c) 2021-2023 Qualcomm Innovation Center, Inc. All Rights Reserved.
3b9dd6ff9STaylor Simpson *
4b9dd6ff9STaylor Simpson * This program is free software; you can redistribute it and/or modify
5b9dd6ff9STaylor Simpson * it under the terms of the GNU General Public License as published by
6b9dd6ff9STaylor Simpson * the Free Software Foundation; either version 2 of the License, or
7b9dd6ff9STaylor Simpson * (at your option) any later version.
8b9dd6ff9STaylor Simpson *
9b9dd6ff9STaylor Simpson * This program is distributed in the hope that it will be useful,
10b9dd6ff9STaylor Simpson * but WITHOUT ANY WARRANTY; without even the implied warranty of
11b9dd6ff9STaylor Simpson * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12b9dd6ff9STaylor Simpson * GNU General Public License for more details.
13b9dd6ff9STaylor Simpson *
14b9dd6ff9STaylor Simpson * You should have received a copy of the GNU General Public License
15b9dd6ff9STaylor Simpson * along with this program; if not, see <http://www.gnu.org/licenses/>.
16b9dd6ff9STaylor Simpson */
17b9dd6ff9STaylor Simpson
18b9dd6ff9STaylor Simpson #include <stdlib.h>
19b9dd6ff9STaylor Simpson #include <stdio.h>
20*0d57cd61STaylor Simpson #include <stdint.h>
21b9dd6ff9STaylor Simpson #include <unistd.h>
22b9dd6ff9STaylor Simpson #include <sys/types.h>
23b9dd6ff9STaylor Simpson #include <fcntl.h>
24b9dd6ff9STaylor Simpson #include <setjmp.h>
25b9dd6ff9STaylor Simpson #include <signal.h>
26b9dd6ff9STaylor Simpson
27b9dd6ff9STaylor Simpson int err;
28b9dd6ff9STaylor Simpson
29*0d57cd61STaylor Simpson #include "hex_test.h"
30b9dd6ff9STaylor Simpson
satub(int32_t src,int32_t * p,bool * ovf_result)31*0d57cd61STaylor Simpson static int32_t satub(int32_t src, int32_t *p, bool *ovf_result)
32b9dd6ff9STaylor Simpson {
33*0d57cd61STaylor Simpson int32_t result;
34*0d57cd61STaylor Simpson uint32_t usr;
35b9dd6ff9STaylor Simpson
36b9dd6ff9STaylor Simpson /*
37b9dd6ff9STaylor Simpson * This instruction can set bit 0 (OVF/overflow) in usr
38b9dd6ff9STaylor Simpson * Clear the bit first, then return that bit to the caller
39b9dd6ff9STaylor Simpson *
40b9dd6ff9STaylor Simpson * We also store the src into *p in the same packet, so we
41b9dd6ff9STaylor Simpson * can ensure the overflow doesn't get set when an exception
42b9dd6ff9STaylor Simpson * is generated.
43b9dd6ff9STaylor Simpson */
44b9dd6ff9STaylor Simpson asm volatile("r2 = usr\n\t"
45b9dd6ff9STaylor Simpson "r2 = clrbit(r2, #0)\n\t" /* clear overflow bit */
46b9dd6ff9STaylor Simpson "usr = r2\n\t"
47b9dd6ff9STaylor Simpson "{\n\t"
48b9dd6ff9STaylor Simpson " %0 = satub(%2)\n\t"
49b9dd6ff9STaylor Simpson " memw(%3) = %2\n\t"
50b9dd6ff9STaylor Simpson "}\n\t"
51b9dd6ff9STaylor Simpson "%1 = usr\n\t"
52b9dd6ff9STaylor Simpson : "=r"(result), "=r"(usr)
53b9dd6ff9STaylor Simpson : "r"(src), "r"(p)
54b9dd6ff9STaylor Simpson : "r2", "usr", "memory");
55b9dd6ff9STaylor Simpson *ovf_result = (usr & 1);
56b9dd6ff9STaylor Simpson return result;
57b9dd6ff9STaylor Simpson }
58b9dd6ff9STaylor Simpson
read_usr_overflow(void)59*0d57cd61STaylor Simpson bool read_usr_overflow(void)
60b9dd6ff9STaylor Simpson {
61*0d57cd61STaylor Simpson uint32_t usr;
62*0d57cd61STaylor Simpson asm volatile("%0 = usr\n\t" : "=r"(usr));
63*0d57cd61STaylor Simpson return usr & 1;
64b9dd6ff9STaylor Simpson }
65b9dd6ff9STaylor Simpson
get_usr_overflow(uint32_t usr)66*0d57cd61STaylor Simpson bool get_usr_overflow(uint32_t usr)
678576e7ecSTaylor Simpson {
688576e7ecSTaylor Simpson return usr & 1;
698576e7ecSTaylor Simpson }
708576e7ecSTaylor Simpson
get_usr_fp_invalid(uint32_t usr)71*0d57cd61STaylor Simpson bool get_usr_fp_invalid(uint32_t usr)
728576e7ecSTaylor Simpson {
738576e7ecSTaylor Simpson return (usr >> 1) & 1;
748576e7ecSTaylor Simpson }
758576e7ecSTaylor Simpson
get_usr_lpcfg(uint32_t usr)76*0d57cd61STaylor Simpson int32_t get_usr_lpcfg(uint32_t usr)
778576e7ecSTaylor Simpson {
788576e7ecSTaylor Simpson return (usr >> 8) & 0x3;
798576e7ecSTaylor Simpson }
80b9dd6ff9STaylor Simpson
81b9dd6ff9STaylor Simpson jmp_buf jmp_env;
82*0d57cd61STaylor Simpson bool usr_overflow;
83b9dd6ff9STaylor Simpson
sig_segv(int sig,siginfo_t * info,void * puc)84b9dd6ff9STaylor Simpson static void sig_segv(int sig, siginfo_t *info, void *puc)
85b9dd6ff9STaylor Simpson {
86b9dd6ff9STaylor Simpson usr_overflow = read_usr_overflow();
87b9dd6ff9STaylor Simpson longjmp(jmp_env, 1);
88b9dd6ff9STaylor Simpson }
89b9dd6ff9STaylor Simpson
test_packet(void)908576e7ecSTaylor Simpson static void test_packet(void)
918576e7ecSTaylor Simpson {
92*0d57cd61STaylor Simpson int32_t convres;
93*0d57cd61STaylor Simpson int32_t satres;
94*0d57cd61STaylor Simpson uint32_t usr;
958576e7ecSTaylor Simpson
968576e7ecSTaylor Simpson asm("r2 = usr\n\t"
978576e7ecSTaylor Simpson "r2 = clrbit(r2, #0)\n\t" /* clear overflow bit */
988576e7ecSTaylor Simpson "r2 = clrbit(r2, #1)\n\t" /* clear FP invalid bit */
998576e7ecSTaylor Simpson "usr = r2\n\t"
1008576e7ecSTaylor Simpson "{\n\t"
1018576e7ecSTaylor Simpson " %0 = convert_sf2uw(%3):chop\n\t"
1028576e7ecSTaylor Simpson " %1 = satb(%4)\n\t"
1038576e7ecSTaylor Simpson "}\n\t"
1048576e7ecSTaylor Simpson "%2 = usr\n\t"
1058576e7ecSTaylor Simpson : "=r"(convres), "=r"(satres), "=r"(usr)
1068576e7ecSTaylor Simpson : "r"(0x6a051b86), "r"(0x0410eec0)
1078576e7ecSTaylor Simpson : "r2", "usr");
1088576e7ecSTaylor Simpson
109*0d57cd61STaylor Simpson check32(convres, 0xffffffff);
110*0d57cd61STaylor Simpson check32(satres, 0x7f);
111*0d57cd61STaylor Simpson check32(get_usr_overflow(usr), true);
112*0d57cd61STaylor Simpson check32(get_usr_fp_invalid(usr), true);
1138576e7ecSTaylor Simpson
1148576e7ecSTaylor Simpson asm("r2 = usr\n\t"
1158576e7ecSTaylor Simpson "r2 = clrbit(r2, #0)\n\t" /* clear overflow bit */
1168576e7ecSTaylor Simpson "usr = r2\n\t"
1178576e7ecSTaylor Simpson "%2 = r2\n\t"
1188576e7ecSTaylor Simpson "p3 = sp3loop0(1f, #1)\n\t"
1198576e7ecSTaylor Simpson "1:\n\t"
1208576e7ecSTaylor Simpson "{\n\t"
1218576e7ecSTaylor Simpson " %0 = satb(%2)\n\t"
1228576e7ecSTaylor Simpson "}:endloop0\n\t"
1238576e7ecSTaylor Simpson "%1 = usr\n\t"
1248576e7ecSTaylor Simpson : "=r"(satres), "=r"(usr)
1258576e7ecSTaylor Simpson : "r"(0x0410eec0)
1268576e7ecSTaylor Simpson : "r2", "usr", "p3", "sa0", "lc0");
1278576e7ecSTaylor Simpson
128*0d57cd61STaylor Simpson check32(satres, 0x7f);
129*0d57cd61STaylor Simpson check32(get_usr_overflow(usr), true);
130*0d57cd61STaylor Simpson check32(get_usr_lpcfg(usr), 2);
1318576e7ecSTaylor Simpson }
1328576e7ecSTaylor Simpson
main()133b9dd6ff9STaylor Simpson int main()
134b9dd6ff9STaylor Simpson {
135b9dd6ff9STaylor Simpson struct sigaction act;
136*0d57cd61STaylor Simpson bool ovf;
137b9dd6ff9STaylor Simpson
138b9dd6ff9STaylor Simpson /* SIGSEGV test */
139b9dd6ff9STaylor Simpson act.sa_sigaction = sig_segv;
140b9dd6ff9STaylor Simpson sigemptyset(&act.sa_mask);
141b9dd6ff9STaylor Simpson act.sa_flags = SA_SIGINFO;
142b9dd6ff9STaylor Simpson sigaction(SIGSEGV, &act, NULL);
143b9dd6ff9STaylor Simpson if (setjmp(jmp_env) == 0) {
144b9dd6ff9STaylor Simpson satub(300, 0, &ovf);
145b9dd6ff9STaylor Simpson }
146b9dd6ff9STaylor Simpson
147b9dd6ff9STaylor Simpson act.sa_handler = SIG_DFL;
148b9dd6ff9STaylor Simpson sigemptyset(&act.sa_mask);
149b9dd6ff9STaylor Simpson act.sa_flags = 0;
150b9dd6ff9STaylor Simpson
151*0d57cd61STaylor Simpson check32(usr_overflow, false);
152b9dd6ff9STaylor Simpson
1538576e7ecSTaylor Simpson test_packet();
1548576e7ecSTaylor Simpson
155b9dd6ff9STaylor Simpson puts(err ? "FAIL" : "PASS");
156b9dd6ff9STaylor Simpson return err ? EXIT_FAILURE : EXIT_SUCCESS;
157b9dd6ff9STaylor Simpson }
158