/* * 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 #include #include #include #include #include #include #include #include #include #include "insttest.h" #include "rv64i.h" int main() { using namespace std; using namespace insttest; // LUI expect(4096, []{return I::lui(1);}, "lui"); expect(numeric_limits::min(), []{return I::lui(0x80000);}, "lui, negative"); // AUIPC expect(true, []{return I::auipc(3);}, "auipc"); // Jump (JAL, JALR) expect(true, []{return I::jal();}, "jal"); expect(true, []{return I::jalr();}, "jalr"); // BEQ expect(true, []{return I::beq(5, 5);}, "beq, equal"); expect(false, []{return I::beq(numeric_limits::max(), numeric_limits::min());}, "beq, not equal"); // BNE expect(false, []{return I::bne(5, 5);}, "bne, equal"); expect(true, []{return I::bne(numeric_limits::max(), numeric_limits::min());}, "bne, not equal"); // BLT expect(true, []{return I::blt(numeric_limits::min(), numeric_limits::max());}, "blt, less"); expect(false, []{return I::blt(numeric_limits::min(), numeric_limits::min());}, "blt, equal"); expect(false, []{return I::blt(numeric_limits::max(), numeric_limits::min());}, "blt, greater"); // BGE expect(false, []{return I::bge(numeric_limits::min(), numeric_limits::max());}, "bge, less"); expect(true, []{return I::bge(numeric_limits::min(), numeric_limits::min());}, "bge, equal"); expect(true, []{return I::bge(numeric_limits::max(), numeric_limits::min());}, "bge, greater"); // BLTU expect(true, []{return I::blt(numeric_limits::min(), numeric_limits::max());}, "bltu, greater"); expect(false, []{return I::blt(numeric_limits::min(), numeric_limits::min());}, "bltu, equal"); expect(false, []{return I::blt(numeric_limits::max(), numeric_limits::min());}, "bltu, less"); // BGEU expect(false, []{return I::bge(numeric_limits::min(), numeric_limits::max());}, "bgeu, greater"); expect(true, []{return I::bge(numeric_limits::min(), numeric_limits::min());}, "bgeu, equal"); expect(true, []{return I::bge(numeric_limits::max(), numeric_limits::min());}, "bgeu, less"); // Load (LB, LH, LW, LBU, LHU) expect(7, []{return I::load(0x07);}, "lb, positive"); expect(numeric_limits::min(), []{return I::load(0x80);}, "lb, negative"); expect(1792, []{return I::load(0x0700);}, "lh, positive"); expect(numeric_limits::min(), []{return I::load(0x8000);}, "lh, negative"); expect(458752, []{return I::load(0x00070000);}, "lw, positive"); expect(numeric_limits::min(), []{return I::load(0x80000000);}, "lw, negative"); expect(128, []{return I::load(0x80);}, "lbu"); expect(32768, []{return I::load(0x8000);}, "lhu"); // Store (SB, SH, SW) expect(0xFF, []{return I::store(-1);}, "sb"); expect(0xFFFF, []{return I::store(-1);}, "sh"); expect(0xFFFFFFFF, []{return I::store(-1);}, "sw"); // ADDI expect(1073742078, []{return I::addi(0x3FFFFFFF, 255);}, "addi"); expect(1, []{return I::addi(-1, 2);}, "addi, overflow"); // SLTI expect(true, []{return I::slti(-1, 0);}, "slti, true"); expect(false, []{return I::slti(0, -1);}, "slti, false"); // SLTIU expect(false, []{return I::sltiu(-1, 0);}, "sltiu, false"); expect(true, []{return I::sltiu(0, -1);}, "sltiu, true"); // XORI expect(0xFF, []{return I::xori(0xAA, 0x55);}, "xori (1)"); expect(0, []{return I::xori(0xAA, 0xAA);}, "xori (0)"); // ORI expect(0xFF, []{return I::ori(0xAA, 0x55);}, "ori (1)"); expect(0xAA, []{return I::ori(0xAA, 0xAA);}, "ori (A)"); // ANDI expect(0, []{return I::andi(-1, 0);}, "andi (0)"); expect(0x1234567812345678ULL, []{return I::andi(0x1234567812345678ULL, -1);}, "andi (1)"); // SLLI expect(65280, []{return I::slli(255, 8);}, "slli, general"); expect(numeric_limits::min(), []{return I::slli(255, 63);}, "slli, erase"); // SRLI expect(255, []{return I::srli(65280, 8);}, "srli, general"); expect(0, []{return I::srli(255, 8);}, "srli, erase"); expect(1, []{return I::srli(numeric_limits::min(), 63);}, "srli, negative"); // SRAI expect(255, []{return I::srai(65280, 8);}, "srai, general"); expect(0, []{return I::srai(255, 8);}, "srai, erase"); expect(-1, []{return I::srai(numeric_limits::min(), 63);}, "srai, negative"); // ADD expect(1073742078, []{return I::add(0x3FFFFFFF, 255);}, "add"); expect(-1, []{return I::add(0x7FFFFFFFFFFFFFFFLL, 0x8000000000000000LL);}, "add, overflow"); // SUB expect(65535, []{return I::sub(65536, 1);}, "sub"); expect(-1, []{return I::sub(0x7FFFFFFFFFFFFFFFLL, 0x8000000000000000LL);}, "sub, \"overflow\""); // SLL expect(65280, []{return I::sll(255, 8);}, "sll, general"); expect(numeric_limits::min(), []{return I::sll(255, 63);}, "sll, erase"); // SLT expect(true, []{return I::slt(-1, 0);}, "slt, true"); expect(false, []{return I::slt(0, -1);}, "slt, false"); // SLTU expect(false, []{return I::sltu(-1, 0);}, "sltu, false"); expect(true, []{return I::sltu(0, -1);}, "sltu, true"); // XOR expect(-1, []{return I::xor_inst(0xAAAAAAAAAAAAAAAAULL, 0x5555555555555555ULL);}, "xor (1)"); expect(0, []{return I::xor_inst(0xAAAAAAAAAAAAAAAAULL, 0xAAAAAAAAAAAAAAAAULL);}, "xor (0)"); // SRL expect(255, []{return I::srl(65280, 8);}, "srl, general"); expect(0, []{return I::srl(255, 8);}, "srl, erase"); expect(1, []{return I::srl(numeric_limits::min(), 63);}, "srl, negative"); // SRA expect(255, []{return I::sra(65280, 8);}, "sra, general"); expect(0, []{return I::sra(255, 8);}, "sra, erase"); expect(-1, []{return I::sra(numeric_limits::min(), 63);}, "sra, negative"); // OR expect(-1, []{return I::or_inst(0xAAAAAAAAAAAAAAAAULL, 0x5555555555555555ULL);}, "or (1)"); expect(0xAAAAAAAAAAAAAAAAULL, []{return I::or_inst(0xAAAAAAAAAAAAAAAAULL, 0xAAAAAAAAAAAAAAAAULL);}, "or (A)"); // AND expect(0, []{return I::and_inst(-1, 0);}, "and (0)"); expect(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(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(0, [=]{return access(fname, F_OK);}, "access F_OK"); expect(0, [=]{return access(fname, R_OK);}, "access R_OK"); expect(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(true, [=]{return access(fname, X_OK) != 0;}, "access X_OK"); expect(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(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(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(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(true, []{ uint64_t cycles = 0; asm("rdcycle %0" : "=r" (cycles)); cout << "Cycles: " << cycles << endl; return cycles > 0; }, "rdcycle"); expect(true, []{ uint64_t time = 0; asm("rdtime %0" : "=r" (time)); cout << "Time: " << time << endl; return time > 0; }, "rdtime"); expect(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(0xFFFFFFFF, []{return I::load(-1);}, "lwu"); expect(30064771072, []{return I::load(30064771072);}, "ld"); expect(-1, []{return I::store(-1);}, "sd"); // ADDIW expect(268435710, []{return I::addiw(0x0FFFFFFF, 255);}, "addiw"); expect(-2147481602, []{return I::addiw(0x7FFFFFFF, 0x7FF);}, "addiw, overflow"); expect(0, []{return I::addiw(0x7FFFFFFFFFFFFFFFLL, 1);}, "addiw, truncate"); // SLLIW expect(65280, []{return I::slliw(255, 8);}, "slliw, general"); expect(numeric_limits::min(), []{return I::slliw(255, 31);}, "slliw, erase"); expect(numeric_limits::min(), []{return I::slliw(0xFFFFFFFF00800000LL, 8);}, "slliw, truncate"); // SRLIW expect(255, []{return I::srliw(65280, 8);}, "srliw, general"); expect(0, []{return I::srliw(255, 8);}, "srliw, erase"); expect(1, []{return I::srliw(numeric_limits::min(), 31);}, "srliw, negative"); expect(1, []{return I::srliw(0xFFFFFFFF80000000LL, 31);}, "srliw, truncate"); // SRAIW expect(255, []{return I::sraiw(65280, 8);}, "sraiw, general"); expect(0, []{return I::sraiw(255, 8);}, "sraiw, erase"); expect(-1, []{return I::sraiw(numeric_limits::min(), 31);}, "sraiw, negative"); expect(-1, []{return I::sraiw(0x0000000180000000LL, 31);}, "sraiw, truncate"); // ADDW expect(1073742078, []{return I::addw(0x3FFFFFFF, 255);}, "addw"); expect(-1, []{return I::addw(0x7FFFFFFF, 0x80000000);}, "addw, overflow"); expect(65536, []{return I::addw(0xFFFFFFFF0000FFFFLL, 1);}, "addw, truncate"); // SUBW expect(65535, []{return I::subw(65536, 1);}, "subw"); expect(-1, []{return I::subw(0x7FFFFFFF, 0x80000000);}, "subw, \"overflow\""); expect(0, []{return I::subw(0xAAAAAAAAFFFFFFFFULL, 0x55555555FFFFFFFFULL);}, "subw, truncate"); // SLLW expect(65280, []{return I::sllw(255, 8);}, "sllw, general"); expect(numeric_limits::min(), []{return I::sllw(255, 31);}, "sllw, erase"); expect(numeric_limits::min(), []{return I::sllw(0xFFFFFFFF00008000LL, 16);}, "sllw, truncate"); // SRLW expect(255, []{return I::srlw(65280, 8);}, "srlw, general"); expect(0, []{return I::srlw(255, 8);}, "srlw, erase"); expect(1, []{return I::srlw(numeric_limits::min(), 31);}, "srlw, negative"); expect(1, []{return I::srlw(0x0000000180000000LL, 31);}, "srlw, truncate"); // SRAW expect(255, []{return I::sraw(65280, 8);}, "sraw, general"); expect(0, []{return I::sraw(255, 8);}, "sraw, erase"); expect(-1, []{return I::sraw(numeric_limits::min(), 31);}, "sraw, negative"); expect(1, []{return I::sraw(0xFFFFFFFF40000000LL, 30);}, "sraw, truncate"); return 0; }