1/*
2 * Copyright (c) 2016 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#pragma once
32
33#include <cstdint>
34#include <iostream>
35
36#include "insttest.h"
37
38namespace I
39{
40
41inline uint64_t
42lui(const uint32_t imm)
43{
44    int64_t rd = -1;
45    asm volatile("lui %0,%1" : "=r" (rd) : "i" (imm));
46    return rd;
47}
48
49inline bool
50auipc(const uint64_t imm)
51{
52    int64_t rd = -1;
53    asm volatile("auipc %0,%1" : "=r" (rd) : "i" (imm));
54    std::cout << "auipc: 0x" << std::hex << std::uppercase << rd <<
55        std::nouppercase << std::dec << std::endl;
56    return rd >= imm;
57}
58
59inline bool
60jal()
61{
62    asm volatile goto("jal zero,%l[jallabel]" : : : : jallabel);
63    return false;
64  jallabel:
65    return true;
66}
67
68inline bool
69jalr()
70{
71    int a = 0;
72    asm volatile("auipc %0,0;"
73                 "jalr t0,%0,12;"
74                 "addi %0,zero,0;"
75                 "sub %0,t0,%0;"
76                 : "+r" (a)
77                 :
78                 : "t0");
79    return a == 8;
80}
81
82inline bool
83beq(int64_t a, int64_t b)
84{
85    asm volatile goto("beq %0,%1,%l[beqlabel]"
86            :
87            : "r" (a), "r" (b)
88            :
89            : beqlabel);
90    return false;
91  beqlabel:
92    return true;
93}
94
95inline bool
96bne(int64_t a, int64_t b)
97{
98    asm volatile goto("bne %0,%1,%l[bnelabel]"
99            :
100            : "r" (a), "r" (b)
101            :
102            : bnelabel);
103    return false;
104  bnelabel:
105    return true;
106}
107
108inline bool
109blt(int64_t a, int64_t b)
110{
111    asm volatile goto("blt %0,%1,%l[bltlabel]"
112            :
113            : "r" (a), "r" (b)
114            :
115            : bltlabel);
116    return false;
117  bltlabel:
118    return true;
119}
120
121inline bool
122bge(int64_t a, int64_t b)
123{
124    asm volatile goto("bge %0,%1,%l[bgelabel]"
125            :
126            : "r" (a), "r" (b)
127            :
128            : bgelabel);
129    return false;
130  bgelabel:
131    return true;
132}
133
134inline bool
135bltu(uint64_t a, uint64_t b)
136{
137    asm volatile goto("bltu %0,%1,%l[bltulabel]"
138            :
139            : "r" (a), "r" (b)
140            :
141            : bltulabel);
142    return false;
143  bltulabel:
144    return true;
145}
146
147inline bool
148bgeu(uint64_t a, uint64_t b)
149{
150    asm volatile goto("bgeu %0,%1,%l[bgeulabel]"
151            :
152            : "r" (a), "r" (b)
153            :
154            : bgeulabel);
155    return false;
156  bgeulabel:
157    return true;
158}
159
160template<typename M, typename R> inline R
161load(const M& b)
162{
163    R a = 0;
164    switch(sizeof(M))
165    {
166      case 1:
167        if (std::is_signed<M>::value) {
168            asm volatile("lb %0,%1" : "=r" (a) : "m" (b));
169        } else {
170            asm volatile("lbu %0,%1" : "=r" (a) : "m" (b));
171        }
172        break;
173      case 2:
174        if (std::is_signed<M>::value) {
175            asm volatile("lh %0,%1" : "=r" (a) : "m" (b));
176        } else {
177            asm volatile("lhu %0,%1" : "=r" (a) : "m" (b));
178        }
179        break;
180      case 4:
181        if (std::is_signed<M>::value) {
182            asm volatile("lw %0,%1" : "=r" (a) : "m" (b));
183        } else {
184            asm volatile("lwu %0,%1" : "=r" (a) : "m" (b));
185        }
186        break;
187      case 8:
188        asm volatile("ld %0,%1" : "=r" (a) : "m" (b));
189        break;
190    }
191    return a;
192}
193
194template<typename M> inline M
195store(const M& rs2)
196{
197    M mem = 0;
198    switch (sizeof(M))
199    {
200      case 1:
201        asm volatile("sb %1,%0" : "=m" (mem) : "r" (rs2));
202        break;
203      case 2:
204        asm volatile("sh %1,%0" : "=m" (mem) : "r" (rs2));
205        break;
206      case 4:
207        asm volatile("sw %1,%0" : "=m" (mem) : "r" (rs2));
208        break;
209      case 8:
210        asm volatile("sd %1,%0" : "=m" (mem) : "r" (rs2));
211        break;
212    }
213    return mem;
214}
215
216inline int64_t
217addi(int64_t rs1, const int16_t imm)
218{
219    int64_t rd = 0;
220    IOP("addi", rd, rs1, imm);
221    return rd;
222}
223
224inline bool
225slti(int64_t rs1, const int16_t imm)
226{
227    bool rd = false;
228    IOP("slti", rd, rs1, imm);
229    return rd;
230}
231
232inline bool
233sltiu(uint64_t rs1, const uint16_t imm)
234{
235    bool rd = false;
236    IOP("sltiu", rd, rs1, imm);
237    return rd;
238}
239
240inline uint64_t
241xori(uint64_t rs1, const uint16_t imm)
242{
243    uint64_t rd = 0;
244    IOP("xori", rd, rs1, imm);
245    return rd;
246}
247
248inline uint64_t
249ori(uint64_t rs1, const uint16_t imm)
250{
251    uint64_t rd = 0;
252    IOP("ori", rd, rs1, imm);
253    return rd;
254}
255
256inline uint64_t
257andi(uint64_t rs1, const uint16_t imm)
258{
259    uint64_t rd = 0;
260    IOP("andi", rd, rs1, imm);
261    return rd;
262}
263
264inline int64_t
265slli(int64_t rs1, const uint16_t imm)
266{
267    int64_t rd = 0;
268    IOP("slli", rd, rs1, imm);
269    return rd;
270}
271
272inline uint64_t
273srli(uint64_t rs1, const uint16_t imm)
274{
275    uint64_t rd = 0;
276    IOP("srli", rd, rs1, imm);
277    return rd;
278}
279
280inline int64_t
281srai(int64_t rs1, const uint16_t imm)
282{
283    int64_t rd = 0;
284    IOP("srai", rd, rs1, imm);
285    return rd;
286}
287
288inline int64_t
289add(int64_t rs1, int64_t rs2)
290{
291    int64_t rd = 0;
292    ROP("add", rd, rs1, rs2);
293    return rd;
294}
295
296inline int64_t
297sub(int64_t rs1, int64_t rs2)
298{
299    int64_t rd = 0;
300    ROP("sub", rd, rs1, rs2);
301    return rd;
302}
303
304inline int64_t
305sll(int64_t rs1, int64_t rs2)
306{
307    int64_t rd = 0;
308    ROP("sll", rd, rs1, rs2);
309    return rd;
310}
311
312inline bool
313slt(int64_t rs1, int64_t rs2)
314{
315    bool rd = false;
316    ROP("slt", rd, rs1, rs2);
317    return rd;
318}
319
320inline bool
321sltu(uint64_t rs1, uint64_t rs2)
322{
323    bool rd = false;
324    ROP("sltu", rd, rs1, rs2);
325    return rd;
326}
327
328inline uint64_t
329xor_inst(uint64_t rs1, uint64_t rs2)
330{
331    uint64_t rd = 0;
332    ROP("xor", rd, rs1, rs2);
333    return rd;
334}
335
336inline uint64_t
337srl(uint64_t rs1, uint64_t rs2)
338{
339    uint64_t rd = 0;
340    ROP("srl", rd, rs1, rs2);
341    return rd;
342}
343
344inline int64_t
345sra(int64_t rs1, int64_t rs2)
346{
347    int64_t rd = 0;
348    ROP("sra", rd, rs1, rs2);
349    return rd;
350}
351
352inline uint64_t
353or_inst(uint64_t rs1, uint64_t rs2)
354{
355    uint64_t rd = 0;
356    ROP("or", rd, rs1, rs2);
357    return rd;
358}
359
360inline uint64_t
361and_inst(uint64_t rs1, uint64_t rs2)
362{
363    uint64_t rd = 0;
364    ROP("and", rd, rs1, rs2);
365    return rd;
366}
367
368inline int64_t
369addiw(int64_t rs1, const int16_t imm)
370{
371    int64_t rd = 0;
372    IOP("addiw", rd, rs1, imm);
373    return rd;
374}
375
376inline int64_t
377slliw(int64_t rs1, const uint16_t imm)
378{
379    int64_t rd = 0;
380    IOP("slliw", rd, rs1, imm);
381    return rd;
382}
383
384inline uint64_t
385srliw(uint64_t rs1, const uint16_t imm)
386{
387    uint64_t rd = 0;
388    IOP("srliw", rd, rs1, imm);
389    return rd;
390}
391
392inline int64_t
393sraiw(int64_t rs1, const uint16_t imm)
394{
395    int64_t rd = 0;
396    IOP("sraiw", rd, rs1, imm);
397    return rd;
398}
399
400inline int64_t
401addw(int64_t rs1,  int64_t rs2)
402{
403    int64_t rd = 0;
404    ROP("addw", rd, rs1, rs2);
405    return rd;
406}
407
408inline int64_t
409subw(int64_t rs1,  int64_t rs2)
410{
411    int64_t rd = 0;
412    ROP("subw", rd, rs1, rs2);
413    return rd;
414}
415
416inline int64_t
417sllw(int64_t rs1,  int64_t rs2)
418{
419    int64_t rd = 0;
420    ROP("sllw", rd, rs1, rs2);
421    return rd;
422}
423
424inline uint64_t
425srlw(uint64_t rs1,  uint64_t rs2)
426{
427    uint64_t rd = 0;
428    ROP("srlw", rd, rs1, rs2);
429    return rd;
430}
431
432inline int64_t
433sraw(int64_t rs1,  int64_t rs2)
434{
435    int64_t rd = 0;
436    ROP("sraw", rd, rs1, rs2);
437    return rd;
438}
439
440} // namespace I
441