diff options
Diffstat (limited to 'tests/test-progs/insttest/src/riscv/rv64i.cpp')
-rw-r--r-- | tests/test-progs/insttest/src/riscv/rv64i.cpp | 432 |
1 files changed, 432 insertions, 0 deletions
diff --git a/tests/test-progs/insttest/src/riscv/rv64i.cpp b/tests/test-progs/insttest/src/riscv/rv64i.cpp new file mode 100644 index 000000000..95e8ee02a --- /dev/null +++ b/tests/test-progs/insttest/src/riscv/rv64i.cpp @@ -0,0 +1,432 @@ +/* + * Copyright (c) 2016 The University of Virginia + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Alec Roelke + */ + +#include <fcntl.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/times.h> +#include <sys/types.h> +#include <unistd.h> + +#include <cstdint> +#include <cstring> +#include <iostream> +#include <limits> + +#include "insttest.h" +#include "rv64i.h" + +int main() +{ + using namespace std; + using namespace insttest; + + // LUI + expect<int64_t>(4096, []{return I::lui(1);}, "lui"); + expect<int64_t>(numeric_limits<int32_t>::min(), + []{return I::lui(0x80000);}, "lui, negative"); + + // AUIPC + expect<bool>(true, []{return I::auipc(3);}, "auipc"); + + // Jump (JAL, JALR) + expect<bool>(true, []{return I::jal();}, "jal"); + expect<bool>(true, []{return I::jalr();}, "jalr"); + + // BEQ + expect<bool>(true, []{return I::beq(5, 5);}, "beq, equal"); + expect<bool>(false, []{return I::beq(numeric_limits<int64_t>::max(), + numeric_limits<int64_t>::min());}, "beq, not equal"); + + // BNE + expect<bool>(false, []{return I::bne(5, 5);}, "bne, equal"); + expect<bool>(true, []{return I::bne(numeric_limits<int64_t>::max(), + numeric_limits<int64_t>::min());}, "bne, not equal"); + + // BLT + expect<bool>(true, []{return I::blt(numeric_limits<int64_t>::min(), + numeric_limits<int64_t>::max());}, "blt, less"); + expect<bool>(false, []{return I::blt(numeric_limits<int64_t>::min(), + numeric_limits<int64_t>::min());}, "blt, equal"); + expect<bool>(false, []{return I::blt(numeric_limits<int64_t>::max(), + numeric_limits<int64_t>::min());}, "blt, greater"); + + // BGE + expect<bool>(false, []{return I::bge(numeric_limits<int64_t>::min(), + numeric_limits<int64_t>::max());}, "bge, less"); + expect<bool>(true, []{return I::bge(numeric_limits<int64_t>::min(), + numeric_limits<int64_t>::min());}, "bge, equal"); + expect<bool>(true, []{return I::bge(numeric_limits<int64_t>::max(), + numeric_limits<int64_t>::min());}, "bge, greater"); + + // BLTU + expect<bool>(true, []{return I::blt(numeric_limits<int64_t>::min(), + numeric_limits<int64_t>::max());}, "bltu, greater"); + expect<bool>(false, []{return I::blt(numeric_limits<int64_t>::min(), + numeric_limits<int64_t>::min());}, "bltu, equal"); + expect<bool>(false, []{return I::blt(numeric_limits<int64_t>::max(), + numeric_limits<int64_t>::min());}, "bltu, less"); + + // BGEU + expect<bool>(false, []{return I::bge(numeric_limits<int64_t>::min(), + numeric_limits<int64_t>::max());}, "bgeu, greater"); + expect<bool>(true, []{return I::bge(numeric_limits<int64_t>::min(), + numeric_limits<int64_t>::min());}, "bgeu, equal"); + expect<bool>(true, []{return I::bge(numeric_limits<int64_t>::max(), + numeric_limits<int64_t>::min());}, "bgeu, less"); + + // Load (LB, LH, LW, LBU, LHU) + expect<int64_t>(7, []{return I::load<int8_t, int64_t>(0x07);}, + "lb, positive"); + expect<int64_t>(numeric_limits<int8_t>::min(), + []{return I::load<int8_t, int64_t>(0x80);}, "lb, negative"); + expect<int64_t>(1792, []{return I::load<int16_t, int64_t>(0x0700);}, + "lh, positive"); + expect<int64_t>(numeric_limits<int16_t>::min(), + []{return I::load<int16_t, int64_t>(0x8000);}, "lh, negative"); + expect<int64_t>(458752, []{return I::load<int32_t, int64_t>(0x00070000);}, + "lw, positive"); + expect<int64_t>(numeric_limits<int32_t>::min(), + []{return I::load<int32_t, int64_t>(0x80000000);}, + "lw, negative"); + expect<uint64_t>(128, []{return I::load<uint8_t, uint64_t>(0x80);}, "lbu"); + expect<uint64_t>(32768, []{return I::load<uint16_t, uint64_t>(0x8000);}, + "lhu"); + + // Store (SB, SH, SW) + expect<uint8_t>(0xFF, []{return I::store<int8_t>(-1);}, "sb"); + expect<uint16_t>(0xFFFF, []{return I::store<int16_t>(-1);}, "sh"); + expect<uint32_t>(0xFFFFFFFF, []{return I::store<int32_t>(-1);}, "sw"); + + // ADDI + expect<int64_t>(1073742078, []{return I::addi(0x3FFFFFFF, 255);}, + "addi"); + expect<int64_t>(1, []{return I::addi(-1, 2);}, "addi, overflow"); + + // SLTI + expect<bool>(true, []{return I::slti(-1, 0);}, "slti, true"); + expect<bool>(false, []{return I::slti(0, -1);}, "slti, false"); + + // SLTIU + expect<bool>(false, []{return I::sltiu(-1, 0);}, "sltiu, false"); + expect<bool>(true, []{return I::sltiu(0, -1);}, "sltiu, true"); + + // XORI + expect<uint64_t>(0xFF, []{return I::xori(0xAA, 0x55);}, "xori (1)"); + expect<uint64_t>(0, []{return I::xori(0xAA, 0xAA);}, "xori (0)"); + + // ORI + expect<uint64_t>(0xFF, []{return I::ori(0xAA, 0x55);}, "ori (1)"); + expect<uint64_t>(0xAA, []{return I::ori(0xAA, 0xAA);}, "ori (A)"); + + // ANDI + expect<uint64_t>(0, []{return I::andi(-1, 0);}, "andi (0)"); + expect<uint64_t>(0x1234567812345678ULL, + []{return I::andi(0x1234567812345678ULL, -1);}, "andi (1)"); + + // SLLI + expect<int64_t>(65280, []{return I::slli(255, 8);}, "slli, general"); + expect<int64_t>(numeric_limits<int64_t>::min(), + []{return I::slli(255, 63);}, "slli, erase"); + + // SRLI + expect<int64_t>(255, []{return I::srli(65280, 8);}, "srli, general"); + expect<int64_t>(0, []{return I::srli(255, 8);}, "srli, erase"); + expect<int64_t>(1, []{return I::srli(numeric_limits<int64_t>::min(), 63);}, + "srli, negative"); + + // SRAI + expect<int64_t>(255, []{return I::srai(65280, 8);}, "srai, general"); + expect<int64_t>(0, []{return I::srai(255, 8);}, "srai, erase"); + expect<int64_t>(-1, + []{return I::srai(numeric_limits<int64_t>::min(), 63);}, + "srai, negative"); + + // ADD + expect<int64_t>(1073742078, []{return I::add(0x3FFFFFFF, 255);}, "add"); + expect<int64_t>(-1, + []{return I::add(0x7FFFFFFFFFFFFFFFLL, 0x8000000000000000LL);}, + "add, overflow"); + + // SUB + expect<int64_t>(65535, []{return I::sub(65536, 1);}, "sub"); + expect<int64_t>(-1, + []{return I::sub(0x7FFFFFFFFFFFFFFFLL, 0x8000000000000000LL);}, + "sub, \"overflow\""); + + // SLL + expect<int64_t>(65280, []{return I::sll(255, 8);}, "sll, general"); + expect<int64_t>(numeric_limits<int64_t>::min(), + []{return I::sll(255, 63);}, "sll, erase"); + + // SLT + expect<bool>(true, []{return I::slt(-1, 0);}, "slt, true"); + expect<bool>(false, []{return I::slt(0, -1);}, "slt, false"); + + // SLTU + expect<bool>(false, []{return I::sltu(-1, 0);}, "sltu, false"); + expect<bool>(true, []{return I::sltu(0, -1);}, "sltu, true"); + + // XOR + expect<uint64_t>(-1, + []{return I::xor_inst(0xAAAAAAAAAAAAAAAAULL, + 0x5555555555555555ULL);}, + "xor (1)"); + expect<uint64_t>(0, + []{return I::xor_inst(0xAAAAAAAAAAAAAAAAULL, + 0xAAAAAAAAAAAAAAAAULL);}, + "xor (0)"); + + // SRL + expect<uint64_t>(255, []{return I::srl(65280, 8);}, "srl, general"); + expect<uint64_t>(0, []{return I::srl(255, 8);}, "srl, erase"); + expect<uint64_t>(1, []{return I::srl(numeric_limits<int64_t>::min(), 63);}, + "srl, negative"); + + // SRA + expect<int64_t>(255, []{return I::sra(65280, 8);}, "sra, general"); + expect<int64_t>(0, []{return I::sra(255, 8);}, "sra, erase"); + expect<int64_t>(-1, []{return I::sra(numeric_limits<int64_t>::min(), 63);}, + "sra, negative"); + + // OR + expect<uint64_t>(-1, + []{return I::or_inst(0xAAAAAAAAAAAAAAAAULL, + 0x5555555555555555ULL);}, + "or (1)"); + expect<uint64_t>(0xAAAAAAAAAAAAAAAAULL, + []{return I::or_inst(0xAAAAAAAAAAAAAAAAULL, + 0xAAAAAAAAAAAAAAAAULL);}, + "or (A)"); + + // AND + expect<uint64_t>(0, []{return I::and_inst(-1, 0);}, "and (0)"); + expect<uint64_t>(0x1234567812345678ULL, + []{return I::and_inst(0x1234567812345678ULL, -1);}, "and (-1)"); + + // FENCE/FENCE.I + asm volatile("fence" : : ); + asm volatile("fence.i" : : ); + + // ECALL + char fname[] = "test.txt"; + char teststr[] = "this is a test"; + expect<bool>(true, [=]{ + int fd = open(fname, O_CREAT | O_WRONLY | O_TRUNC, 0644); + if (fd < 0) { + return false; + } + size_t n = write(fd, teststr, sizeof(teststr)); + cout << "Bytes written: " << n << endl; + return close(fd) >= 0 && n > 0; + }, "open, write"); + expect<int>(0, [=]{return access(fname, F_OK);}, "access F_OK"); + expect<int>(0, [=]{return access(fname, R_OK);}, "access R_OK"); + expect<int>(0, [=]{return access(fname, W_OK);}, "access W_OK"); + // gem5's implementation of access is incorrect; it should return + // -1 on failure, not -errno. Account for this using an inequality. + expect<bool>(true, [=]{return access(fname, X_OK) != 0;}, "access X_OK"); + expect<bool>(true, [=]{ + struct stat stat_buf, fstat_buf; + int s = stat(fname, &stat_buf); + if (s < 0) { + return false; + } else { + cout << "stat:" << endl; + cout << "\tst_dev =\t" << stat_buf.st_dev << endl; + cout << "\tst_ino =\t" << stat_buf.st_ino << endl; + cout << "\tst_mode =\t" << stat_buf.st_mode << endl; + cout << "\tst_nlink =\t" << stat_buf.st_nlink << endl; + cout << "\tst_uid =\t" << stat_buf.st_uid << endl; + cout << "\tst_gid =\t" << stat_buf.st_gid << endl; + cout << "\tst_rdev =\t" << stat_buf.st_rdev << endl; + cout << "\tst_size =\t" << stat_buf.st_size << endl; + cout << "\tst_blksize =\t" << stat_buf.st_blksize << endl; + cout << "\tst_blocks =\t" << stat_buf.st_blocks << endl; + } + int fd = open(fname, O_RDONLY); + if (fd < 0) { + return false; + } + int f = fstat(fd, &fstat_buf); + if (f >= 0) { + cout << "fstat:" << endl; + cout << "\tst_dev =\t" << fstat_buf.st_dev << endl; + cout << "\tst_ino =\t" << fstat_buf.st_ino << endl; + cout << "\tst_mode =\t" << fstat_buf.st_mode << endl; + cout << "\tst_nlink =\t" << fstat_buf.st_nlink << endl; + cout << "\tst_uid =\t" << fstat_buf.st_uid << endl; + cout << "\tst_gid =\t" << fstat_buf.st_gid << endl; + cout << "\tst_rdev =\t" << fstat_buf.st_rdev << endl; + cout << "\tst_size =\t" << fstat_buf.st_size << endl; + cout << "\tst_blksize =\t" << fstat_buf.st_blksize << endl; + cout << "\tst_blocks =\t" << fstat_buf.st_blocks << endl; + } + return close(fd) >= 0 && f >= 0; + }, "open, stat"); + expect<bool>(true, [=]{ + int fd = open(fname, O_RDONLY); + if (fd < 0) { + return false; + } + char in[128]; + size_t n = read(fd, in, sizeof(in)); + cout << "Bytes read: " << n << endl; + cout << "String read: " << in << endl; + int cl = close(fd); + int un = unlink(fname); + return n > 0 && cl >= 0 && un >= 0 && strcmp(teststr, in) == 0; + }, "open, read, unlink"); + expect<bool>(true, []{ + struct tms buf; + clock_t t = times(&buf); + cout << "times:" << endl; + cout << "\ttms_utime =\t" << buf.tms_utime << endl; + cout << "\ttms_stime =\t" << buf.tms_stime << endl; + cout << "\ttms_cutime =\t" << buf.tms_cutime << endl; + cout << "\ttms_cstime =\t" << buf.tms_cstime << endl; + return t > 0; + }, "times"); + expect<int>(0, []{ + struct timeval time; + int res = gettimeofday(&time, nullptr); + cout << "timeval:" << endl; + cout << "\ttv_sec =\t" << time.tv_sec << endl; + cout << "\ttv_usec =\t" << time.tv_usec << endl; + return res; + }, "gettimeofday"); + + // EBREAK not tested because it only makes sense in FS mode or when + // using gdb + + // ERET not tested because it only makes sense in FS mode and will cause + // a panic when used in SE mode + + // CSRs (RDCYCLE, RDTIME, RDINSTRET) + expect<bool>(true, []{ + uint64_t cycles = 0; + asm("rdcycle %0" : "=r" (cycles)); + cout << "Cycles: " << cycles << endl; + return cycles > 0; + }, "rdcycle"); + expect<bool>(true, []{ + uint64_t time = 0; + asm("rdtime %0" : "=r" (time)); + cout << "Time: " << time << endl; + return time > 0; + }, "rdtime"); + expect<bool>(true, []{ + uint64_t instret = 0; + asm("rdinstret %0" : "=r" (instret)); + cout << "Instructions Retired: " << instret << endl; + return instret > 0; + }, "rdinstret"); + + // 64-bit memory (LWU, LD, SD) + expect<int64_t>(0xFFFFFFFF, []{return I::load<uint32_t, uint64_t>(-1);}, + "lwu"); + expect<int64_t>(30064771072, + []{return I::load<int64_t, int64_t>(30064771072);}, "ld"); + expect<uint64_t>(-1, []{return I::store<int64_t>(-1);}, "sd"); + + // ADDIW + expect<int64_t>(268435710, []{return I::addiw(0x0FFFFFFF, 255);}, "addiw"); + expect<int64_t>(-2147481602, []{return I::addiw(0x7FFFFFFF, 0x7FF);}, + "addiw, overflow"); + expect<int64_t>(0, []{return I::addiw(0x7FFFFFFFFFFFFFFFLL, 1);}, + "addiw, truncate"); + + // SLLIW + expect<int64_t>(65280, []{return I::slliw(255, 8);}, "slliw, general"); + expect<int64_t>(numeric_limits<int32_t>::min(), + []{return I::slliw(255, 31);}, "slliw, erase"); + expect<int64_t>(numeric_limits<int32_t>::min(), + []{return I::slliw(0xFFFFFFFF00800000LL, 8);}, "slliw, truncate"); + + // SRLIW + expect<int64_t>(255, []{return I::srliw(65280, 8);}, "srliw, general"); + expect<int64_t>(0, []{return I::srliw(255, 8);}, "srliw, erase"); + expect<int64_t>(1, + []{return I::srliw(numeric_limits<int32_t>::min(), 31);}, + "srliw, negative"); + expect<int64_t>(1, []{return I::srliw(0xFFFFFFFF80000000LL, 31);}, + "srliw, truncate"); + + // SRAIW + expect<int64_t>(255, []{return I::sraiw(65280, 8);}, "sraiw, general"); + expect<int64_t>(0, []{return I::sraiw(255, 8);}, "sraiw, erase"); + expect<int64_t>(-1, + []{return I::sraiw(numeric_limits<int32_t>::min(), 31);}, + "sraiw, negative"); + expect<int64_t>(-1, []{return I::sraiw(0x0000000180000000LL, 31);}, + "sraiw, truncate"); + + // ADDW + expect<int64_t>(1073742078, []{return I::addw(0x3FFFFFFF, 255);}, "addw"); + expect<int64_t>(-1, []{return I::addw(0x7FFFFFFF, 0x80000000);}, + "addw, overflow"); + expect<int64_t>(65536, []{return I::addw(0xFFFFFFFF0000FFFFLL, 1);}, + "addw, truncate"); + + // SUBW + expect<int64_t>(65535, []{return I::subw(65536, 1);}, "subw"); + expect<int64_t>(-1, []{return I::subw(0x7FFFFFFF, 0x80000000);}, + "subw, \"overflow\""); + expect<int64_t>(0, + []{return I::subw(0xAAAAAAAAFFFFFFFFULL, 0x55555555FFFFFFFFULL);}, + "subw, truncate"); + + // SLLW + expect<int64_t>(65280, []{return I::sllw(255, 8);}, "sllw, general"); + expect<int64_t>(numeric_limits<int32_t>::min(), + []{return I::sllw(255, 31);}, "sllw, erase"); + expect<int64_t>(numeric_limits<int32_t>::min(), + []{return I::sllw(0xFFFFFFFF00008000LL, 16);}, "sllw, truncate"); + + // SRLW + expect<uint64_t>(255, []{return I::srlw(65280, 8);}, "srlw, general"); + expect<uint64_t>(0, []{return I::srlw(255, 8);}, "srlw, erase"); + expect<uint64_t>(1, + []{return I::srlw(numeric_limits<int32_t>::min(), 31);}, + "srlw, negative"); + expect<uint64_t>(1, []{return I::srlw(0x0000000180000000LL, 31);}, + "srlw, truncate"); + + // SRAW + expect<int64_t>(255, []{return I::sraw(65280, 8);}, "sraw, general"); + expect<int64_t>(0, []{return I::sraw(255, 8);}, "sraw, erase"); + expect<int64_t>(-1, + []{return I::sraw(numeric_limits<int32_t>::min(), 31);}, + "sraw, negative"); + expect<int64_t>(1, []{return I::sraw(0xFFFFFFFF40000000LL, 30);}, + "sraw, truncate"); + + return 0; +} |