blob: a6b57cb1783af2de81783d6a8e35d3d44cad4864 [file] [log] [blame]
/*
* fwrisc_instr_tests.cpp
*
*
* Copyright 2018 Matthew Ballance
*
* Licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in
* writing, software distributed under the License is
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See
* the License for the specific language governing
* permissions and limitations under the License.
*
* Created on: Oct 28, 2018
* Author: ballance
*/
#include "fwrisc_instr_tests.h"
#include "BfmType.h"
#include "ElfDataReader.h"
fwrisc_instr_tests::fwrisc_instr_tests(uint32_t max_instr) : m_max_instr(max_instr) {
m_halt_addr = 0x80000004;
m_max_instr = 1000000000;
test = this;
}
fwrisc_instr_tests::~fwrisc_instr_tests() {
// TODO Auto-generated destructor stub
test = 0;
}
fwrisc_instr_tests *fwrisc_instr_tests::test = 0;
void fwrisc_instr_tests::SetUp() {
// GoogletestHdl::SetUp();
test = this;
m_icount = 0;
m_end_of_test = false;
for (uint32_t i=0; i<64; i++) {
m_regs[i] = std::pair<uint32_t, bool>(0, false);
}
for (uint32_t i=0; i<1024; i++) {
m_mem[i] = std::pair<uint32_t, bool>(0, false);
}
// Register ourselves as a listener on this BFM
fwrisc_tracer_bfm_t::bfm("*.u_tracer.u_core")->set_rsp_if(this);
GoogletestHdl::raiseObjection();
}
void fwrisc_instr_tests::TearDown() {
test = 0;
}
void fwrisc_instr_tests::regwrite(uint32_t raddr, uint32_t rdata) {
/*
fprintf(stdout, "--> regwrite 0x%02x <= 0x%08x\n", raddr, rdata);
fflush(stdout);
*/
if (raddr < 64) {
m_regs[raddr].first = rdata;
m_regs[raddr].second = true;
} else {
fprintf(stdout, "Error: raddr 0x%08x outside 0..63 range\n", raddr);
}
/*
fprintf(stdout, "<-- regwrite 0x%02x <= 0x%08x\n", raddr, rdata);
fflush(stdout);
*/
}
void fwrisc_instr_tests::memwrite(uint32_t addr, uint8_t mask, uint32_t data) {
/*
fprintf(stdout, "memwrite 0x%08x=0x%08x mask=%02x\n", addr, data, mask);
fflush(stdout);
*/
if ((addr & 0xFFFF8000) == 0x80000000) {
uint32_t offset = ((addr & 0x0000FFFF) >> 2);
// fprintf(stdout, "offset=%d\n", offset);
m_mem[offset].second = true; // accessed
if (mask & 1) {
m_mem[offset].first &= ~0x000000FF;
m_mem[offset].first |= (data & 0x000000FF);
}
if (mask & 2) {
m_mem[offset].first &= ~0x0000FF00;
m_mem[offset].first |= (data & 0x0000FF00);
}
if (mask & 4) {
m_mem[offset].first &= ~0x00FF0000;
m_mem[offset].first |= (data & 0x00FF0000);
}
if (mask & 8) {
m_mem[offset].first &= ~0xFF000000;
m_mem[offset].first |= (data & 0xFF000000);
}
fprintf(stdout, " mem=0x%08x\n", m_mem[offset].first);
} else {
fprintf(stdout, "Error: illegal access to address 0x%08x\n", addr);
ASSERT_EQ((addr & 0xFFFFF000), 0x00000000);
}
}
void fwrisc_instr_tests::exec(uint32_t addr, uint32_t instr) {
fprintf(stdout, "exec: 0x%08x - 0x%08x\n", addr, instr);
/*
fprintf(stdout, "EXEC: 0x%08x - 0x%08x\n", addr, instr);
fflush(stdout);
*/
if (m_halt_addr != 0 && addr == m_halt_addr) {
fprintf(stdout, "hit halt address 0x%08x\n", m_halt_addr);
m_end_of_test = true;
fprintf(stdout, "--> dropObjection\n");
fflush(stdout);
GoogletestHdl::dropObjection();
fprintf(stdout, "<-- dropObjection\n");
fflush(stdout);
}
if (++m_icount > m_max_instr) {
fprintf(stdout, "test timeout\n");
GoogletestHdl::dropObjection();
}
}
void fwrisc_instr_tests::run() {
GoogletestHdl::run();
}
void fwrisc_instr_tests::runtest(
const std::string &program,
reg_val_s *regs,
uint32_t n_regs) {
runtest(regs, n_regs);
}
void fwrisc_instr_tests::runtest(
reg_val_s *regs,
uint32_t n_regs) {
fprintf(stdout, "--> runtest (DEPRECATED)\n");
fflush(stdout);
GoogletestHdl::run();
check(regs, n_regs);
fprintf(stdout, "<-- runtest\n");
fflush(stdout);
}
void fwrisc_instr_tests::check(reg_val_s *regs, uint32_t n_regs) {
bool accessed[64];
ASSERT_EQ(m_end_of_test, true); // Ensure we actually reached the end of the test
memset(accessed, 0, sizeof(accessed));
// First, display all registers that were written
fprintf(stdout, "Written Registers:\n");
for (uint32_t i=1; i<sizeof(m_regs)/sizeof(reg_val_s); i++) {
if (m_regs[i].second) {
fprintf(stdout, "R[%d] = 0x%08x\n", i, m_regs[i].first);
fflush(stdout);
}
}
fprintf(stdout, "Expected Registers:\n");
for (uint32_t i=0; i<n_regs; i++) {
fprintf(stdout, "Expect R[%d] = 0x%08x\n", regs[i].addr, regs[i].val);
fflush(stdout);
}
// Perform the affirmative test
for (uint32_t i=0; i<n_regs; i++) {
if (!m_regs[regs[i].addr].second) {
fprintf(stdout, "Error: reg %d was not written\n", regs[i].addr);
fflush(stdout);
}
ASSERT_EQ(m_regs[regs[i].addr].second, true); // Ensure we wrote the register
if (m_regs[regs[i].addr].first != regs[i].val) {
fprintf(stdout, "Error: reg %d regs.value='h%08x expected='h%08hx\n",
regs[i].addr, m_regs[regs[i].addr].first, regs[i].val);
fflush(stdout);
}
ASSERT_EQ(m_regs[regs[i].addr].first, regs[i].val);
accessed[regs[i].addr] = true;
}
for (uint32_t i=0; i<63; i++) { // r63 is the CSR temp register
if (i == 54 || i == 55 || i == 0 || i >= 60) { // ignore the counter registers
continue;
}
if (m_regs[i].second != accessed[i]) {
fprintf(stdout, "Error: reg %d: regs.accessed=%s accessed=%s\n",
i, (m_regs[i].second)?"true":"false",
(accessed[i])?"true":"false");
}
ASSERT_EQ(m_regs[i].second, accessed[i]);
}
}
TEST_F(fwrisc_instr_tests,runtest) {
ElfSymtabReader symtab;
GoogletestHdl::run();
const CmdlineProcessor &clp = GoogletestHdl::clp();
std::string sw_image;
ASSERT_TRUE(clp.get_plusarg_value("+SW_IMAGE", sw_image));
symtab.read(sw_image);
Elf32_Sym start_expected = symtab.find_sym("start_expected");
Elf32_Sym end_expected = symtab.find_sym("end_expected");
ASSERT_TRUE(start_expected.st_value >= 0x80000000);
ASSERT_TRUE(end_expected.st_value >= 0x80000000);
uint32_t n_regs = (end_expected.st_value-start_expected.st_value)/(sizeof(uint32_t)*2);
reg_val_s *regs = new reg_val_s[n_regs];
ElfDataReader reader;
ASSERT_TRUE(reader.read(sw_image,
start_expected.st_value,
n_regs*(sizeof(reg_val_s)),
regs));
check(regs, n_regs);
}