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