From 33683bd087c2009db588844e8fa89b454a5c3d77 Mon Sep 17 00:00:00 2001 From: Alec Roelke Date: Wed, 30 Nov 2016 17:12:56 -0500 Subject: riscv: [Patch 8/5] Added some regression tests to RISC-V This patch is the eighth patch in a series adding RISC-V to gem5, and third of the bonus patches to the original series of five. It adds some regression tests to RISC-V. Regression tests included: - se/00.hello - se/02.insttest (split into several binaries which are not included due to large size) The tests added to 00.insttest will need to be build manually; to facilitate this, a Makefile is included. The required toolchain and compiler (riscv64-unknown-elf-gcc) can be built from the riscv-tools GitHub repository at https://github.com/riscv/riscv-tools. Note that because EBREAK only makes sense when gdb is running or while in FS mode, it is not included in the linux-rv64i insttest. ERET is not included because it does not make sense in SE mode and, in fact, causes a panic by design. Note also that not every system call is tested in linux-rv64i; of the ones defined in linux/process.hh, some have been given numbers but not definitions for the toolchain, or are merely stubs that always return 0. Of the ones that do work properly, only a subset are tested due to similar functionality. Signed-off by: Alec Roelke Signed-off by: Jason Lowe-Power --- tests/test-progs/insttest/src/riscv/rv64i.cpp | 432 ++++++++++++++++++++++++++ 1 file changed, 432 insertions(+) create mode 100644 tests/test-progs/insttest/src/riscv/rv64i.cpp (limited to 'tests/test-progs/insttest/src/riscv/rv64i.cpp') 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 +#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; +} -- cgit v1.2.3