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#pragma once
32
33#include <cstdint>
34#include <type_traits>
35
36#include "insttest.h"
37
38#define CIOP(op, r, imm) asm volatile(op " %0,%1" : "+r" (r) : "i" (imm));
39#define CROP(op, rd, rs) asm volatile(op " %0,%1" : "+r" (rd) : "r" (rs))
40
41namespace C
42{
43
44inline int64_t
45c_li(const int8_t imm)
46{
47    int64_t rd = 0;
48    CIOP("c.li", rd, imm);
49    return rd;
50}
51
52inline int64_t
53c_lui(const int8_t imm)
54{
55    int64_t rd = 0;
56    CIOP("c.lui", rd, imm);
57    return rd;
58}
59
60inline int64_t
61c_addi(int64_t r, const int8_t imm)
62{
63    CIOP("c.addi", r, imm);
64    return r;
65}
66
67inline int64_t
68c_addiw(int64_t r, const int8_t imm)
69{
70    CIOP("c.addiw", r, imm);
71    return r;
72}
73
74inline uint64_t
75c_addi4spn(const int16_t imm)
76{
77    uint64_t rd = 0;
78    asm volatile("c.addi4spn %0,sp,%1" : "=r" (rd) : "i" (imm));
79    return rd;
80}
81
82inline uint64_t
83c_slli(uint64_t r, uint8_t shamt)
84{
85    CIOP("c.slli", r, shamt);
86    return r;
87}
88
89inline uint64_t
90c_srli(uint64_t r, uint8_t shamt)
91{
92    CIOP("c.srli", r, shamt);
93    return r;
94}
95
96inline int64_t
97c_srai(int64_t r, uint8_t shamt)
98{
99    CIOP("c.srai", r, shamt);
100    return r;
101}
102
103inline uint64_t
104c_andi(uint64_t r, uint8_t imm)
105{
106    CIOP("c.andi", r, imm);
107    return r;
108}
109
110inline int64_t
111c_mv(int64_t rs)
112{
113    int64_t rd = 0;
114    CROP("c.mv", rd, rs);
115    return rd;
116}
117
118inline int64_t
119c_add(int64_t rd, int64_t rs)
120{
121    CROP("c.add", rd, rs);
122    return rd;
123}
124
125inline uint64_t
126c_and(int64_t rd, int64_t rs)
127{
128    CROP("c.and", rd, rs);
129    return rd;
130}
131
132inline uint64_t
133c_or(int64_t rd, int64_t rs)
134{
135    CROP("c.or", rd, rs);
136    return rd;
137}
138
139inline uint64_t
140c_xor(int64_t rd, int64_t rs)
141{
142    CROP("c.xor", rd, rs);
143    return rd;
144}
145
146inline int64_t
147c_sub(int64_t rd, int64_t rs)
148{
149    CROP("c.sub", rd, rs);
150    return rd;
151}
152
153inline int64_t
154c_addw(int64_t rd, int64_t rs)
155{
156    CROP("c.addw", rd, rs);
157    return rd;
158}
159
160inline int64_t
161c_subw(int64_t rd, int64_t rs)
162{
163    CROP("c.subw", rd, rs);
164    return rd;
165}
166
167template<typename M, typename R> inline R
168c_load(M m)
169{
170    R r = 0;
171    switch (sizeof(M))
172    {
173      case 4:
174        asm volatile("c.lw %0,0(%1)" : "=r" (r) : "r" (&m) : "memory");
175        break;
176      case 8:
177        if (std::is_floating_point<M>::value)
178            asm volatile("c.fld %0,0(%1)" : "=f" (r) : "r" (&m) : "memory");
179        else
180            asm volatile("c.ld %0,0(%1)" : "=r" (r) : "r" (&m) : "memory");
181        break;
182    }
183    return r;
184}
185
186template<typename M> inline M
187c_store(const M& rs)
188{
189    M mem = 0;
190    switch (sizeof(M))
191    {
192      case 4:
193        asm volatile("c.sw %0,0(%1)" : : "r" (rs), "r" (&mem) : "memory");
194        break;
195      case 8:
196        if (std::is_floating_point<M>::value)
197            asm volatile("c.fsd %0,0(%1)" : : "f" (rs), "r" (&mem) : "memory");
198        else
199            asm volatile("c.sd %0,0(%1)" : : "r" (rs), "r" (&mem) : "memory");
200        break;
201    }
202    return mem;
203}
204
205inline bool
206c_j()
207{
208    asm volatile goto("c.j %l[jallabel]" : : : : jallabel);
209    return false;
210  jallabel:
211    return true;
212}
213
214inline bool
215c_jr()
216{
217    uint64_t a = 0;
218    asm volatile("auipc %0,0;"
219                 "c.addi %0,12;"
220                 "c.jr %0;"
221                 "addi %0,zero,0;"
222                 "addi %0,%0,0;"
223                 : "+r" (a));
224    return a > 0;
225}
226
227inline bool
228c_jalr()
229{
230    int64_t a = 0;
231    asm volatile("auipc %0,0;"
232                 "c.addi %0,12;"
233                 "c.jalr %0;"
234                 "addi %0,zero,0;"
235                 "sub %0,ra,%0;"
236                 : "+r" (a)
237                 :
238                 : "ra");
239    return a == -4;
240}
241
242inline bool
243c_beqz(int64_t a)
244{
245    asm volatile goto("c.beqz %0,%l[beqlabel]"
246            :
247            : "r" (a)
248            :
249            : beqlabel);
250    return false;
251  beqlabel:
252    return true;
253}
254
255inline bool
256c_bnez(int64_t a)
257{
258    asm volatile goto("c.bnez %0,%l[beqlabel]"
259            :
260            : "r" (a)
261            :
262            : beqlabel);
263    return false;
264  beqlabel:
265    return true;
266}
267
268} // namespace C