xref: /openbmc/qemu/tests/tcg/hexagon/overflow.c (revision b14df228)
1 /*
2  *  Copyright(c) 2021-2022 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 #include <stdlib.h>
19 #include <stdio.h>
20 #include <unistd.h>
21 #include <sys/types.h>
22 #include <fcntl.h>
23 #include <setjmp.h>
24 #include <signal.h>
25 
26 
27 int err;
28 
29 static void __check(const char *filename, int line, int x, int expect)
30 {
31     if (x != expect) {
32         printf("ERROR %s:%d - %d != %d\n",
33                filename, line, x, expect);
34         err++;
35     }
36 }
37 
38 #define check(x, expect) __check(__FILE__, __LINE__, (x), (expect))
39 
40 static int satub(int src, int *p, int *ovf_result)
41 {
42     int result;
43     int usr;
44 
45     /*
46      * This instruction can set bit 0 (OVF/overflow) in usr
47      * Clear the bit first, then return that bit to the caller
48      *
49      * We also store the src into *p in the same packet, so we
50      * can ensure the overflow doesn't get set when an exception
51      * is generated.
52      */
53     asm volatile("r2 = usr\n\t"
54                  "r2 = clrbit(r2, #0)\n\t"        /* clear overflow bit */
55                  "usr = r2\n\t"
56                  "{\n\t"
57                  "    %0 = satub(%2)\n\t"
58                  "    memw(%3) = %2\n\t"
59                  "}\n\t"
60                  "%1 = usr\n\t"
61                  : "=r"(result), "=r"(usr)
62                  : "r"(src), "r"(p)
63                  : "r2", "usr", "memory");
64   *ovf_result = (usr & 1);
65   return result;
66 }
67 
68 int read_usr_overflow(void)
69 {
70     int result;
71     asm volatile("%0 = usr\n\t" : "=r"(result));
72     return result & 1;
73 }
74 
75 int get_usr_overflow(int usr)
76 {
77     return usr & 1;
78 }
79 
80 int get_usr_fp_invalid(int usr)
81 {
82     return (usr >> 1) & 1;
83 }
84 
85 int get_usr_lpcfg(int usr)
86 {
87     return (usr >> 8) & 0x3;
88 }
89 
90 jmp_buf jmp_env;
91 int usr_overflow;
92 
93 static void sig_segv(int sig, siginfo_t *info, void *puc)
94 {
95     usr_overflow = read_usr_overflow();
96     longjmp(jmp_env, 1);
97 }
98 
99 static void test_packet(void)
100 {
101     int convres;
102     int satres;
103     int usr;
104 
105     asm("r2 = usr\n\t"
106         "r2 = clrbit(r2, #0)\n\t"        /* clear overflow bit */
107         "r2 = clrbit(r2, #1)\n\t"        /* clear FP invalid bit */
108         "usr = r2\n\t"
109         "{\n\t"
110         "    %0 = convert_sf2uw(%3):chop\n\t"
111         "    %1 = satb(%4)\n\t"
112         "}\n\t"
113         "%2 = usr\n\t"
114         : "=r"(convres), "=r"(satres), "=r"(usr)
115         : "r"(0x6a051b86), "r"(0x0410eec0)
116         : "r2", "usr");
117 
118     check(convres, 0xffffffff);
119     check(satres, 0x7f);
120     check(get_usr_overflow(usr), 1);
121     check(get_usr_fp_invalid(usr), 1);
122 
123     asm("r2 = usr\n\t"
124         "r2 = clrbit(r2, #0)\n\t"        /* clear overflow bit */
125         "usr = r2\n\t"
126         "%2 = r2\n\t"
127         "p3 = sp3loop0(1f, #1)\n\t"
128         "1:\n\t"
129         "{\n\t"
130         "    %0 = satb(%2)\n\t"
131         "}:endloop0\n\t"
132         "%1 = usr\n\t"
133         : "=r"(satres), "=r"(usr)
134         : "r"(0x0410eec0)
135         : "r2", "usr", "p3", "sa0", "lc0");
136 
137     check(satres, 0x7f);
138     check(get_usr_overflow(usr), 1);
139     check(get_usr_lpcfg(usr), 2);
140 }
141 
142 int main()
143 {
144     struct sigaction act;
145     int ovf;
146 
147     /* SIGSEGV test */
148     act.sa_sigaction = sig_segv;
149     sigemptyset(&act.sa_mask);
150     act.sa_flags = SA_SIGINFO;
151     sigaction(SIGSEGV, &act, NULL);
152     if (setjmp(jmp_env) == 0) {
153         satub(300, 0, &ovf);
154     }
155 
156     act.sa_handler = SIG_DFL;
157     sigemptyset(&act.sa_mask);
158     act.sa_flags = 0;
159 
160     check(usr_overflow, 0);
161 
162     test_packet();
163 
164     puts(err ? "FAIL" : "PASS");
165     return err ? EXIT_FAILURE : EXIT_SUCCESS;
166 }
167