Verilator test bench refactor

This commit is contained in:
Eric Matthews 2019-09-10 15:42:53 -07:00
parent 8cfcca5080
commit 2713b8675a
7 changed files with 315 additions and 186 deletions

View file

@ -209,20 +209,20 @@ module taiga (
//Trace Interface
generate if (ENABLE_TRACE_INTERFACE) begin
always_ff @(posedge clk) begin
tr.operand_stall <= tr_operand_stall;
tr.unit_stall <= tr_unit_stall;
tr.no_id_stall <= tr_no_id_stall;
tr.no_instruction_stall <= tr_no_instruction_stall;
tr.other_stall <= tr_other_stall;
tr.instruction_issued_dec <= tr_instruction_issued_dec;
tr.events.operand_stall <= tr_operand_stall;
tr.events.unit_stall <= tr_unit_stall;
tr.events.no_id_stall <= tr_no_id_stall;
tr.events.no_instruction_stall <= tr_no_instruction_stall;
tr.events.other_stall <= tr_other_stall;
tr.events.instruction_issued_dec <= tr_instruction_issued_dec;
tr.events.branch_misspredict <= tr_branch_misspredict;
tr.events.return_misspredict <= tr_return_misspredict;
tr.events.wb_mux_contention <= tr_wb_mux_contention;
tr.events.rs1_forwarding_needed <= tr_rs1_forwarding_needed;
tr.events.rs2_forwarding_needed <= tr_rs2_forwarding_needed;
tr.events.rs1_and_rs2_forwarding_needed <= tr_rs1_and_rs2_forwarding_needed;
tr.instruction_pc_dec <= tr_instruction_pc_dec;
tr.instruction_data_dec <= tr_instruction_data_dec;
tr.branch_misspredict <= tr_branch_misspredict;
tr.return_misspredict <= tr_return_misspredict;
tr.wb_mux_contention <= tr_wb_mux_contention;
tr.rs1_forwarding_needed <= tr_rs1_forwarding_needed;
tr.rs2_forwarding_needed <= tr_rs2_forwarding_needed;
tr.rs1_and_rs2_forwarding_needed <= tr_rs1_and_rs2_forwarding_needed;
end
end
endgenerate

View file

@ -449,15 +449,7 @@ package taiga_types;
logic no_id_stall;
logic no_instruction_stall;
logic other_stall;
logic instruction_issued_dec;
logic [31:0] instruction_pc_dec;
logic [31:0] instruction_data_dec;
//Register File
logic rs1_forwarding_needed;
logic rs2_forwarding_needed;
logic rs1_and_rs2_forwarding_needed;
//Branch Unit
logic branch_misspredict;
@ -465,6 +457,17 @@ package taiga_types;
//Writeback
logic wb_mux_contention;
//Register File
logic rs1_forwarding_needed;
logic rs2_forwarding_needed;
logic rs1_and_rs2_forwarding_needed;
} taiga_trace_events_t;
typedef struct packed {
logic [31:0] instruction_pc_dec;
logic [31:0] instruction_data_dec;
taiga_trace_events_t events;
} trace_outputs_t;
//Assembly register definitions for simulation purposes

View file

@ -0,0 +1,153 @@
/*
* Copyright © 2019 Eric Matthews, Lesley Shannon
*
* 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.
*
* Initial code developed under the supervision of Dr. Lesley Shannon,
* Reconfigurable Computing Lab, Simon Fraser University.
*
* Author(s):
* Eric Matthews <ematthew@sfu.ca>
*/
#include <iostream>
#include "TaigaTracer.h"
template <class TB>
bool TaigaTracer<TB>::check_instruction_issued(uint32_t inst) {
return (tb->instruction_data_dec == inst && tb->instruction_issued);
}
template <class TB>
bool TaigaTracer<TB>::has_terminated() {
if (check_instruction_issued(ERROR_TERMINATION_NOP)) {
std::cout << "\n\nError!!!!\n\n";
return true;
}//Custom nop for regular termination
else if (check_instruction_issued(SUCCESS_TERMINATION_NOP)) {
return true;
}
return false;
}
template <class TB>
bool TaigaTracer<TB>::has_stalled() {
if (!tb->instruction_issued) {
stall_count++;
if (stall_count > stall_limit) {
stall_count = 0;
std::cout << "\n\nError!!!!\n";
std::cout << "Stall of " << stall_limit << " cycles detected!\n\n";
return true;
} else {
stall_count = 0;
}
}
return false;
}
template <class TB>
void TaigaTracer<TB>::reset_stats() {
event_counters = { 0 };
}
template <class TB>
void TaigaTracer<TB>::update_stats() {
for (int i=0; i < numEvents; i++)
event_counters[i] += tb->taiga_events[i];
}
template <class TB>
void TaigaTracer<TB>::print_stats() {
std::cout << " Taiga trace stats:\n";
std::cout << "--------------------------------------------------------------\n";
for (int i=0; i < numEvents; i++)
std::cout << " " << eventNames[i] << ": " << event_counters[i] << std::endl;
std::cout << "--------------------------------------------------------------\n\n";
}
template <class TB>
void TaigaTracer<TB>::reset() {
tb->rst = 1;
for (int i=0; i <reset_length; i++)
tick();
tb->rst = 0;
}
template <class TB>
void TaigaTracer<TB>::set_log_file(std::ofstream* logFile) {
this->logFile = logFile;
}
template <class TB>
void TaigaTracer<TB>::update_UART() {
if (tb->write_uart) {
std::cout << tb->uart_byte;
*logFile << tb->uart_byte;
}
}
template <class TB>
void TaigaTracer<TB>::tick() {
tb->clk = 1;
tb->eval();
tb->clk = 0;
tb->eval();
cycle_count++;
update_stats();
#ifdef TRACE_ON
verilatorWaveformTracer->dump(vluint32_t(cycle_cout));
#endif
}
template <class TB>
void TaigaTracer<TB>::start_tracer(const char *trace_file) {
#ifdef TRACE_ON
verilatorWaveformTracer = new VerilatedVcdC;
tb->trace(verilatorWaveformTracer, 99);
verilatorWaveformTracer->open(trace_file);
#endif
}
template <class TB>
uint64_t TaigaTracer<TB>::get_cycle_count() {
return cycle_count;
}
template <class TB>
TaigaTracer<TB>::TaigaTracer() {
#ifdef TRACE_ON
Verilated::traceEverOn(true);
#endif
tb = new TB;
tb->clk = 0;
tb->eval();
reset();
}
template <class TB>
TaigaTracer<TB>::~TaigaTracer() {
#ifdef TRACE_ON
verilatorWaveformTracer->flush();
verilatorWaveformTracer->close();
#endif
delete tb;
}

View file

@ -0,0 +1,85 @@
/*
* Copyright © 2019 Eric Matthews, Lesley Shannon
*
* 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.
*
* Initial code developed under the supervision of Dr. Lesley Shannon,
* Reconfigurable Computing Lab, Simon Fraser University.
*
* Author(s):
* Eric Matthews <ematthew@sfu.ca>
*/
#ifndef TaigaTracer_H
#define TaigaTracer_H
#include <stdlib.h>
#include <iostream>
#include <iterator>
#define COMPLIANCE_SIG_PHASE_NOP 0x00B00013U
#define ERROR_TERMINATION_NOP 0x00F00013U
#define SUCCESS_TERMINATION_NOP 0x00A00013U
template <typename T, int N>
constexpr int arraySize(T(&)[N]) { return N; }
static const char * const eventNames[] = {
"operand_stall",
"unit_stall",
"no_id_stall",
"no_instruction_stall",
"other_stall",
"instruction_issued_dec",
"branch_misspredict",
"return_misspredict",
"wb_mux_contention",
"rs1_forwarding_needed",
"rs2_forwarding_needed",
"rs1_and_rs2_forwarding_needed"
};
static const int numEvents = arraySize(eventNames);
//Testbench with Taiga trace outputs on toplevel
template <class TB>
class TaigaTracer {
public:
TaigaTracer();
~TaigaTracer();
bool check_instruction_issued(uint32_t inst);
bool has_terminated();
bool has_stalled();
void print_stats();
void update_stats();
void update_UART();
void reset_stats();
void reset();
void tick();
void set_log_file(std::ofstream* logFile);
void start_tracer(const char *trace_file);
uint64_t get_cycle_count();
private:
TB *tb;
#ifdef TRACE_ON
VerilatedVcdC *verilatorWaveformTracer;
#endif
std::ofstream* logFile;
int reset_length = 64;
int stall_limit = 2000;
int stall_count = 0;
uint64_t cycle_count = 0;
uint64_t event_counters[numEvents];
};
#include "TaigaTracer.cc"
#endif

View file

@ -4,174 +4,74 @@
#include "Vtaiga_local_mem.h"
#include "verilated.h"
#include "verilated_vcd_c.h"
//#define TRACE_ON
////////////////////////////////////////////////////
//Trace Interface Counters
uint64_t operand_stall = 0;
uint64_t unit_stall = 0;
uint64_t no_id_stall = 0;
uint64_t no_instruction_stall = 0;
uint64_t other_stall = 0;
uint64_t instruction_issued_dec = 0;
uint64_t branch_misspredict = 0;
uint64_t return_misspredict = 0;
uint64_t wb_mux_contention = 0;
uint64_t rs1_forwarding_needed = 0;
uint64_t rs2_forwarding_needed = 0;
uint64_t rs1_and_rs2_forwarding_needed = 0;
#include "TaigaTracer.h"
using namespace std;
int main(int argc, char **argv) {
ofstream logFile, sigFile;
bool logPhase; //Log phase vs signature phase used for compliance tests
bool stallDetected = false;
int stall_cycles = 0;
TaigaTracer<Vtaiga_local_mem> *taigaTracer;
ofstream logFile, sigFile;
// Initialize Verilators variables
Verilated::commandArgs(argc, argv);
#ifdef TRACE_ON
Verilated::traceEverOn(true);
#endif
if (!argv[1]) {
cout << "Missing log file name.\n";
exit(EXIT_FAILURE);
}
if (!argv[2]) {
cout << "Missing signature file name.\n";
exit(EXIT_FAILURE);
}
if (!argv[3]) {
cout << "Missing trace log file name.\n";
exit(EXIT_FAILURE);
}
logFile.open (argv[1]);
sigFile.open (argv[2]);
if (!logFile.is_open()) {
cout << "Failed to open logfile: " << argv[1] << endl;
exit(EXIT_FAILURE);
}
if (!sigFile.is_open()) {
cout << "Failed to open sigFile: " << argv[2] << endl;
exit(EXIT_FAILURE);
}
// Create an instance of our module under test
Vtaiga_local_mem *tb = new Vtaiga_local_mem;
#ifdef TRACE_ON
VerilatedVcdC *tracer;
tracer = new VerilatedVcdC;
tb->trace(tracer, 99);
tracer->open("/data/sim-logs/sim_results.vcd");
taigaTracer = new TaigaTracer<Vtaiga_local_mem>;
taigaTracer->set_log_file(&logFile);
#ifdef TRACE_ON
taigaTracer->start_tracer(argv[3]);
#endif
cout << "--------------------------------------------------------------\n";
cout << " Starting Simulation, logging to: " << argv[1] << "\n";
cout << "--------------------------------------------------------------\n";
int reset_count = 0;
uint64_t cycle_cout = 0;
tb->rst = 1;
logPhase = true;
// Tick the clock until we are done
while(!Verilated::gotFinish()) {
if (reset_count > 64) {
tb->rst = 0;
}
else {
reset_count++;
}
while(!(taigaTracer->has_stalled() || taigaTracer->has_terminated())) {
taigaTracer->tick();
tb->clk = 1;
tb->eval();
tb->clk = 0;
tb->eval();
if (reset_count > 64) {
operand_stall += tb->operand_stall;
unit_stall += tb->unit_stall;
no_id_stall += tb->no_id_stall;
no_instruction_stall += tb->no_instruction_stall;
other_stall += tb->other_stall;
instruction_issued_dec += tb->instruction_issued_dec;
branch_misspredict += tb->branch_misspredict;
return_misspredict += tb->return_misspredict;
wb_mux_contention += tb->wb_mux_contention;
rs1_forwarding_needed += tb->rs1_forwarding_needed;
rs2_forwarding_needed += tb->rs2_forwarding_needed;
rs1_and_rs2_forwarding_needed += tb->rs1_and_rs2_forwarding_needed;
//Compliance Tests Signature Printing Phase
if (taigaTracer->check_instruction_issued(COMPLIANCE_SIG_PHASE_NOP)) {
std::cout << "\n--------------------------------------------------------------\n";
std::cout << " Signature\n";
std::cout << "--------------------------------------------------------------\n";
taigaTracer->set_log_file(&sigFile);
}
//Custom nop to change to signature phase for compliance tests
if (tb->instruction_data_dec == 0x00B00013U && tb->instruction_issued_dec) {
logPhase = false;
cout << "\n--------------------------------------------------------------\n";
cout << " Signature\n";
cout << "--------------------------------------------------------------\n";
}
//if (!logPhase) {
// std::cout << std::hex << tb-> dec_pc_debug_r << std::endl;
//}
if (tb->write_uart) {
if (logPhase) {
cout << tb->uart_byte;
logFile << tb->uart_byte;
} else {
cout << tb->uart_byte;
sigFile << tb->uart_byte;
}
}
//Custom nop for error termination
if (tb->instruction_data_dec == 0x00F00013U && tb->instruction_issued_dec) {
cout << "\n\nError!!!!\n\n";
break;
}//Custom nop for regular termination
else if (tb->instruction_data_dec == 0x00A00013U && tb->instruction_issued_dec) {
break;
}
#ifdef TRACE_ON
tracer->dump(vluint32_t(cycle_cout));
#endif
cycle_cout++;
if (!tb->instruction_issued_dec) {
stall_cycles++;
if (stall_cycles > 2000) {
stall_cycles = 0;
cout << "\n\nError!!!!\n";
cout << "PC unchanged for at least 2000 cycles!\n\n";
break;
}
} else {
stall_cycles = 0;
}
}
#ifdef TRACE_ON
tracer->flush();
tracer->close();
#endif
cout << "--------------------------------------------------------------\n";
cout << " Simulation Completed: " << cycle_cout << " cycles.\n";
cout << " Taiga trace stats:\n";
cout << "--------------------------------------------------------------\n";
cout << " operand_stall: " << operand_stall << "\n";
cout << " unit_stall: " << unit_stall << "\n";
cout << " no_id_stall: " << no_id_stall << "\n";
cout << " no_instruction_stall: " << no_instruction_stall << "\n";
cout << " other_stall: " << other_stall << "\n";
cout << " instruction_issued_dec: " << instruction_issued_dec << "\n";
cout << " branch_misspredict: " << branch_misspredict << "\n";
cout << " return_misspredict: " << return_misspredict << "\n";
cout << " wb_mux_contention: " << wb_mux_contention << "\n";
cout << " rs1_forwarding_needed: " << rs1_forwarding_needed << "\n";
cout << " rs2_forwarding_needed: " << rs2_forwarding_needed << "\n";
cout << " rs1_OR_rs2_forwarding_needed: " << rs1_forwarding_needed + rs2_forwarding_needed << "\n";
cout << " rs1_AND_rs2_forwarding_needed: " << rs1_and_rs2_forwarding_needed << "\n";
cout << "--------------------------------------------------------------\n\n";
cout << " Simulation Completed: " << taigaTracer->get_cycle_count() << " cycles.\n";
taigaTracer->print_stats();
logFile.close();
sigFile.close();
delete tb;
exit(EXIT_SUCCESS);
delete taigaTracer;
exit(EXIT_SUCCESS);
}

View file

@ -77,25 +77,13 @@ module taiga_local_mem # (
//Used by verilator
output logic write_uart,
output logic [7:0] uart_byte,
//Trace Interface
output logic operand_stall,
output logic unit_stall,
output logic no_id_stall,
output logic no_instruction_stall,
output logic other_stall,
output logic instruction_issued_dec,
//Trace Interface
output logic instruction_issued,
output logic taiga_events [$bits(taiga_trace_events_t)-1:0],
output logic [31:0] instruction_pc_dec,
output logic [31:0] instruction_data_dec,
output logic branch_misspredict,
output logic return_misspredict,
output logic wb_mux_contention,
output logic rs1_forwarding_needed,
output logic rs2_forwarding_needed,
output logic rs1_and_rs2_forwarding_needed,
//L2
//l2 request
output logic [29:0] addr,
@ -340,18 +328,14 @@ module taiga_local_mem # (
////////////////////////////////////////////////////
//Trace Interface
assign operand_stall = tr.operand_stall;
assign unit_stall = tr.unit_stall;
assign no_id_stall = tr.no_id_stall;
assign no_instruction_stall = tr.no_instruction_stall;
assign other_stall = tr.other_stall;
assign instruction_issued_dec = tr.instruction_issued_dec;
assign instruction_pc_dec = tr.instruction_pc_dec;
assign instruction_data_dec = tr.instruction_data_dec;
assign branch_misspredict = tr.branch_misspredict;
assign return_misspredict = tr.return_misspredict;
assign wb_mux_contention = tr.wb_mux_contention;
assign rs1_forwarding_needed = tr.rs1_forwarding_needed;
assign rs2_forwarding_needed = tr.rs2_forwarding_needed;
assign rs1_and_rs2_forwarding_needed = tr.rs1_and_rs2_forwarding_needed;
assign instruction_issued = tr.events.instruction_issued_dec;
logic [$bits(taiga_trace_events_t)-1:0] taiga_events_packed;
assign taiga_events_packed = tr.events;
always_comb begin
foreach (taiga_events_packed[i])
taiga_events[i] = taiga_events_packed[i];
end
endmodule

View file

@ -15,7 +15,9 @@ VERILATOR_DIR=$(TAIGA_DIR)/test_benches/verilator
TAIGA_SRCS = $(shell cat taiga_compile_order)
VERILATOR_LINT_IGNORE= -Wno-LITENDIAN -Wno-SYMRSVDWORD
VERILATOR_CFLAGS = -CFLAGS "-g0 -Os -march=native -pipe -flto -Wl,-flto" -LDFLAGS "-flto"
VERILATOR_CFLAGS = -CFLAGS "-g0 -Os -march=native -pipe"
VERILATOR_TRACE_FILE="/data/sim-logs/sim_results.vcd"
AR="gcc-ar"
RANLIB="gcc-ranlib"
@ -67,13 +69,15 @@ ELF_TO_HW_INIT ?= python3 $(TAIGA_DIR)/tools/taiga_binary_converter.py $(RISCV_P
define verilator_local_mem_test
mkdir -p $1
cp $(VERILATOR_DIR)/TaigaTracer.h $1/
cp $(VERILATOR_DIR)/TaigaTracer.cc $1/
cp $(VERILATOR_DIR)/taiga_local_mem.cc $1/
verilator -cc --exe --Mdir $1 $(VERILATOR_LINT_IGNORE) $(VERILATOR_CFLAGS) $(TAIGA_SRCS) \
verilator --cc --exe --Mdir $1 $(VERILATOR_LINT_IGNORE) $(VERILATOR_CFLAGS) $(TAIGA_SRCS) \
../test_benches/verilator/taiga_local_mem.sv --top-module taiga_local_mem taiga_local_mem.cc \
-GMEMORY_FILE=$2
$(MAKE) -C $1 -f Vtaiga_local_mem.mk AR="gcc-ar" RANLIB="gcc-ranlib"
echo $1 > $@
./$1/Vtaiga_local_mem $3 $4 >> $@
./$1/Vtaiga_local_mem $3 $4 $(VERILATOR_TRACE_FILE) >> $@
endef
.PHONY: lint