277 lines
16 KiB
C++
277 lines
16 KiB
C++
#include <verilated.h>
|
|
#include "VCore.h"
|
|
#include "VCore___024root.h"
|
|
#include "memory.h"
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
|
|
#define MAX_CYCLES 300000
|
|
|
|
static void dump_rob_entry(VCore* core, unsigned idx, const char* label) {
|
|
#define ROB_ENTRY_CASE(n) \
|
|
case n: \
|
|
fprintf(stderr, \
|
|
"%s[%u]: valid=%u completed=%u exception=%u mispredict=%u " \
|
|
"arch=%u writes=%u op=%u dest=%u old=%u cause=0x%lx bad=0x%lx redirect=0x%lx\n", \
|
|
label, idx, \
|
|
(unsigned)core->rootp->Core__DOT__backend__DOT__rename__DOT__rob__DOT__valid_##n, \
|
|
(unsigned)core->rootp->Core__DOT__backend__DOT__rename__DOT__rob__DOT__completed_##n, \
|
|
(unsigned)core->rootp->Core__DOT__backend__DOT__rename__DOT__rob__DOT__exception_##n, \
|
|
(unsigned)core->rootp->Core__DOT__backend__DOT__rename__DOT__rob__DOT__branchMispredict_##n, \
|
|
(unsigned)core->rootp->Core__DOT__backend__DOT__rename__DOT__rob__DOT__entries_##n##_archDest, \
|
|
(unsigned)core->rootp->Core__DOT__backend__DOT__rename__DOT__rob__DOT__entries_##n##_writesDest, \
|
|
(unsigned)core->rootp->Core__DOT__backend__DOT__rename__DOT__rob__DOT__entries_##n##_opClass, \
|
|
(unsigned)core->rootp->Core__DOT__backend__DOT__rename__DOT__rob__DOT__entries_##n##_dest, \
|
|
(unsigned)core->rootp->Core__DOT__backend__DOT__rename__DOT__rob__DOT__entries_##n##_oldDest, \
|
|
(uint64_t)core->rootp->Core__DOT__backend__DOT__rename__DOT__rob__DOT__exceptionCause_##n, \
|
|
(uint64_t)core->rootp->Core__DOT__backend__DOT__rename__DOT__rob__DOT__badAddr_##n, \
|
|
(uint64_t)core->rootp->Core__DOT__backend__DOT__rename__DOT__rob__DOT__redirectPc_##n); \
|
|
break
|
|
|
|
switch (idx & 63U) {
|
|
ROB_ENTRY_CASE(0); ROB_ENTRY_CASE(1); ROB_ENTRY_CASE(2); ROB_ENTRY_CASE(3);
|
|
ROB_ENTRY_CASE(4); ROB_ENTRY_CASE(5); ROB_ENTRY_CASE(6); ROB_ENTRY_CASE(7);
|
|
ROB_ENTRY_CASE(8); ROB_ENTRY_CASE(9); ROB_ENTRY_CASE(10); ROB_ENTRY_CASE(11);
|
|
ROB_ENTRY_CASE(12); ROB_ENTRY_CASE(13); ROB_ENTRY_CASE(14); ROB_ENTRY_CASE(15);
|
|
ROB_ENTRY_CASE(16); ROB_ENTRY_CASE(17); ROB_ENTRY_CASE(18); ROB_ENTRY_CASE(19);
|
|
ROB_ENTRY_CASE(20); ROB_ENTRY_CASE(21); ROB_ENTRY_CASE(22); ROB_ENTRY_CASE(23);
|
|
ROB_ENTRY_CASE(24); ROB_ENTRY_CASE(25); ROB_ENTRY_CASE(26); ROB_ENTRY_CASE(27);
|
|
ROB_ENTRY_CASE(28); ROB_ENTRY_CASE(29); ROB_ENTRY_CASE(30); ROB_ENTRY_CASE(31);
|
|
ROB_ENTRY_CASE(32); ROB_ENTRY_CASE(33); ROB_ENTRY_CASE(34); ROB_ENTRY_CASE(35);
|
|
ROB_ENTRY_CASE(36); ROB_ENTRY_CASE(37); ROB_ENTRY_CASE(38); ROB_ENTRY_CASE(39);
|
|
ROB_ENTRY_CASE(40); ROB_ENTRY_CASE(41); ROB_ENTRY_CASE(42); ROB_ENTRY_CASE(43);
|
|
ROB_ENTRY_CASE(44); ROB_ENTRY_CASE(45); ROB_ENTRY_CASE(46); ROB_ENTRY_CASE(47);
|
|
ROB_ENTRY_CASE(48); ROB_ENTRY_CASE(49); ROB_ENTRY_CASE(50); ROB_ENTRY_CASE(51);
|
|
ROB_ENTRY_CASE(52); ROB_ENTRY_CASE(53); ROB_ENTRY_CASE(54); ROB_ENTRY_CASE(55);
|
|
ROB_ENTRY_CASE(56); ROB_ENTRY_CASE(57); ROB_ENTRY_CASE(58); ROB_ENTRY_CASE(59);
|
|
ROB_ENTRY_CASE(60); ROB_ENTRY_CASE(61); ROB_ENTRY_CASE(62); ROB_ENTRY_CASE(63);
|
|
}
|
|
#undef ROB_ENTRY_CASE
|
|
}
|
|
|
|
int main(int argc, char** argv) {
|
|
if (argc < 2) {
|
|
fprintf(stderr, "Usage: %s <test.elf>\n", argv[0]);
|
|
return 1;
|
|
}
|
|
|
|
Verilated::commandArgs(argc, argv);
|
|
|
|
VCore* core = new VCore;
|
|
Memory* mem = new Memory();
|
|
|
|
if (!mem->load_elf(argv[1])) {
|
|
fprintf(stderr, "Failed to load test binary\n");
|
|
return 1;
|
|
}
|
|
uint64_t tohost_addr = mem->get_tohost_addr();
|
|
|
|
// Reset
|
|
core->reset = 1;
|
|
core->clock = 0;
|
|
core->eval();
|
|
core->clock = 1;
|
|
core->eval();
|
|
core->clock = 0;
|
|
core->reset = 0;
|
|
core->eval();
|
|
|
|
uint64_t cycle = 0;
|
|
bool test_done = false;
|
|
int exit_code = 0;
|
|
int bad_access_reports = 0;
|
|
bool saw_tohost_req = false;
|
|
int flush_reports = 0;
|
|
int csr_reports = 0;
|
|
int store_reports = 0;
|
|
|
|
while (cycle < MAX_CYCLES && !test_done) {
|
|
// Handle instruction memory interface
|
|
if (core->io_imem_req_valid) {
|
|
uint64_t pc = core->io_imem_req_bits;
|
|
if ((pc < MEM_BASE || pc >= MEM_BASE + MEM_SIZE) && bad_access_reports < 32) {
|
|
fprintf(stderr, "[%lu] Bad imem fetch pc=0x%lx\n", cycle, pc);
|
|
bad_access_reports++;
|
|
}
|
|
core->io_imem_resp_valid = 1;
|
|
core->io_imem_resp_bits_0 = mem->read32(pc);
|
|
core->io_imem_resp_bits_1 = mem->read32(pc + 4);
|
|
} else {
|
|
core->io_imem_resp_valid = 0;
|
|
}
|
|
|
|
// Handle data memory interface
|
|
if (core->io_dmem_req_valid) {
|
|
uint64_t addr = core->io_dmem_req_bits_addr;
|
|
if ((addr < MEM_BASE || addr >= MEM_BASE + MEM_SIZE) && addr != tohost_addr && bad_access_reports < 32) {
|
|
fprintf(stderr,
|
|
"[%lu] Bad dmem %s addr=0x%lx data=0x%lx size=%u\n",
|
|
cycle,
|
|
core->io_dmem_req_bits_isStore ? "store" : "load",
|
|
addr,
|
|
(uint64_t)core->io_dmem_req_bits_data,
|
|
(unsigned)core->io_dmem_req_bits_size);
|
|
bad_access_reports++;
|
|
}
|
|
|
|
// Check for tohost write
|
|
if (core->io_dmem_req_bits_isStore && addr == tohost_addr) {
|
|
saw_tohost_req = true;
|
|
uint64_t tohost = core->io_dmem_req_bits_data;
|
|
if (tohost == 1) {
|
|
printf("[%lu] TEST PASSED\n", cycle);
|
|
test_done = true;
|
|
exit_code = 0;
|
|
} else if (tohost & 1) {
|
|
printf("[%lu] TEST FAILED: error code %lu\n", cycle, tohost >> 1);
|
|
test_done = true;
|
|
exit_code = 1;
|
|
}
|
|
}
|
|
|
|
if (core->io_dmem_req_bits_isStore) {
|
|
if (store_reports < 64) {
|
|
fprintf(stderr,
|
|
"[%lu] STORE addr=0x%lx data=0x%lx size=%u\n",
|
|
cycle,
|
|
addr,
|
|
(uint64_t)core->io_dmem_req_bits_data,
|
|
(unsigned)core->io_dmem_req_bits_size);
|
|
store_reports++;
|
|
}
|
|
switch (core->io_dmem_req_bits_size) {
|
|
case 0: mem->write8(addr, core->io_dmem_req_bits_data & 0xff); break;
|
|
case 1: mem->write16(addr, core->io_dmem_req_bits_data & 0xffff); break;
|
|
case 2: mem->write32(addr, core->io_dmem_req_bits_data & 0xffffffff); break;
|
|
default: mem->write64(addr, core->io_dmem_req_bits_data); break;
|
|
}
|
|
core->io_dmem_resp_valid = 0;
|
|
} else {
|
|
core->io_dmem_resp_bits = mem->read64(addr);
|
|
core->io_dmem_resp_valid = 1;
|
|
}
|
|
} else {
|
|
core->io_dmem_resp_valid = 0;
|
|
}
|
|
|
|
// Clock cycle
|
|
core->clock = 0;
|
|
core->eval();
|
|
core->clock = 1;
|
|
core->eval();
|
|
|
|
cycle++;
|
|
|
|
if ((core->rootp->Core__DOT__backend__DOT__commitCsr0 ||
|
|
(core->rootp->Core__DOT__backend__DOT___commit_io_commitReady_1 &&
|
|
core->rootp->Core__DOT__backend__DOT___rename_io_commitEntry_1_csrValid)) &&
|
|
csr_reports < 64) {
|
|
fprintf(stderr,
|
|
"[%lu] CSR commit slot0=%u slot1=%u addr=0x%x cmd=%u next=0x%lx mtvec=0x%lx\n",
|
|
cycle,
|
|
(unsigned)core->rootp->Core__DOT__backend__DOT__commitCsr0,
|
|
(unsigned)(core->rootp->Core__DOT__backend__DOT___commit_io_commitReady_1 &&
|
|
core->rootp->Core__DOT__backend__DOT___rename_io_commitEntry_1_csrValid),
|
|
(unsigned)core->rootp->Core__DOT__backend__DOT____Vcellinp__csr__io_cmd_addr,
|
|
(unsigned)core->rootp->Core__DOT__backend__DOT____Vcellinp__csr__io_cmd_cmd,
|
|
(uint64_t)core->rootp->Core__DOT__backend__DOT__csr__DOT__unnamedblk1__DOT__next,
|
|
(uint64_t)core->rootp->Core__DOT__backend__DOT__csr__DOT__mtvecReg);
|
|
csr_reports++;
|
|
}
|
|
if (core->rootp->Core__DOT___backend_io_flush && flush_reports < 64) {
|
|
fprintf(stderr,
|
|
"[%lu] FLUSH exception=%u mtvec=0x%lx mepc=0x%lx mcause=0x%lx frontend_pc=0x%lx\n",
|
|
cycle,
|
|
(unsigned)core->rootp->Core__DOT__backend__DOT___commit_io_exception,
|
|
(uint64_t)core->rootp->Core__DOT__backend__DOT__csr__DOT__mtvecReg,
|
|
(uint64_t)core->rootp->Core__DOT__backend__DOT__csr__DOT__mepcReg,
|
|
(uint64_t)core->rootp->Core__DOT__backend__DOT__csr__DOT__mcause,
|
|
(uint64_t)core->rootp->Core__DOT__frontend__DOT__pc);
|
|
flush_reports++;
|
|
}
|
|
}
|
|
|
|
if (!test_done) {
|
|
printf("[%lu] TEST TIMEOUT\n", cycle);
|
|
fprintf(stderr,
|
|
"Timeout state: frontend_pc=0x%lx ic_state=%u ic_lookup=0x%lx ic_miss=0x%lx "
|
|
"fetchValid=%u fetchReady=%u feOut=%u issueInReady0=%u robCount=%u "
|
|
"rsFree=0x%x freeMask=0x%lx "
|
|
"issueReady=%u/%u issue0_pc=0x%lx issue1_pc=0x%lx "
|
|
"robHead=%u robTail=%u mtvec=0x%lx mepc=0x%lx mcause=0x%lx "
|
|
"flush=%u commitReady=%u/%u commitValid1=%u sawTohost=%u\n",
|
|
core->rootp->Core__DOT__frontend__DOT__pc,
|
|
(unsigned)core->rootp->Core__DOT__frontend__DOT__icache__DOT__state,
|
|
core->rootp->Core__DOT__frontend__DOT__icache__DOT__lookupAddr,
|
|
core->rootp->Core__DOT__frontend__DOT__icache__DOT__missAddr,
|
|
(unsigned)core->rootp->Core__DOT__fetchValid,
|
|
(unsigned)core->rootp->Core__DOT__fetchReady,
|
|
(unsigned)core->rootp->Core__DOT___frontend_io_outValid,
|
|
(unsigned)core->rootp->Core__DOT__backend__DOT___issue_io_inReady_0,
|
|
(unsigned)core->rootp->Core__DOT__backend__DOT__rename__DOT__rob__DOT__count,
|
|
(unsigned)core->rootp->Core__DOT__backend__DOT__issue__DOT__queue__DOT__intRs__DOT__freeMask,
|
|
(uint64_t)core->rootp->Core__DOT__backend__DOT__rename__DOT__freeList__DOT__freeMask,
|
|
(unsigned)core->rootp->Core__DOT__backend__DOT__issue_io_outReady_0,
|
|
(unsigned)core->rootp->Core__DOT__backend__DOT__issue_io_outReady_1,
|
|
core->rootp->Core__DOT__backend__DOT___issue_io_out_0_decoded_pc,
|
|
core->rootp->Core__DOT__backend__DOT___issue_io_out_1_decoded_pc,
|
|
(unsigned)core->rootp->Core__DOT__backend__DOT__rename__DOT__rob__DOT__head,
|
|
(unsigned)core->rootp->Core__DOT__backend__DOT__rename__DOT__rob__DOT__tail,
|
|
core->rootp->Core__DOT__backend__DOT__csr__DOT__mtvecReg,
|
|
core->rootp->Core__DOT__backend__DOT__csr__DOT__mepcReg,
|
|
core->rootp->Core__DOT__backend__DOT__csr__DOT__mcause,
|
|
(unsigned)core->rootp->Core__DOT___backend_io_flush,
|
|
(unsigned)core->rootp->Core__DOT__backend__DOT___commit_io_commitReady_0,
|
|
(unsigned)core->rootp->Core__DOT__backend__DOT___commit_io_commitReady_1,
|
|
(unsigned)core->rootp->Core__DOT__backend__DOT___rename_io_commitValid_1,
|
|
saw_tohost_req ? 1u : 0u);
|
|
unsigned head = (unsigned)core->rootp->Core__DOT__backend__DOT__rename__DOT__rob__DOT__head;
|
|
dump_rob_entry(core, head, "robHead");
|
|
dump_rob_entry(core, head + 1U, "robNext");
|
|
fprintf(stderr,
|
|
"rs0: valid=%u ready=%u pc=0x%lx inst=0x%08x rob=%u prs=%u/%u readySrc=%u/%u prd=%u\n",
|
|
(unsigned)core->rootp->Core__DOT__backend__DOT__issue__DOT__queue__DOT__intRs__DOT__valid_0,
|
|
(unsigned)core->rootp->Core__DOT__backend__DOT__issue__DOT__queue__DOT__intRs__DOT__readyVec_0,
|
|
(uint64_t)core->rootp->Core__DOT__backend__DOT__issue__DOT__queue__DOT__intRs__DOT__slots_0_decoded_pc,
|
|
(unsigned)core->rootp->Core__DOT__backend__DOT__issue__DOT__queue__DOT__intRs__DOT__slots_0_decoded_inst,
|
|
(unsigned)core->rootp->Core__DOT__backend__DOT__issue__DOT__queue__DOT__intRs__DOT__slots_0_robIdx,
|
|
(unsigned)core->rootp->Core__DOT__backend__DOT__issue__DOT__queue__DOT__intRs__DOT__slots_0_prs1,
|
|
(unsigned)core->rootp->Core__DOT__backend__DOT__issue__DOT__queue__DOT__intRs__DOT__slots_0_prs2,
|
|
(unsigned)core->rootp->Core__DOT__backend__DOT__issue__DOT__queue__DOT__intRs__DOT__slots_0_src1Ready,
|
|
(unsigned)core->rootp->Core__DOT__backend__DOT__issue__DOT__queue__DOT__intRs__DOT__slots_0_src2Ready,
|
|
(unsigned)core->rootp->Core__DOT__backend__DOT__issue__DOT__queue__DOT__intRs__DOT__slots_0_prd);
|
|
fprintf(stderr,
|
|
"rs1: valid=%u ready=%u pc=0x%lx inst=0x%08x rob=%u prs=%u/%u readySrc=%u/%u prd=%u issueOH=0x%x/0x%x\n",
|
|
(unsigned)core->rootp->Core__DOT__backend__DOT__issue__DOT__queue__DOT__intRs__DOT__valid_1,
|
|
(unsigned)core->rootp->Core__DOT__backend__DOT__issue__DOT__queue__DOT__intRs__DOT__readyVec_1,
|
|
(uint64_t)core->rootp->Core__DOT__backend__DOT__issue__DOT__queue__DOT__intRs__DOT__slots_1_decoded_pc,
|
|
(unsigned)core->rootp->Core__DOT__backend__DOT__issue__DOT__queue__DOT__intRs__DOT__slots_1_decoded_inst,
|
|
(unsigned)core->rootp->Core__DOT__backend__DOT__issue__DOT__queue__DOT__intRs__DOT__slots_1_robIdx,
|
|
(unsigned)core->rootp->Core__DOT__backend__DOT__issue__DOT__queue__DOT__intRs__DOT__slots_1_prs1,
|
|
(unsigned)core->rootp->Core__DOT__backend__DOT__issue__DOT__queue__DOT__intRs__DOT__slots_1_prs2,
|
|
(unsigned)core->rootp->Core__DOT__backend__DOT__issue__DOT__queue__DOT__intRs__DOT__slots_1_src1Ready,
|
|
(unsigned)core->rootp->Core__DOT__backend__DOT__issue__DOT__queue__DOT__intRs__DOT__slots_1_src2Ready,
|
|
(unsigned)core->rootp->Core__DOT__backend__DOT__issue__DOT__queue__DOT__intRs__DOT__slots_1_prd,
|
|
(unsigned)core->rootp->Core__DOT__backend__DOT__issue__DOT__queue__DOT__intRs__DOT__issue0OH,
|
|
(unsigned)core->rootp->Core__DOT__backend__DOT__issue__DOT__queue__DOT__intRs__DOT__issue1OH);
|
|
fprintf(stderr,
|
|
"complete: valid=%u/%u idx0=%u exc=%u/%u mis=%u/%u cause=0x%lx/0x%lx redirect=0x%lx/0x%lx\n",
|
|
(unsigned)core->rootp->Core__DOT__backend__DOT____Vcellinp__rename__io_completeValid_0,
|
|
(unsigned)core->rootp->Core__DOT__backend__DOT____Vcellinp__rename__io_completeValid_1,
|
|
(unsigned)core->rootp->Core__DOT__backend__DOT____Vcellinp__rename__io_completeIdx_0,
|
|
(unsigned)core->rootp->Core__DOT__backend__DOT____Vcellinp__rename__io_completeException_0,
|
|
(unsigned)core->rootp->Core__DOT__backend__DOT____Vcellinp__rename__io_completeException_1,
|
|
(unsigned)core->rootp->Core__DOT__backend__DOT____Vcellinp__rename__io_completeMispredict_0,
|
|
(unsigned)core->rootp->Core__DOT__backend__DOT____Vcellinp__rename__io_completeMispredict_1,
|
|
(uint64_t)core->rootp->Core__DOT__backend__DOT____Vcellinp__rename__io_completeCause_0,
|
|
(uint64_t)core->rootp->Core__DOT__backend__DOT____Vcellinp__rename__io_completeCause_1,
|
|
(uint64_t)core->rootp->Core__DOT__backend__DOT____Vcellinp__rename__io_completeRedirectPc_0,
|
|
(uint64_t)core->rootp->Core__DOT__backend__DOT____Vcellinp__rename__io_completeRedirectPc_1);
|
|
exit_code = 2;
|
|
}
|
|
|
|
delete core;
|
|
delete mem;
|
|
return exit_code;
|
|
}
|