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#include <fcntl.h>
32#include <sys/stat.h>
33#include <sys/time.h>
34#include <sys/times.h>
35#include <sys/types.h>
36#include <unistd.h>
37
38#include <cstdint>
39#include <cstring>
40#include <iostream>
41#include <limits>
42
43#include "insttest.h"
44#include "rv64i.h"
45
46int main()
47{
48    using namespace std;
49    using namespace insttest;
50
51    // LUI
52    expect<int64_t>(4096, []{return I::lui(1);}, "lui");
53    expect<int64_t>(numeric_limits<int32_t>::min(),
54            []{return I::lui(0x80000);}, "lui, negative");
55
56    // AUIPC
57    expect<bool>(true, []{return I::auipc(3);}, "auipc");
58
59    // Jump (JAL, JALR)
60    expect<bool>(true, []{return I::jal();}, "jal");
61    expect<bool>(true, []{return I::jalr();}, "jalr");
62
63    // BEQ
64    expect<bool>(true, []{return I::beq(5, 5);}, "beq, equal");
65    expect<bool>(false, []{return I::beq(numeric_limits<int64_t>::max(),
66            numeric_limits<int64_t>::min());}, "beq, not equal");
67
68    // BNE
69    expect<bool>(false, []{return I::bne(5, 5);}, "bne, equal");
70    expect<bool>(true, []{return I::bne(numeric_limits<int64_t>::max(),
71            numeric_limits<int64_t>::min());}, "bne, not equal");
72
73    // BLT
74    expect<bool>(true, []{return I::blt(numeric_limits<int64_t>::min(),
75            numeric_limits<int64_t>::max());}, "blt, less");
76    expect<bool>(false, []{return I::blt(numeric_limits<int64_t>::min(),
77            numeric_limits<int64_t>::min());}, "blt, equal");
78    expect<bool>(false, []{return I::blt(numeric_limits<int64_t>::max(),
79            numeric_limits<int64_t>::min());}, "blt, greater");
80
81    // BGE
82    expect<bool>(false, []{return I::bge(numeric_limits<int64_t>::min(),
83            numeric_limits<int64_t>::max());}, "bge, less");
84    expect<bool>(true, []{return I::bge(numeric_limits<int64_t>::min(),
85            numeric_limits<int64_t>::min());}, "bge, equal");
86    expect<bool>(true, []{return I::bge(numeric_limits<int64_t>::max(),
87            numeric_limits<int64_t>::min());}, "bge, greater");
88
89    // BLTU
90    expect<bool>(true, []{return I::blt(numeric_limits<int64_t>::min(),
91            numeric_limits<int64_t>::max());}, "bltu, greater");
92    expect<bool>(false, []{return I::blt(numeric_limits<int64_t>::min(),
93            numeric_limits<int64_t>::min());}, "bltu, equal");
94    expect<bool>(false, []{return I::blt(numeric_limits<int64_t>::max(),
95            numeric_limits<int64_t>::min());}, "bltu, less");
96
97    // BGEU
98    expect<bool>(false, []{return I::bge(numeric_limits<int64_t>::min(),
99            numeric_limits<int64_t>::max());}, "bgeu, greater");
100    expect<bool>(true, []{return I::bge(numeric_limits<int64_t>::min(),
101            numeric_limits<int64_t>::min());}, "bgeu, equal");
102    expect<bool>(true, []{return I::bge(numeric_limits<int64_t>::max(),
103            numeric_limits<int64_t>::min());}, "bgeu, less");
104
105    // Load (LB, LH, LW, LBU, LHU)
106    expect<int64_t>(7, []{return I::load<int8_t, int64_t>(0x07);},
107            "lb, positive");
108    expect<int64_t>(numeric_limits<int8_t>::min(),
109            []{return I::load<int8_t, int64_t>(0x80);}, "lb, negative");
110    expect<int64_t>(1792, []{return I::load<int16_t, int64_t>(0x0700);},
111            "lh, positive");
112    expect<int64_t>(numeric_limits<int16_t>::min(),
113            []{return I::load<int16_t, int64_t>(0x8000);}, "lh, negative");
114    expect<int64_t>(458752, []{return I::load<int32_t, int64_t>(0x00070000);},
115            "lw, positive");
116    expect<int64_t>(numeric_limits<int32_t>::min(),
117            []{return I::load<int32_t, int64_t>(0x80000000);},
118            "lw, negative");
119    expect<uint64_t>(128, []{return I::load<uint8_t, uint64_t>(0x80);}, "lbu");
120    expect<uint64_t>(32768, []{return I::load<uint16_t, uint64_t>(0x8000);},
121            "lhu");
122
123    // Store (SB, SH, SW)
124    expect<uint8_t>(0xFF, []{return I::store<int8_t>(-1);}, "sb");
125    expect<uint16_t>(0xFFFF, []{return I::store<int16_t>(-1);}, "sh");
126    expect<uint32_t>(0xFFFFFFFF, []{return I::store<int32_t>(-1);}, "sw");
127
128    // ADDI
129    expect<int64_t>(1073742078, []{return I::addi(0x3FFFFFFF, 255);},
130            "addi");
131    expect<int64_t>(1, []{return I::addi(-1, 2);}, "addi, overflow");
132
133    // SLTI
134    expect<bool>(true, []{return I::slti(-1, 0);}, "slti, true");
135    expect<bool>(false, []{return I::slti(0, -1);}, "slti, false");
136
137    // SLTIU
138    expect<bool>(false, []{return I::sltiu(-1, 0);}, "sltiu, false");
139    expect<bool>(true, []{return I::sltiu(0, -1);}, "sltiu, true");
140    expect<bool>(true, []{return I::sltiu(0xFFFF, -1);}, "sltiu, sext");
141
142    // XORI
143    expect<uint64_t>(0xFF, []{return I::xori(0xAA, 0x55);}, "xori (1)");
144    expect<uint64_t>(0, []{return I::xori(0xAA, 0xAA);}, "xori (0)");
145
146    // ORI
147    expect<uint64_t>(0xFF, []{return I::ori(0xAA, 0x55);}, "ori (1)");
148    expect<uint64_t>(0xAA, []{return I::ori(0xAA, 0xAA);}, "ori (A)");
149
150    // ANDI
151    expect<uint64_t>(0, []{return I::andi(-1, 0);}, "andi (0)");
152    expect<uint64_t>(0x1234567812345678ULL,
153            []{return I::andi(0x1234567812345678ULL, -1);}, "andi (1)");
154
155    // SLLI
156    expect<int64_t>(65280, []{return I::slli(255, 8);}, "slli, general");
157    expect<int64_t>(numeric_limits<int64_t>::min(),
158            []{return I::slli(255, 63);}, "slli, erase");
159
160    // SRLI
161    expect<int64_t>(255, []{return I::srli(65280, 8);}, "srli, general");
162    expect<int64_t>(0, []{return I::srli(255, 8);}, "srli, erase");
163    expect<int64_t>(1, []{return I::srli(numeric_limits<int64_t>::min(), 63);},
164            "srli, negative");
165
166    // SRAI
167    expect<int64_t>(255, []{return I::srai(65280, 8);}, "srai, general");
168    expect<int64_t>(0, []{return I::srai(255, 8);}, "srai, erase");
169    expect<int64_t>(-1,
170            []{return I::srai(numeric_limits<int64_t>::min(), 63);},
171            "srai, negative");
172
173    // ADD
174    expect<int64_t>(1073742078, []{return I::add(0x3FFFFFFF, 255);}, "add");
175    expect<int64_t>(-1,
176            []{return I::add(0x7FFFFFFFFFFFFFFFLL, 0x8000000000000000LL);},
177            "add, overflow");
178
179    // SUB
180    expect<int64_t>(65535, []{return I::sub(65536, 1);}, "sub");
181    expect<int64_t>(-1,
182            []{return I::sub(0x7FFFFFFFFFFFFFFFLL, 0x8000000000000000LL);},
183            "sub, \"overflow\"");
184
185    // SLL
186    expect<int64_t>(65280, []{return I::sll(255, 8);}, "sll, general");
187    expect<int64_t>(numeric_limits<int64_t>::min(),
188            []{return I::sll(255, 63);}, "sll, erase");
189
190    // SLT
191    expect<bool>(true, []{return I::slt(-1, 0);}, "slt, true");
192    expect<bool>(false, []{return I::slt(0, -1);}, "slt, false");
193
194    // SLTU
195    expect<bool>(false, []{return I::sltu(-1, 0);}, "sltu, false");
196    expect<bool>(true, []{return I::sltu(0, -1);}, "sltu, true");
197
198    // XOR
199    expect<uint64_t>(-1,
200            []{return I::xor_inst(0xAAAAAAAAAAAAAAAAULL,
201                    0x5555555555555555ULL);},
202            "xor (1)");
203    expect<uint64_t>(0,
204            []{return I::xor_inst(0xAAAAAAAAAAAAAAAAULL,
205                    0xAAAAAAAAAAAAAAAAULL);},
206            "xor (0)");
207
208    // SRL
209    expect<uint64_t>(255, []{return I::srl(65280, 8);}, "srl, general");
210    expect<uint64_t>(0, []{return I::srl(255, 8);}, "srl, erase");
211    expect<uint64_t>(1, []{return I::srl(numeric_limits<int64_t>::min(), 63);},
212            "srl, negative");
213
214    // SRA
215    expect<int64_t>(255, []{return I::sra(65280, 8);}, "sra, general");
216    expect<int64_t>(0, []{return I::sra(255, 8);}, "sra, erase");
217    expect<int64_t>(-1, []{return I::sra(numeric_limits<int64_t>::min(), 63);},
218            "sra, negative");
219
220    // OR
221    expect<uint64_t>(-1,
222            []{return I::or_inst(0xAAAAAAAAAAAAAAAAULL,
223                    0x5555555555555555ULL);},
224            "or (1)");
225    expect<uint64_t>(0xAAAAAAAAAAAAAAAAULL,
226            []{return I::or_inst(0xAAAAAAAAAAAAAAAAULL,
227                    0xAAAAAAAAAAAAAAAAULL);},
228            "or (A)");
229
230    // AND
231    expect<uint64_t>(0, []{return I::and_inst(-1, 0);}, "and (0)");
232    expect<uint64_t>(0x1234567812345678ULL,
233            []{return I::and_inst(0x1234567812345678ULL, -1);}, "and (-1)");
234
235    // FENCE/FENCE.I
236    asm volatile("fence" : : );
237    asm volatile("fence.i" : : );
238
239    // ECALL
240    char fname[] = "test.txt";
241    char teststr[] = "this is a test";
242    expect<bool>(true, [=]{
243            int fd = open(fname, O_CREAT | O_WRONLY | O_TRUNC, 0644);
244            if (fd < 0) {
245                return false;
246            }
247            size_t n = write(fd, teststr, sizeof(teststr));
248            cout << "Bytes written: " << n << endl;
249            return close(fd) >= 0 && n > 0;
250        }, "open, write");
251    expect<int>(0, [=]{return access(fname, F_OK);}, "access F_OK");
252    expect<int>(0, [=]{return access(fname, R_OK);}, "access R_OK");
253    expect<int>(0, [=]{return access(fname, W_OK);}, "access W_OK");
254    // gem5's implementation of access is incorrect; it should return
255    // -1 on failure, not -errno.  Account for this using an inequality.
256    expect<bool>(true, [=]{return access(fname, X_OK) != 0;}, "access X_OK");
257    expect<bool>(true, [=]{
258            struct stat stat_buf, fstat_buf;
259            int s = stat(fname, &stat_buf);
260            if (s < 0) {
261                return false;
262            } else {
263                cout << "stat:" << endl;
264                cout << "\tst_dev =\t" << stat_buf.st_dev << endl;
265                cout << "\tst_ino =\t" << stat_buf.st_ino << endl;
266                cout << "\tst_mode =\t" << stat_buf.st_mode << endl;
267                cout << "\tst_nlink =\t" << stat_buf.st_nlink << endl;
268                cout << "\tst_uid =\t" << stat_buf.st_uid << endl;
269                cout << "\tst_gid =\t" << stat_buf.st_gid << endl;
270                cout << "\tst_rdev =\t" << stat_buf.st_rdev << endl;
271                cout << "\tst_size =\t" << stat_buf.st_size << endl;
272                cout << "\tst_blksize =\t" << stat_buf.st_blksize << endl;
273                cout << "\tst_blocks =\t" << stat_buf.st_blocks << endl;
274            }
275            int fd = open(fname, O_RDONLY);
276            if (fd < 0) {
277                return false;
278            }
279            int f = fstat(fd, &fstat_buf);
280            if (f >= 0) {
281                cout << "fstat:" << endl;
282                cout << "\tst_dev =\t" << fstat_buf.st_dev << endl;
283                cout << "\tst_ino =\t" << fstat_buf.st_ino << endl;
284                cout << "\tst_mode =\t" << fstat_buf.st_mode << endl;
285                cout << "\tst_nlink =\t" << fstat_buf.st_nlink << endl;
286                cout << "\tst_uid =\t" << fstat_buf.st_uid << endl;
287                cout << "\tst_gid =\t" << fstat_buf.st_gid << endl;
288                cout << "\tst_rdev =\t" << fstat_buf.st_rdev << endl;
289                cout << "\tst_size =\t" << fstat_buf.st_size << endl;
290                cout << "\tst_blksize =\t" << fstat_buf.st_blksize << endl;
291                cout << "\tst_blocks =\t" << fstat_buf.st_blocks << endl;
292            }
293            return close(fd) >= 0 && f >= 0;
294        }, "open, stat");
295    expect<bool>(true, [=]{
296            int fd = open(fname, O_RDONLY);
297            if (fd < 0) {
298                return false;
299            }
300            char in[128];
301            size_t n = read(fd, in, sizeof(in));
302            cout << "Bytes read: " << n << endl;
303            cout << "String read: " << in << endl;
304            int cl = close(fd);
305            int un = unlink(fname);
306            return n > 0 && cl >= 0 && un >= 0 && strcmp(teststr, in) == 0;
307        }, "open, read, unlink");
308    expect<bool>(true, []{
309            struct tms buf;
310            clock_t t = times(&buf);
311            cout << "times:" << endl;
312            cout << "\ttms_utime =\t" << buf.tms_utime << endl;
313            cout << "\ttms_stime =\t" << buf.tms_stime << endl;
314            cout << "\ttms_cutime =\t" << buf.tms_cutime << endl;
315            cout << "\ttms_cstime =\t" << buf.tms_cstime << endl;
316            return t > 0;
317        }, "times");
318    expect<int>(0, []{
319            struct timeval time;
320            int res = gettimeofday(&time, nullptr);
321            cout << "timeval:" << endl;
322            cout << "\ttv_sec =\t" << time.tv_sec << endl;
323            cout << "\ttv_usec =\t" << time.tv_usec << endl;
324            return res;
325        }, "gettimeofday");
326
327    // EBREAK not tested because it only makes sense in FS mode or when
328    // using gdb
329
330    // ERET not tested because it only makes sense in FS mode and will cause
331    // a panic when used in SE mode
332
333    // CSRs (RDCYCLE, RDTIME, RDINSTRET)
334    expect<bool>(true, []{
335                uint64_t cycles = 0;
336                asm("rdcycle %0" : "=r" (cycles));
337                cout << "Cycles: " << cycles << endl;
338                return cycles > 0;
339            }, "rdcycle");
340    expect<bool>(true, []{
341                uint64_t time = 0;
342                asm("rdtime %0" : "=r" (time));
343                cout << "Time: " << time << endl;
344                return time > 0;
345            }, "rdtime");
346    expect<bool>(true, []{
347                uint64_t instret = 0;
348                asm("rdinstret %0" : "=r" (instret));
349                cout << "Instructions Retired: " << instret << endl;
350                return instret > 0;
351            }, "rdinstret");
352
353    // 64-bit memory (LWU, LD, SD)
354    expect<int64_t>(0xFFFFFFFF, []{return I::load<uint32_t, uint64_t>(-1);},
355            "lwu");
356    expect<int64_t>(30064771072,
357            []{return I::load<int64_t, int64_t>(30064771072);}, "ld");
358    expect<uint64_t>(-1, []{return I::store<int64_t>(-1);}, "sd");
359
360    // ADDIW
361    expect<int64_t>(268435710, []{return I::addiw(0x0FFFFFFF, 255);}, "addiw");
362    expect<int64_t>(-2147481602, []{return I::addiw(0x7FFFFFFF, 0x7FF);},
363            "addiw, overflow");
364    expect<int64_t>(0, []{return I::addiw(0x7FFFFFFFFFFFFFFFLL, 1);},
365            "addiw, truncate");
366
367    // SLLIW
368    expect<int64_t>(65280, []{return I::slliw(255, 8);}, "slliw, general");
369    expect<int64_t>(numeric_limits<int32_t>::min(),
370            []{return I::slliw(255, 31);}, "slliw, erase");
371    expect<int64_t>(numeric_limits<int32_t>::min(),
372            []{return I::slliw(0xFFFFFFFF00800000LL, 8);}, "slliw, truncate");
373
374    // SRLIW
375    expect<int64_t>(255, []{return I::srliw(65280, 8);}, "srliw, general");
376    expect<int64_t>(0, []{return I::srliw(255, 8);}, "srliw, erase");
377    expect<int64_t>(1,
378            []{return I::srliw(numeric_limits<int32_t>::min(), 31);},
379            "srliw, negative");
380    expect<int64_t>(1, []{return I::srliw(0xFFFFFFFF80000000LL, 31);},
381            "srliw, truncate");
382
383    // SRAIW
384    expect<int64_t>(255, []{return I::sraiw(65280, 8);}, "sraiw, general");
385    expect<int64_t>(0, []{return I::sraiw(255, 8);}, "sraiw, erase");
386    expect<int64_t>(-1,
387            []{return I::sraiw(numeric_limits<int32_t>::min(), 31);},
388            "sraiw, negative");
389    expect<int64_t>(-1, []{return I::sraiw(0x0000000180000000LL, 31);},
390            "sraiw, truncate");
391
392    // ADDW
393    expect<int64_t>(1073742078, []{return I::addw(0x3FFFFFFF, 255);}, "addw");
394    expect<int64_t>(-1, []{return I::addw(0x7FFFFFFF, 0x80000000);},
395            "addw, overflow");
396    expect<int64_t>(65536, []{return I::addw(0xFFFFFFFF0000FFFFLL, 1);},
397            "addw, truncate");
398
399    // SUBW
400    expect<int64_t>(65535, []{return I::subw(65536, 1);}, "subw");
401    expect<int64_t>(-1, []{return I::subw(0x7FFFFFFF, 0x80000000);},
402            "subw, \"overflow\"");
403    expect<int64_t>(0,
404            []{return I::subw(0xAAAAAAAAFFFFFFFFULL, 0x55555555FFFFFFFFULL);},
405            "subw, truncate");
406
407    // SLLW
408    expect<int64_t>(65280, []{return I::sllw(255, 8);}, "sllw, general");
409    expect<int64_t>(numeric_limits<int32_t>::min(),
410            []{return I::sllw(255, 31);}, "sllw, erase");
411    expect<int64_t>(numeric_limits<int32_t>::min(),
412            []{return I::sllw(0xFFFFFFFF00008000LL, 16);}, "sllw, truncate");
413
414    // SRLW
415    expect<uint64_t>(255, []{return I::srlw(65280, 8);}, "srlw, general");
416    expect<uint64_t>(0, []{return I::srlw(255, 8);}, "srlw, erase");
417    expect<uint64_t>(1,
418            []{return I::srlw(numeric_limits<int32_t>::min(), 31);},
419            "srlw, negative");
420    expect<uint64_t>(1, []{return I::srlw(0x0000000180000000LL, 31);},
421            "srlw, truncate");
422
423    // SRAW
424    expect<int64_t>(255, []{return I::sraw(65280, 8);}, "sraw, general");
425    expect<int64_t>(0, []{return I::sraw(255, 8);}, "sraw, erase");
426    expect<int64_t>(-1,
427            []{return I::sraw(numeric_limits<int32_t>::min(), 31);},
428            "sraw, negative");
429    expect<int64_t>(1, []{return I::sraw(0xFFFFFFFF40000000LL, 30);},
430            "sraw, truncate");
431
432    return 0;
433}
434