1/*
2 * Copyright (c) 2017 The University of Virginia
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * Authors: Alec Roelke
29 */
30
31#include <limits>
32
33#include "insttest.h"
34#include "rv64c.h"
35#include "rv64d.h"
36
37int main()
38{
39    using namespace insttest;
40    using namespace std;
41
42    // C.LWSP
43    expect<bool>(true, []{
44        uint64_t lw = 0, lwsp = -1;
45        int64_t i = 16;
46        asm volatile("lw %0,%2(sp);"
47                     "c.lwsp %1,%2(sp);"
48                     : "=r" (lw), "=r" (lwsp)
49                     : "i" (i));
50        return lw == lwsp;
51    }, "c.lwsp");
52
53    // C.LDSP
54    expect<bool>(true, []{
55        uint64_t ld = 0, ldsp = -1;
56        int64_t i = 8;
57        asm volatile("ld %0,%2(sp);"
58                     "c.ldsp %1,%2(sp);"
59                     : "=r" (ld), "=r" (ldsp)
60                     : "i" (i));
61        return ld == ldsp;
62    }, "c.ldsp");
63
64    // C.FLDSP
65    expect<bool>(true, []{
66        double fld = 0.0, fldsp = -1.0;
67        int64_t i = 32;
68        asm volatile("fld %0,%2(sp);"
69                     "c.fldsp %1,%2(sp);"
70                     : "=f" (fld), "=f" (fldsp)
71                     : "i" (i));
72        return D::bits(fld) == D::bits(fldsp);
73    }, "c.fldsp");
74
75    // C.SWSP
76    expect<bool>(true, []{
77        int64_t value = -1, result = 0;
78        asm volatile("addi sp,sp,-8;"
79                     "c.swsp %1,8(sp);"
80                     "lw %0,8(sp);"
81                     "addi sp,sp,8;"
82                     : "=r" (result)
83                     : "r" (value)
84                     : "memory");
85        return value == result;
86    }, "c.swsp");
87
88    // C.SDSP
89    expect<bool>(true, []{
90        int64_t value = -1, result = 0;
91        asm volatile("addi sp,sp,-8;"
92                     "c.sdsp %1,8(sp);"
93                     "ld %0,8(sp);"
94                     "addi sp,sp,8;"
95                     : "=r" (result)
96                     : "r" (value)
97                     : "memory");
98        return value == result;
99    }, "c.sdsp");
100
101    // C.FSDSP
102    expect<bool>(true, []{
103        double value = 0.1, result = numeric_limits<double>::signaling_NaN();
104        asm volatile("addi sp,sp,-8;"
105                     "c.fsdsp %1,8(sp);"
106                     "fld %0,8(sp);"
107                     "addi sp,sp,8;"
108                     : "=f" (result)
109                     : "f" (value)
110                     : "memory");
111        return value == result;
112    }, "c.fsdsp");
113
114    // C.LW, C.LD, C.FLD
115    expect<int64_t>(458752,
116            []{return C::c_load<int32_t, int64_t>(0x00070000);},
117            "c.lw, positive");
118    expect<int64_t>(numeric_limits<int32_t>::min(),
119            []{return C::c_load<int32_t, int64_t>(0x80000000);},
120            "c.lw, negative");
121    expect<int64_t>(30064771072,
122            []{return C::c_load<int64_t, int64_t>(30064771072);}, "c.ld");
123    expect<double>(3.1415926, []{return C::c_load<double, double>(3.1415926);},
124        "c.fld");
125
126    // C.SW, C.SD, C.FSD
127    expect<uint32_t>(0xFFFFFFFF, []{return C::c_store<int32_t>(-1);}, "c.sw");
128    expect<uint64_t>(-1, []{return C::c_store<int64_t>(-1);}, "c.sd");
129    expect<double>(1.61803398875,
130            []{return C::c_store<double>(1.61803398875);}, "c.fsd");
131
132    // C.J, C.JR, C.JALR
133    expect<bool>(true, []{return C::c_j();}, "c.j");
134    expect<bool>(true, []{return C::c_jr();}, "c.jr");
135    expect<bool>(true, []{return C::c_jalr();}, "c.jalr");
136
137    // C.BEQZ
138    expect<bool>(true, []{return C::c_beqz(0);}, "c.beqz, zero");
139    expect<bool>(false, []{return C::c_beqz(7);}, "c.beqz, not zero");
140
141    // C.BNEZ
142    expect<bool>(true, []{return C::c_bnez(15);}, "c.bnez, not zero");
143    expect<bool>(false, []{return C::c_bnez(0);}, "c.bnez, zero");
144
145    // C.LI
146    expect<int64_t>(1, []{return C::c_li(1);}, "c.li");
147    expect<int64_t>(-1, []{return C::c_li(-1);}, "c.li, sign extend");
148
149    // C.LUI
150    expect<int64_t>(4096, []{return C::c_lui(1);}, "c.lui");
151    // Note that sign extension can't be tested here because apparently the
152    // compiler doesn't allow the 6th (sign) bit of the immediate to be 1
153
154    // C.ADDI
155    expect<int64_t>(15, []{return C::c_addi(7, 8);}, "c.addi");
156
157    // C.ADDIW
158    expect<int64_t>(15, []{return C::c_addiw(8, 7);}, "c.addiw");
159    expect<int64_t>(1, []{return C::c_addiw(0xFFFFFFFF, 2);},
160            "c.addiw, overflow");
161    expect<int64_t>(1, []{return C::c_addiw(0x100000001, 0);},
162            "c.addiw, truncate");
163
164    // C.ADDI16SP
165    expect<bool>(true, []{
166        uint64_t sp = 0, rd = 0;
167        const int16_t i = 4;
168        asm volatile("mv %0,sp;"
169                     "c.addi16sp sp,%2;"
170                     "mv %1,sp;"
171                     "mv sp,%0;"
172                     : "+r" (sp), "=r" (rd)
173                     : "i" (i*16));
174        return rd == sp + i*16;
175    }, "c.addi16sp");
176
177    // C.ADDI4SPN
178    expect<bool>(true, []{
179        uint64_t sp = 0, rd = 0;
180        const int16_t i = 3;
181        asm volatile("mv %0,sp;"
182                     "c.addi4spn %1,sp,%2;"
183                     : "=r" (sp), "=r" (rd)
184                     : "i" (i*4));
185        return rd == sp + i*4;
186    }, "c.addi4spn");
187
188    // C.SLLI
189    expect<uint64_t>(16, []{return C::c_slli(1, 4);}, "c.slli");
190    expect<uint64_t>(0, []{return C::c_slli(8, 61);}, "c.slli, overflow");
191
192    // C.SRLI
193    expect<uint64_t>(4, []{return C::c_srli(128, 5);}, "c.srli");
194    expect<uint64_t>(0, []{return C::c_srli(128, 8);}, "c.srli, overflow");
195    expect<uint64_t>(1, []{return C::c_srli(-1, 63);}, "c.srli, -1");
196
197    // C.SRAI
198    expect<uint64_t>(4, []{return C::c_srai(128, 5);}, "c.srai");
199    expect<uint64_t>(0, []{return C::c_srai(128, 8);}, "c.srai, overflow");
200    expect<uint64_t>(-1, []{return C::c_srai(-2, 63);}, "c.srai, -1");
201
202    // C.ANDI
203    expect<uint64_t>(0, []{return C::c_andi(-1, 0);}, "c.andi (0)");
204    expect<uint64_t>(0x1234567812345678ULL,
205            []{return C::c_andi(0x1234567812345678ULL, -1);}, "c.andi (1)");
206
207    // C.MV
208    expect<int64_t>(1024, []{return C::c_mv(1024);}, "c.mv");
209
210    // C.ADD
211    expect<int64_t>(15, []{return C::c_add(10, 5);}, "c.add");
212
213    // C.AND
214    expect<uint64_t>(0, []{return C::c_and(-1, 0);}, "c.and (0)");
215    expect<uint64_t>(0x1234567812345678ULL,
216            []{return C::c_and(0x1234567812345678ULL, -1);}, "c.and (-1)");
217
218    // C.OR
219    expect<uint64_t>(-1,
220            []{return C::c_or(0xAAAAAAAAAAAAAAAAULL,
221                    0x5555555555555555ULL);},
222            "c.or (1)");
223    expect<uint64_t>(0xAAAAAAAAAAAAAAAAULL,
224            []{return C::c_or(0xAAAAAAAAAAAAAAAAULL,
225                    0xAAAAAAAAAAAAAAAAULL);},
226            "c.or (A)");
227
228    // C.XOR
229    expect<uint64_t>(-1,
230            []{return C::c_xor(0xAAAAAAAAAAAAAAAAULL,
231                    0x5555555555555555ULL);},
232            "c.xor (1)");
233    expect<uint64_t>(0,
234            []{return C::c_xor(0xAAAAAAAAAAAAAAAAULL,
235                    0xAAAAAAAAAAAAAAAAULL);},
236            "c.xor (0)");
237
238    // C.SUB
239    expect<int64_t>(65535, []{return C::c_sub(65536, 1);}, "c.sub");
240
241    // C.ADDW
242    expect<int64_t>(1073742078, []{return C::c_addw(0x3FFFFFFF, 255);},
243            "c.addw");
244    expect<int64_t>(-1, []{return C::c_addw(0x7FFFFFFF, 0x80000000);},
245            "c.addw, overflow");
246    expect<int64_t>(65536, []{return C::c_addw(0xFFFFFFFF0000FFFFLL, 1);},
247            "c.addw, truncate");
248
249    // C.SUBW
250    expect<int64_t>(65535, []{return C::c_subw(65536, 1);}, "c.subw");
251    expect<int64_t>(-1, []{return C::c_subw(0x7FFFFFFF, 0x80000000);},
252            "c.subw, \"overflow\"");
253    expect<int64_t>(0,
254            []{return C::c_subw(0xAAAAAAAAFFFFFFFFULL,0x55555555FFFFFFFFULL);},
255            "c.subw, truncate");
256}