🎨 Flatten tb submodule

This commit is contained in:
Florian Zaruba 2018-08-01 01:39:01 +02:00
parent 319ed5632e
commit 622a09779a
20 changed files with 1833 additions and 48 deletions

3
.gitmodules vendored
View file

@ -1,9 +1,6 @@
[submodule "riscv-torture"]
path = riscv-torture
url = https://github.com/pulp-platform/riscv-torture.git
[submodule "tb"]
path = tb
url = https://github.com/pulp-platform/uvm-components.git
[submodule "src/axi_mem_if"]
path = src/axi_mem_if
url = https://github.com/pulp-platform/axi_mem_if.git

View file

@ -17,20 +17,10 @@ questa_version ?=
verilator ?= verilator
# Sources
# Ariane PKG
ariane_pkg := include/riscv_pkg.sv src/debug/dm_pkg.sv include/ariane_pkg.sv include/nbdcache_pkg.sv
ariane_pkg := include/riscv_pkg.sv src/debug/dm_pkg.sv include/ariane_pkg.sv include/nbdcache_pkg.sv include/axi_if.sv
# utility modules
util := $(wildcard src/util/*.svh) src/util/instruction_tracer_pkg.sv src/util/instruction_tracer_if.sv \
src/util/generic_fifo.sv src/util/cluster_clock_gating.sv src/util/behav_sram.sv
# test targets
tests := alu scoreboard fifo dcache_arbiter store_queue lsu core fetch_fifo
# UVM agents
agents := $(wildcard tb/agents/*/*.sv*)
# path to interfaces
interfaces := $(wildcard include/*.svh)
# UVM environments
envs := $(wildcard tb/env/*/*.sv*)
# UVM Sequences
sequences := $(wildcard tb/sequences/*/*.sv*)
# Test packages
test_pkg := $(wildcard tb/test/*/*sequence_pkg.sv*) $(wildcard tb/test/*/*_pkg.sv*)
# DPI
@ -43,7 +33,7 @@ src := $(wildcard src/*.sv) $(wildcard tb/common/*.sv) $(wildcard tb/common/*.v)
$(filter-out src/debug/dm_pkg.sv, $(wildcard src/debug/*.sv)) $(wildcard bootrom/*.sv) \
$(wildcard src/debug/debug_rom/*.sv)
# look for testbenches
tbs := tb/alu_tb.sv tb/ariane_tb.sv tb/ariane_testharness.sv tb/dcache_arbiter_tb.sv tb/store_queue_tb.sv tb/scoreboard_tb.sv tb/fifo_tb.sv
tbs := tb/ariane_tb.sv tb/ariane_testharness.sv
# RISCV-tests path
riscv-test-dir := tmp/riscv-tests/build/isa
@ -63,16 +53,15 @@ uvm-flags += +UVM_NO_RELNOTES
list_incdir := $(foreach dir, ${incdir}, +incdir+$(dir))
# Build the TB and module using QuestaSim
build: $(library) $(library)/.build-agents $(library)/.build-interfaces $(library)/.build-components \
$(library)/.build-srcs $(library)/.build-tb $(library)/ariane_dpi.so
build: $(library) $(library)/.build-srcs $(library)/.build-tb $(library)/ariane_dpi.so
# Optimize top level
vopt$(questa_version) $(compile_flag) -work $(library) $(test_top_level) -o $(test_top_level)_optimized +acc -check_synthesis
# src files
$(library)/.build-srcs: $(util) $(src)
$(library)/.build-srcs: $(ariane_pkg) $(util) $(src)
vlog$(questa_version) $(compile_flag) -work $(library) $(filter %.sv,$(ariane_pkg)) $(list_incdir) -suppress 2583
vlog$(questa_version) $(compile_flag) -work $(library) $(filter %.sv,$(util)) $(list_incdir) -suppress 2583
# Suppress message that always_latch may not be checked thoroughly by QuestaSim.
# Compile agents, interfaces and environments
vlog$(questa_version) $(compile_flag) -work $(library) -pedanticerrors $(src) $(list_incdir) -suppress 2583
touch $(library)/.build-srcs
@ -90,22 +79,6 @@ $(library)/ariane_dpi.so: $(dpi)
# Compile C-code and generate .so file
g++ -shared -m64 -o $(library)/ariane_dpi.so $? -lfesvr
# Compile Sequences and Tests
$(library)/.build-components: $(envs) $(sequences) $(test_pkg)
vlog$(questa_version) $(compile_flag) -work $(library) $(filter %.sv,$(envs)) $(filter %.sv,$(sequences)) \
$(filter %.sv,$(test_pkg)) ${list_incdir} -suppress 2583
touch $(library)/.build-components
# Compile Agents
$(library)/.build-agents: $(agents) $(ariane_pkg)
vlog$(questa_version) $(compile_flag) -work $(library) $(ariane_pkg) $(filter %.sv,$(agents)) $(list_incdir) -suppress 2583
touch $(library)/.build-agents
# Compile Interfaces
$(library)/.build-interfaces: $(interfaces)
vlog$(questa_version) $(compile_flag) -work $(library) $(interfaces) $(list_incdir) -suppress 2583
touch $(library)/.build-interfaces
$(library):
# Create the library
vlib${questa_version} ${library}
@ -127,17 +100,6 @@ run-asm-tests: build
-do "coverage save -onexit $@.ucdb; run -a; quit -code [coverage attribute -name TESTSTATUS -concise]" \
$(library).$(test_top_level)_optimized +permissive-off ++$(test);)
# Run the specified test case
$(tests): build
# Optimize top level
vopt${questa_version} -work ${library} ${compile_flag} $@_tb -o $@_tb_optimized +acc -check_synthesis
# vsim${questa_version} $@_tb_optimized
# vsim${questa_version} +UVM_TESTNAME=$@_test -coverage -classdebug $@_tb_optimized
vsim${questa_version} -64 +UVM_TESTNAME=$@_test +ASMTEST=$(riscv-test-dir)/$(riscv-test) \
+uvm_set_action="*,_ALL_,UVM_ERROR,UVM_DISPLAY|UVM_STOP" -c -coverage -classdebug -sv_lib $(library)/ariane_dpi \
-do "coverage save -onexit $@.ucdb; run -a; quit -code [coverage attribute -name TESTSTATUS -concise]" \
${library}.$@_tb_optimized
# User Verilator, at some point in the future this will be auto-generated
verilate:
$(verilator) \
@ -155,7 +117,6 @@ verilate:
src/util/cluster_clock_gating.sv \
src/util/behav_sram.sv \
src/axi_mem_if/src/axi2mem.sv \
tb/agents/axi_if/axi_if.sv \
+incdir+src/axi_node \
--unroll-count 256 \
-Werror-PINMISSING \

128
include/axi_if.sv Normal file
View file

@ -0,0 +1,128 @@
// Copyright 2015 - 2018 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this 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.
//
////////////////////////////////////////////////////////////////////////////////
// Only general functions and definitions are defined here //
// These functions are not intended to be modified //
////////////////////////////////////////////////////////////////////////////////
interface AXI_BUS
#(
parameter AXI_ADDR_WIDTH = 64,
parameter AXI_DATA_WIDTH = 64,
parameter AXI_ID_WIDTH = 10,
parameter AXI_USER_WIDTH = 6
);
localparam AXI_STRB_WIDTH = AXI_DATA_WIDTH/8;
logic [AXI_ADDR_WIDTH-1:0] aw_addr;
logic [2:0] aw_prot;
logic [3:0] aw_region;
logic [7:0] aw_len;
logic [2:0] aw_size;
logic [1:0] aw_burst;
logic aw_lock;
logic [3:0] aw_cache;
logic [3:0] aw_qos;
logic [AXI_ID_WIDTH-1:0] aw_id;
logic [AXI_USER_WIDTH-1:0] aw_user;
logic aw_ready;
logic aw_valid;
logic [AXI_ADDR_WIDTH-1:0] ar_addr;
logic [2:0] ar_prot;
logic [3:0] ar_region;
logic [7:0] ar_len;
logic [2:0] ar_size;
logic [1:0] ar_burst;
logic ar_lock;
logic [3:0] ar_cache;
logic [3:0] ar_qos;
logic [AXI_ID_WIDTH-1:0] ar_id;
logic [AXI_USER_WIDTH-1:0] ar_user;
logic ar_ready;
logic ar_valid;
logic w_valid;
logic [AXI_DATA_WIDTH-1:0] w_data;
logic [AXI_STRB_WIDTH-1:0] w_strb;
logic [AXI_USER_WIDTH-1:0] w_user;
logic w_last;
logic w_ready;
logic [AXI_DATA_WIDTH-1:0] r_data;
logic [1:0] r_resp;
logic r_last;
logic [AXI_ID_WIDTH-1:0] r_id;
logic [AXI_USER_WIDTH-1:0] r_user;
logic r_ready;
logic r_valid;
logic [1:0] b_resp;
logic [AXI_ID_WIDTH-1:0] b_id;
logic [AXI_USER_WIDTH-1:0] b_user;
logic b_ready;
logic b_valid;
// Master Side
//***************************************
modport Master
(
output aw_valid, output aw_addr, output aw_prot, output aw_region,
output aw_len, output aw_size, output aw_burst, output aw_lock,
output aw_cache, output aw_qos, output aw_id, output aw_user,
input aw_ready,
output ar_valid, output ar_addr, output ar_prot, output ar_region,
output ar_len, output ar_size, output ar_burst, output ar_lock,
output ar_cache, output ar_qos, output ar_id, output ar_user,
input ar_ready,
output w_valid, output w_data, output w_strb, output w_user, output w_last,
input w_ready,
input r_valid, input r_data, input r_resp, input r_last, input r_id, input r_user,
output r_ready,
input b_valid, input b_resp, input b_id, input b_user,
output b_ready
);
// Slave Side
//***************************************
modport Slave
(
input aw_valid, input aw_addr, input aw_prot, input aw_region,
input aw_len, input aw_size, input aw_burst, input aw_lock,
input aw_cache, input aw_qos, input aw_id, input aw_user,
output aw_ready,
input ar_valid, input ar_addr, input ar_prot, input ar_region,
input ar_len, input ar_size, input ar_burst, input ar_lock,
input ar_cache, input ar_qos, input ar_id, input ar_user,
output ar_ready,
input w_valid, input w_data, input w_strb, input w_user, input w_last,
output w_ready,
output r_valid, output r_data, output r_resp, output r_last, output r_id, output r_user,
input r_ready,
output b_valid, output b_resp, output b_id, output b_user,
input b_ready
);
endinterface

1
tb

@ -1 +0,0 @@
Subproject commit 61b5a5eeeb79cd21382f1ab7fb856134ce63cf4f

329
tb/ariane_tb.cpp Normal file
View file

@ -0,0 +1,329 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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.
#include "Variane_testharness.h"
#include "verilator.h"
#include "verilated.h"
#include "verilated_vcd_c.h"
#include "Variane_testharness__Dpi.h"
#include <stdio.h>
#include <iostream>
#include <iomanip>
#include <string>
#include <getopt.h>
#include <chrono>
#include <ctime>
#include <fesvr/dtm.h>
#include "remote_bitbang.h"
// This software is heavily based on Rocket Chip
// Checkout this awesome project:
// https://github.com/freechipsproject/rocket-chip/
// This is a 64-bit integer to reduce wrap over issues and
// allow modulus. You can also use a double, if you wish.
static vluint64_t main_time = 0;
static const char *verilog_plusargs[] = {"jtag_rbb_enable"};
extern dtm_t* dtm;
extern remote_bitbang_t * jtag;
void handle_sigterm(int sig) {
dtm->stop();
}
// Called by $time in Verilog converts to double, to match what SystemC does
double sc_time_stamp () {
return main_time;
}
static void usage(const char * program_name) {
printf("Usage: %s [EMULATOR OPTION]... [VERILOG PLUSARG]... [HOST OPTION]... BINARY [TARGET OPTION]...\n",
program_name);
fputs("\
Run a BINARY on the Ariane emulator.\n\
\n\
Mandatory arguments to long options are mandatory for short options too.\n\
\n\
EMULATOR OPTIONS\n\
-r, --rbb-port=PORT Use PORT for remote bit bang (with OpenOCD and GDB) \n\
If not specified, a random port will be chosen\n\
automatically.\n\
", stdout);
#if VM_TRACE == 0
fputs("\
\n\
EMULATOR DEBUG OPTIONS (only supported in debug build -- try `make debug`)\n",
stdout);
#endif
fputs("\
-v, --vcd=FILE, Write vcd trace to FILE (or '-' for stdout)\n\
-p, Print performance statistic at end of test\n\
", stdout);
// fputs("\n" PLUSARG_USAGE_OPTIONS, stdout);
fputs("\n" HTIF_USAGE_OPTIONS, stdout);
printf("\n"
"EXAMPLES\n"
" - run a bare metal test:\n"
" %s $RISCV/riscv64-unknown-elf/share/riscv-tests/isa/rv64ui-p-add\n"
" - run a bare metal test showing cycle-by-cycle information:\n"
" %s spike-dasm < trace_core_00_0.dasm > trace.out\n"
#if VM_TRACE
" - run a bare metal test to generate a VCD waveform:\n"
" %s -v rv64ui-p-add.vcd $RISCV/riscv64-unknown-elf/share/riscv-tests/isa/rv64ui-p-add\n"
#endif
" - run an ELF (you wrote, called 'hello') using the proxy kernel:\n"
" %s pk hello\n",
program_name, program_name, program_name
#if VM_TRACE
, program_name
#endif
);
}
int main(int argc, char **argv) {
std::clock_t c_start = std::clock();
auto t_start = std::chrono::high_resolution_clock::now();
bool verbose;
bool perf;
unsigned random_seed = (unsigned)time(NULL) ^ (unsigned)getpid();
uint64_t max_cycles = -1;
int ret = 0;
bool print_cycles = false;
// Port numbers are 16 bit unsigned integers.
uint16_t rbb_port = 0;
#if VM_TRACE
FILE * vcdfile = NULL;
uint64_t start = 0;
#endif
char ** htif_argv = NULL;
int verilog_plusargs_legal = 1;
while (1) {
static struct option long_options[] = {
{"cycle-count", no_argument, 0, 'c' },
{"help", no_argument, 0, 'h' },
{"max-cycles", required_argument, 0, 'm' },
{"seed", required_argument, 0, 's' },
{"rbb-port", required_argument, 0, 'r' },
{"verbose", no_argument, 0, 'V' },
#if VM_TRACE
{"vcd", required_argument, 0, 'v' },
{"dump-start", required_argument, 0, 'x' },
#endif
HTIF_LONG_OPTIONS
};
int option_index = 0;
#if VM_TRACE
int c = getopt_long(argc, argv, "-chpm:s:r:v:Vx:", long_options, &option_index);
#else
int c = getopt_long(argc, argv, "-chpm:s:r:V", long_options, &option_index);
#endif
if (c == -1) break;
retry:
switch (c) {
// Process long and short EMULATOR options
case '?': usage(argv[0]); return 1;
case 'c': print_cycles = true; break;
case 'h': usage(argv[0]); return 0;
case 'm': max_cycles = atoll(optarg); break;
case 's': random_seed = atoi(optarg); break;
case 'r': rbb_port = atoi(optarg); break;
case 'V': verbose = true; break;
case 'p': perf = true; break;
#if VM_TRACE
case 'v': {
vcdfile = strcmp(optarg, "-") == 0 ? stdout : fopen(optarg, "w");
if (!vcdfile) {
std::cerr << "Unable to open " << optarg << " for VCD write\n";
return 1;
}
break;
}
case 'x': start = atoll(optarg); break;
#endif
// Process legacy '+' EMULATOR arguments by replacing them with
// their getopt equivalents
case 1: {
std::string arg = optarg;
if (arg.substr(0, 1) != "+") {
optind--;
goto done_processing;
}
if (arg == "+verbose")
c = 'V';
else if (arg.substr(0, 12) == "+max-cycles=") {
c = 'm';
optarg = optarg+12;
}
#if VM_TRACE
else if (arg.substr(0, 12) == "+dump-start=") {
c = 'x';
optarg = optarg+12;
}
#endif
else if (arg.substr(0, 12) == "+cycle-count")
c = 'c';
// If we don't find a legacy '+' EMULATOR argument, it still could be
// a VERILOG_PLUSARG and not an error.
else if (verilog_plusargs_legal) {
const char ** plusarg = &verilog_plusargs[0];
int legal_verilog_plusarg = 0;
while (*plusarg && (legal_verilog_plusarg == 0)){
if (arg.substr(1, strlen(*plusarg)) == *plusarg) {
legal_verilog_plusarg = 1;
}
plusarg ++;
}
if (!legal_verilog_plusarg) {
verilog_plusargs_legal = 0;
} else {
c = 'P';
}
goto retry;
}
// If we STILL don't find a legacy '+' argument, it still could be
// an HTIF (HOST) argument and not an error. If this is the case, then
// we're done processing EMULATOR and VERILOG arguments.
else {
static struct option htif_long_options [] = { HTIF_LONG_OPTIONS };
struct option * htif_option = &htif_long_options[0];
while (htif_option->name) {
if (arg.substr(1, strlen(htif_option->name)) == htif_option->name) {
optind--;
goto done_processing;
}
htif_option++;
}
std::cerr << argv[0] << ": invalid plus-arg (Verilog or HTIF) \""
<< arg << "\"\n";
c = '?';
}
goto retry;
}
case 'P': break; // Nothing to do here, Verilog PlusArg
// Realize that we've hit HTIF (HOST) arguments or error out
default:
if (c >= HTIF_LONG_OPTIONS_OPTIND) {
optind--;
goto done_processing;
}
c = '?';
goto retry;
}
}
done_processing:
if (optind == argc) {
std::cerr << "No binary specified for emulator\n";
usage(argv[0]);
return 1;
}
int htif_argc = 1 + argc - optind;
htif_argv = (char **) malloc((htif_argc) * sizeof (char *));
htif_argv[0] = argv[0];
for (int i = 1; optind < argc;) htif_argv[i++] = argv[optind++];
const char *vcd_file = NULL;
Verilated::commandArgs(argc, argv);
jtag = new remote_bitbang_t(rbb_port);
dtm = new dtm_t(htif_argc, htif_argv);
signal(SIGTERM, handle_sigterm);
std::unique_ptr<Variane_testharness> top(new Variane_testharness);
#if VM_TRACE
Verilated::traceEverOn(true); // Verilator must compute traced signals
std::unique_ptr<VerilatedVcdFILE> vcdfd(new VerilatedVcdFILE(vcdfile));
std::unique_ptr<VerilatedVcdC> tfp(new VerilatedVcdC(vcdfd.get()));
if (vcdfile) {
top->trace(tfp.get(), 99); // Trace 99 levels of hierarchy
tfp->open("");
}
#endif
for (int i = 0; i < 10; i++) {
top->rst_ni = 0;
top->clk_i = 0;
top->eval();
#if VM_TRACE
tfp->dump(static_cast<vluint64_t>(main_time * 2));
#endif
top->clk_i = 1;
top->eval();
#if VM_TRACE
tfp->dump(static_cast<vluint64_t>(main_time * 2 + 1));
#endif
main_time ++;
}
top->rst_ni = 1;
while (!dtm->done() && !jtag->done()) {
top->clk_i = 0;
top->eval();
#if VM_TRACE
// dump = tfp && trace_count >= start;
// if (dump)
tfp->dump(static_cast<vluint64_t>(main_time * 2));
#endif
top->clk_i = 1;
top->eval();
#if VM_TRACE
// if (dump)
tfp->dump(static_cast<vluint64_t>(main_time * 2 + 1));
#endif
main_time++;
}
#if VM_TRACE
if (tfp)
tfp->close();
if (vcdfile)
fclose(vcdfile);
#endif
if (dtm->exit_code()) {
fprintf(stderr, "%s *** FAILED *** (code = %d) after %ld cycles\n", htif_argv[1], dtm->exit_code(), main_time);
ret = dtm->exit_code();
} else if (jtag->exit_code()) {
fprintf(stderr, "%s *** FAILED *** (code = %d, seed %d) after %ld cycles\n", htif_argv[1], jtag->exit_code(), random_seed, main_time);
ret = jtag->exit_code();
} else {
fprintf(stderr, "%s completed after %ld cycles\n", htif_argv[1], main_time);
}
if (dtm) delete dtm;
if (jtag) delete jtag;
std::clock_t c_end = std::clock();
auto t_end = std::chrono::high_resolution_clock::now();
if (perf) {
std::cout << std::fixed << std::setprecision(2) << "CPU time used: "
<< 1000.0 * (c_end-c_start) / CLOCKS_PER_SEC << " ms\n"
<< "Wall clock time passed: "
<< std::chrono::duration<double, std::milli>(t_end-t_start).count()
<< " ms\n";
}
return ret;
}

86
tb/ariane_tb.sv Normal file
View file

@ -0,0 +1,86 @@
// Copyright 2018 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this 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.
//
// Author: Florian Zaruba, ETH Zurich
// Date: 15/04/2017
// Description: Top level testbench module. Instantiates the top level DUT, configures
// the virtual interfaces and starts the test passed by +UVM_TEST+
import ariane_pkg::*;
import uvm_pkg::*;
`include "uvm_macros.svh"
module ariane_tb;
// static uvm_cmdline_processor uvcl = uvm_cmdline_processor::get_inst();
localparam int unsigned CLOCK_PERIOD = 20ns;
logic clk_i;
logic rst_ni;
logic [63:0] time_i;
longint unsigned cycles;
longint unsigned max_cycles;
logic [31:0] exit_o;
ariane_testharness dut (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
.exit_o ( exit_o )
);
// Clock process
initial begin
clk_i = 1'b0;
rst_ni = 1'b0;
repeat(8)
#(CLOCK_PERIOD/2) clk_i = ~clk_i;
rst_ni = 1'b1;
forever begin
#(CLOCK_PERIOD/2) clk_i = 1'b1;
#(CLOCK_PERIOD/2) clk_i = 1'b0;
//if (cycles > max_cycles)
// $fatal(1, "Simulation reached maximum cycle count of %d", max_cycles);
cycles++;
end
end
// Real Time Clock
initial begin
// initialize platform timer
time_i = 64'b0;
// increment timer with a frequency of 32.768 kHz
forever begin
#30.517578us;
time_i++;
end
end
initial begin
forever begin
wait (exit_o[0]);
if ((exit_o >> 1)) begin
`uvm_error( "Core Test", $sformatf("*** FAILED *** (tohost = %0d)", (exit_o >> 1)))
end else begin
`uvm_info( "Core Test", $sformatf("*** SUCCESS *** (tohost = %0d)", (exit_o >> 1)), UVM_LOW)
end
$finish();
end
end
endmodule

315
tb/ariane_testharness.sv Normal file
View file

@ -0,0 +1,315 @@
// Copyright 2018 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this 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.
//
// Author: Florian Zaruba, ETH Zurich
// Date: 19.03.2017
// Description: Test-harness for Ariane
// Instantiates an AXI-Bus and memories
module ariane_testharness #(
parameter logic [63:0] CACHE_START_ADDR = 64'h8000_0000, // address on which to decide whether the request is cache-able or not
parameter int unsigned AXI_ID_WIDTH = 10,
parameter int unsigned AXI_USER_WIDTH = 1,
parameter int unsigned AXI_ADDRESS_WIDTH = 64,
parameter int unsigned AXI_DATA_WIDTH = 64,
parameter int unsigned NUM_WORDS = 2**24 // memory size
)(
input logic clk_i,
input logic rst_ni,
output logic [31:0] exit_o
);
// disable test-enable
logic test_en;
logic ndmreset;
logic ndmreset_n;
logic debug_req;
int jtag_enable;
logic init_done;
logic [31:0] jtag_exit, dmi_exit;
logic jtag_TCK;
logic jtag_TMS;
logic jtag_TDI;
logic jtag_TRSTn;
logic jtag_TDO_data;
logic jtag_TDO_driven;
logic debug_req_valid;
logic debug_req_ready;
logic [6:0] debug_req_bits_addr;
logic [1:0] debug_req_bits_op;
logic [31:0] debug_req_bits_data;
logic debug_resp_valid;
logic debug_resp_ready;
logic [1:0] debug_resp_bits_resp;
logic [31:0] debug_resp_bits_data;
logic jtag_req_valid;
logic [6:0] jtag_req_bits_addr;
logic [1:0] jtag_req_bits_op;
logic [31:0] jtag_req_bits_data;
logic jtag_resp_ready;
logic jtag_resp_valid;
logic dmi_req_valid;
logic [6:0] dmi_req_bits_addr;
logic [1:0] dmi_req_bits_op;
logic [31:0] dmi_req_bits_data;
logic dmi_resp_ready;
logic dmi_resp_valid;
assign test_en = 1'b0;
assign ndmreset_n = ~ndmreset ;
localparam NB_SLAVE = 3;
localparam NB_MASTER = 3;
localparam AXI_ID_WIDTH_SLAVES = AXI_ID_WIDTH + $clog2(NB_SLAVE);
AXI_BUS #(
.AXI_ADDR_WIDTH ( AXI_ADDRESS_WIDTH ),
.AXI_DATA_WIDTH ( AXI_DATA_WIDTH ),
.AXI_ID_WIDTH ( AXI_ID_WIDTH ),
.AXI_USER_WIDTH ( AXI_USER_WIDTH )
) slave[NB_SLAVE-1:0]();
AXI_BUS #(
.AXI_ADDR_WIDTH ( AXI_ADDRESS_WIDTH ),
.AXI_DATA_WIDTH ( AXI_DATA_WIDTH ),
.AXI_ID_WIDTH ( AXI_ID_WIDTH_SLAVES ),
.AXI_USER_WIDTH ( AXI_USER_WIDTH )
) master[NB_MASTER-1:0]();
// ---------------
// Debug
// ---------------
assign init_done = rst_ni;
initial begin
if (!$value$plusargs("jtag_rbb_enable=%b", jtag_enable)) jtag_enable = 'h0;
end
// debug if MUX
assign debug_req_valid = (jtag_enable[0]) ? jtag_req_valid : dmi_req_valid;
assign debug_req_bits_addr = (jtag_enable[0]) ? jtag_req_bits_addr : dmi_req_bits_addr;
assign debug_req_bits_op = (jtag_enable[0]) ? jtag_req_bits_op : dmi_req_bits_op;
assign debug_req_bits_data = (jtag_enable[0]) ? jtag_req_bits_data : dmi_req_bits_data;
assign debug_resp_ready = (jtag_enable[0]) ? jtag_resp_ready : dmi_resp_ready;
assign exit_o = (jtag_enable[0]) ? jtag_exit : dmi_exit;
assign jtag_resp_valid = (jtag_enable[0]) ? debug_resp_valid : 1'b0;
assign dmi_resp_valid = (jtag_enable[0]) ? 1'b0 : debug_resp_valid;
// SiFive's SimJTAG Module
// Converts to DPI calls
SimJTAG i_SimJTAG (
.clock ( clk_i ),
.reset ( ~rst_ni ),
.enable ( jtag_enable[0] ),
.init_done ( init_done ),
.jtag_TCK ( jtag_TCK ),
.jtag_TMS ( jtag_TMS ),
.jtag_TDI ( jtag_TDI ),
.jtag_TRSTn ( jtag_TRSTn ),
.jtag_TDO_data ( jtag_TDO_data ),
.jtag_TDO_driven ( jtag_TDO_driven ),
.exit ( jtag_exit )
);
dmi_jtag i_dmi_jtag (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
.dmi_rst_no ( ),
.dmi_req_valid_o ( jtag_req_valid ),
.dmi_req_ready_i ( debug_req_ready ),
.dmi_req_bits_addr_o ( jtag_req_bits_addr ),
.dmi_req_bits_op_o ( jtag_req_bits_op ),
.dmi_req_bits_data_o ( jtag_req_bits_data ),
.dmi_resp_valid_i ( jtag_resp_valid ),
.dmi_resp_ready_o ( jtag_resp_ready ),
.dmi_resp_bits_resp_i ( debug_resp_bits_resp ),
.dmi_resp_bits_data_i ( debug_resp_bits_data ),
.tck_i ( jtag_TCK ),
.tms_i ( jtag_TMS ),
.trst_ni ( jtag_TRSTn ),
.td_i ( jtag_TDI ),
.td_o ( jtag_TDO_data ),
.tdo_oe_o ( jtag_TDO_driven )
);
// SiFive's SimDTM Module
// Converts to DPI calls
SimDTM i_SimDTM (
.clk ( clk_i ),
.reset ( ~rst_ni ),
.debug_req_valid ( dmi_req_valid ),
.debug_req_ready ( debug_req_ready ),
.debug_req_bits_addr ( dmi_req_bits_addr ),
.debug_req_bits_op ( dmi_req_bits_op ),
.debug_req_bits_data ( dmi_req_bits_data ),
.debug_resp_valid ( dmi_resp_valid ),
.debug_resp_ready ( dmi_resp_ready ),
.debug_resp_bits_resp ( debug_resp_bits_resp ),
.debug_resp_bits_data ( debug_resp_bits_data ),
.exit ( dmi_exit )
);
// debug module
dm_top #(
// current implementation only supports 1 hart
.NrHarts ( 1 ),
.AxiIdWidth ( AXI_ID_WIDTH_SLAVES ),
.AxiAddrWidth ( AXI_ADDRESS_WIDTH ),
.AxiDataWidth ( AXI_DATA_WIDTH ),
.AxiUserWidth ( AXI_USER_WIDTH )
) i_dm_top (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ), // PoR
.ndmreset_o ( ndmreset ),
.dmactive_o ( ), // active debug session
.debug_req_o ( debug_req ),
.axi_slave ( master[2] ),
.dmi_rst_ni ( rst_ni ),
.dmi_req_valid_i ( debug_req_valid ),
.dmi_req_ready_o ( debug_req_ready ),
.dmi_req_bits_addr_i ( debug_req_bits_addr ),
.dmi_req_bits_op_i ( debug_req_bits_op ),
.dmi_req_bits_data_i ( debug_req_bits_data ),
.dmi_resp_valid_o ( debug_resp_valid ),
.dmi_resp_ready_i ( debug_resp_ready ),
.dmi_resp_bits_resp_o ( debug_resp_bits_resp ),
.dmi_resp_bits_data_o ( debug_resp_bits_data )
);
// ---------------
// ROM
// ---------------
logic rom_req;
logic [AXI_ADDRESS_WIDTH-1:0] rom_addr;
logic [AXI_DATA_WIDTH-1:0] rom_rdata;
axi2mem #(
.AXI_ID_WIDTH ( AXI_ID_WIDTH_SLAVES ),
.AXI_ADDR_WIDTH ( AXI_ADDRESS_WIDTH ),
.AXI_DATA_WIDTH ( AXI_DATA_WIDTH ),
.AXI_USER_WIDTH ( AXI_USER_WIDTH )
) i_axi2rom (
.clk_i ( clk_i ),
.rst_ni ( ndmreset_n ),
.slave ( master[1] ),
.req_o ( rom_req ),
.we_o ( ),
.addr_o ( rom_addr ),
.be_o ( ),
.data_o ( ),
.data_i ( rom_rdata )
);
bootrom i_bootrom (
.clk_i ( clk_i ),
.req_i ( rom_req ),
.addr_i ( rom_addr ),
.rdata_o ( rom_rdata )
);
// ---------------
// Memory
// ---------------
logic req;
logic we;
logic [AXI_ADDRESS_WIDTH-1:0] addr;
logic [AXI_DATA_WIDTH/8-1:0] be;
logic [AXI_DATA_WIDTH-1:0] wdata;
logic [AXI_DATA_WIDTH-1:0] rdata;
logic [AXI_DATA_WIDTH-1:0] bit_en;
// convert byte enable to bit enable
for (genvar i = 0; i < AXI_DATA_WIDTH/8; i++) begin
assign bit_en[i*8 +: 8] = {8{be[i]}};
end
axi2mem #(
.AXI_ID_WIDTH ( AXI_ID_WIDTH_SLAVES ),
.AXI_ADDR_WIDTH ( AXI_ADDRESS_WIDTH ),
.AXI_DATA_WIDTH ( AXI_DATA_WIDTH ),
.AXI_USER_WIDTH ( AXI_USER_WIDTH )
) i_axi2mem (
.clk_i ( clk_i ),
.rst_ni ( ndmreset_n ),
.slave ( master[0] ),
.req_o ( req ),
.we_o ( we ),
.addr_o ( addr ),
.be_o ( be ),
.data_o ( wdata ),
.data_i ( rdata )
);
sram #(
.DATA_WIDTH ( AXI_DATA_WIDTH ),
.NUM_WORDS ( NUM_WORDS )
) i_sram (
.clk_i ( clk_i ),
.req_i ( req ),
.we_i ( we ),
.addr_i ( addr[$clog2(NUM_WORDS)-1+$clog2(AXI_DATA_WIDTH/8):$clog2(AXI_DATA_WIDTH/8)] ),
.wdata_i ( wdata ),
.be_i ( bit_en ),
.rdata_o ( rdata )
);
// ---------------
// AXI Xbar
// ---------------
axi_node_intf_wrap #(
// three ports from Ariane (instruction, data and bypass)
.NB_SLAVE ( NB_SLAVE ),
.NB_MASTER ( NB_MASTER ), // debug unit, memory unit
.AXI_ADDR_WIDTH ( AXI_ADDRESS_WIDTH ),
.AXI_DATA_WIDTH ( AXI_DATA_WIDTH ),
.AXI_USER_WIDTH ( AXI_USER_WIDTH ),
.AXI_ID_WIDTH ( AXI_ID_WIDTH )
) i_axi_xbar (
.clk ( clk_i ),
.rst_n ( ndmreset_n ),
.test_en_i ( test_en ),
.slave ( slave ),
.master ( master ),
.start_addr_i ( {64'h0, 64'h10000, CACHE_START_ADDR} ),
.end_addr_i ( {64'hFFF, 64'h1FFFF, CACHE_START_ADDR + 2**24} )
);
// ---------------
// Core
// ---------------
ariane #(
.CACHE_START_ADDR ( CACHE_START_ADDR ),
.AXI_ID_WIDTH ( AXI_ID_WIDTH ),
.AXI_USER_WIDTH ( AXI_USER_WIDTH )
) i_ariane (
.clk_i ( clk_i ),
.rst_ni ( ndmreset_n ),
.test_en_i ( test_en ),
.boot_addr_i ( 64'h10000 ), // start fetching from ROM
.core_id_i ( '0 ),
.cluster_id_i ( '0 ),
.irq_i ( '0 ),
.ipi_i ( '0 ),
.time_irq_i ( '0 ),
.debug_req_i ( debug_req ),
.data_if ( slave[2] ),
.bypass_if ( slave[1] ),
.instr_if ( slave[0] )
);
endmodule

81
tb/common/SimDTM.sv Normal file
View file

@ -0,0 +1,81 @@
// See LICENSE.SiFive for license details.
//VCS coverage exclude_file
import "DPI-C" function int debug_tick
(
output bit debug_req_valid,
input bit debug_req_ready,
output int debug_req_bits_addr,
output int debug_req_bits_op,
output int debug_req_bits_data,
input bit debug_resp_valid,
output bit debug_resp_ready,
input int debug_resp_bits_resp,
input int debug_resp_bits_data
);
module SimDTM(
input clk,
input reset,
output debug_req_valid,
input debug_req_ready,
output [ 6:0] debug_req_bits_addr,
output [ 1:0] debug_req_bits_op,
output [31:0] debug_req_bits_data,
input debug_resp_valid,
output debug_resp_ready,
input [ 1:0] debug_resp_bits_resp,
input [31:0] debug_resp_bits_data,
output [31:0] exit
);
bit r_reset;
wire #0.1 __debug_req_ready = debug_req_ready;
wire #0.1 __debug_resp_valid = debug_resp_valid;
wire [31:0] #0.1 __debug_resp_bits_resp = {30'b0, debug_resp_bits_resp};
wire [31:0] #0.1 __debug_resp_bits_data = debug_resp_bits_data;
bit __debug_req_valid;
int __debug_req_bits_addr;
int __debug_req_bits_op;
int __debug_req_bits_data;
bit __debug_resp_ready;
int __exit;
assign #0.1 debug_req_valid = __debug_req_valid;
assign #0.1 debug_req_bits_addr = __debug_req_bits_addr[6:0];
assign #0.1 debug_req_bits_op = __debug_req_bits_op[1:0];
assign #0.1 debug_req_bits_data = __debug_req_bits_data[31:0];
assign #0.1 debug_resp_ready = __debug_resp_ready;
assign #0.1 exit = __exit;
always @(posedge clk)
begin
r_reset <= reset;
if (reset || r_reset)
begin
__debug_req_valid = 0;
__debug_resp_ready = 0;
__exit = 0;
end
else
begin
__exit = debug_tick(
__debug_req_valid,
__debug_req_ready,
__debug_req_bits_addr,
__debug_req_bits_op,
__debug_req_bits_data,
__debug_resp_valid,
__debug_resp_ready,
__debug_resp_bits_resp,
__debug_resp_bits_data
);
end
end
endmodule

83
tb/common/SimJTAG.sv Normal file
View file

@ -0,0 +1,83 @@
// See LICENSE.SiFive for license details.
//VCS coverage exclude_file
import "DPI-C" function int jtag_tick
(
output bit jtag_TCK,
output bit jtag_TMS,
output bit jtag_TDI,
output bit jtag_TRSTn,
input bit jtag_TDO
);
module SimJTAG #(
parameter TICK_DELAY = 50
)(
input clock,
input reset,
input enable,
input init_done,
output jtag_TCK,
output jtag_TMS,
output jtag_TDI,
output jtag_TRSTn,
input jtag_TDO_data,
input jtag_TDO_driven,
output [31:0] exit
);
reg [31:0] tickCounterReg;
wire [31:0] tickCounterNxt;
assign tickCounterNxt = (tickCounterReg == 0) ? TICK_DELAY : (tickCounterReg - 1);
bit r_reset;
wire [31:0] random_bits = $random;
wire #0.1 __jtag_TDO = jtag_TDO_driven ?
jtag_TDO_data : random_bits[0];
bit __jtag_TCK;
bit __jtag_TMS;
bit __jtag_TDI;
bit __jtag_TRSTn;
int __exit;
reg init_done_sticky;
assign #0.1 jtag_TCK = __jtag_TCK;
assign #0.1 jtag_TMS = __jtag_TMS;
assign #0.1 jtag_TDI = __jtag_TDI;
assign #0.1 jtag_TRSTn = __jtag_TRSTn;
assign #0.1 exit = __exit;
always @(posedge clock) begin
r_reset <= reset;
if (reset || r_reset) begin
__exit = 0;
tickCounterReg <= TICK_DELAY;
init_done_sticky <= 1'b0;
end else begin
init_done_sticky <= init_done | init_done_sticky;
if (enable && init_done_sticky) begin
tickCounterReg <= tickCounterNxt;
if (tickCounterReg == 0) begin
__exit = jtag_tick(
__jtag_TCK,
__jtag_TMS,
__jtag_TDI,
__jtag_TRSTn,
__jtag_TDO);
end
end // if (enable && init_done_sticky)
end // else: !if(reset || r_reset)
end // always @ (posedge clock)
endmodule

77
tb/common/core_mem.sv Executable file
View file

@ -0,0 +1,77 @@
// Copyright 2018 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this 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.
//
// Author: Florian Zaruba, ETH Zurich
// Date: 23.05.2017
// Description: Load Store Unit, handles address calculation and memory interface signals
module core_mem #(
parameter logic [63:0] DRAM_BASE = 64'h80000000
)(
input logic clk_i, // Clock
input logic rst_ni, // Asynchronous reset active low
// Data memory/cache
input logic [63:0] data_if_address_i,
input logic data_if_data_req_i,
input logic [7:0] data_if_data_be_i,
output logic data_if_data_rvalid_o,
output logic [63:0] data_if_data_rdata_o,
input logic [63:0] data_if_data_wdata_i,
input logic data_if_data_we_i
);
// we always grant the access
localparam ADDRESS_WIDTH = 24;
logic [63:0] fetch_data_ram, fetch_data_rom;
logic [63:0] data_address_q;
logic [63:0] data_ram, data_rom;
// look at the address of the previous cycle to determine what to return
assign data_if_data_rdata_o = (data_address_q >= DRAM_BASE) ? data_ram : data_rom;
dp_ram #(
.ADDR_WIDTH ( ADDRESS_WIDTH ),
.DATA_WIDTH ( 64 )
) ram_i (
.clk ( clk_i ),
.en_a_i ( 1'b0 ),
.addr_a_i ( ),
.wdata_a_i ( ), // not connected
.rdata_a_o ( ),
.we_a_i ( 1'b0 ), // r/o interface
.be_a_i ( ),
// data RAM
.en_b_i ( data_if_data_req_i ),
.addr_b_i ( data_if_address_i[ADDRESS_WIDTH-1+3:3] ),
.wdata_b_i ( data_if_data_wdata_i ),
.rdata_b_o ( data_ram ),
.we_b_i ( ((data_if_address_i >= DRAM_BASE) ? data_if_data_we_i : 1'b0) ),
.be_b_i ( data_if_data_be_i )
);
boot_rom data_boot_rom_i (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
.address_i ( data_address_q ),
.data_o ( data_rom )
);
// Output the rvalid one cycle later, together with the rdata
always_ff @(posedge clk_i or negedge rst_ni) begin : proc_
if (~rst_ni) begin
data_if_data_rvalid_o <= 1'b0;
data_address_q <= '0;
end else begin
data_if_data_rvalid_o <= data_if_data_req_i;
data_address_q <= data_if_address_i;
end
end
endmodule

60
tb/common/dp_ram.sv Executable file
View file

@ -0,0 +1,60 @@
// Copyright 2015-2018 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this 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.
module dp_ram
#(
parameter int ADDR_WIDTH = 8,
parameter int DATA_WIDTH = 64
)(
// Clock and Reset
input logic clk,
input logic en_a_i,
input logic [ADDR_WIDTH-1:0] addr_a_i,
input logic [DATA_WIDTH-1:0] wdata_a_i,
output logic [DATA_WIDTH-1:0] rdata_a_o,
input logic we_a_i,
input logic [DATA_WIDTH/8-1:0] be_a_i,
input logic en_b_i,
input logic [ADDR_WIDTH-1:0] addr_b_i,
input logic [DATA_WIDTH-1:0] wdata_b_i,
output logic [DATA_WIDTH-1:0] rdata_b_o,
input logic we_b_i,
input logic [DATA_WIDTH/8-1:0] be_b_i
);
localparam words = 2**ADDR_WIDTH;
logic [DATA_WIDTH/8-1:0][7:0] mem [words-1:0];
always @(posedge clk) begin
if (en_a_i && we_a_i) begin
for (int i = 0; i < DATA_WIDTH/8; i++) begin
if (be_a_i[i])
mem[addr_a_i][i] <= wdata_a_i[i*8 +: 8];
end
end
rdata_a_o <= mem[addr_a_i];
if (en_b_i && we_b_i) begin
for (int i = 0; i < DATA_WIDTH/8; i++) begin
if (be_b_i[i])
mem[addr_b_i][i] <= wdata_b_i[i*8 +: 8];
end
end
rdata_b_o <= mem[addr_b_i];
end
endmodule

33
tb/common/pulp_sync.sv Normal file
View file

@ -0,0 +1,33 @@
// Copyright 2018 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this 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.
// Antonio Pullini <pullinia@iis.ee.ethz.ch>
module pulp_sync #(
parameter STAGES = 2
)(
input logic clk_i,
input logic rstn_i,
input logic serial_i,
output logic serial_o
);
logic [STAGES-1:0] r_reg;
always_ff @(posedge clk_i, negedge rstn_i) begin
if (!rstn_i)
r_reg <= 'h0;
else
r_reg <= {r_reg[STAGES-2:0], serial_i};
end
assign serial_o = r_reg[STAGES-1];
endmodule

67
tb/common/string_buffer.svh Executable file
View file

@ -0,0 +1,67 @@
// Copyright 2018 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this 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.
//
// Author: Florian Zaruba, ETH Zurich
// Date: 13.07.2017
// Description: Buffers a string until a new line appears.
class string_buffer extends uvm_component;
/*-------------------------------------------------------------------------------
-- Interface, port, fields
-------------------------------------------------------------------------------*/
// string buffer
byte buffer [$];
// name to display in console
string logger_name;
/*-------------------------------------------------------------------------------
-- UVM Factory register
-------------------------------------------------------------------------------*/
// Provide implementations of virtual methods such as get_type_name and create
`uvm_component_utils(string_buffer)
/*-------------------------------------------------------------------------------
-- Functions
-------------------------------------------------------------------------------*/
// Constructor
function new(string name = "string_buffer", uvm_component parent=null);
super.new(name, parent);
// default logger name
logger_name = "String Buffer";
endfunction : new
function void set_logger(string logger_name);
this.logger_name = logger_name;
endfunction : set_logger
function void flush();
string s;
// dump the buffer out the whole buffer
foreach (buffer[i]) begin
s = $sformatf("%s%c",s, buffer[i]);
end
uvm_report_info(logger_name, s, UVM_LOW);
// clear buffer afterwards
buffer = {};
endfunction : flush
// put a char to the buffer
function void append(byte ch);
// wait for the new line
if (ch == 8'hA)
this.flush();
else
buffer.push_back(ch);
endfunction : append
endclass : string_buffer

114
tb/common/uart.sv Normal file
View file

@ -0,0 +1,114 @@
// Copyright 2018 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this 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.
//
// Author: Unknown
// Date: Unknown
// Description: This module takes data over UART and prints them to the console
// A string is printed to the console as soon as a '\n' character is found
interface uart_bus
#(
parameter BAUD_RATE = 115200,
parameter PARITY_EN = 0
)
(
input logic rx,
output logic tx,
input logic rx_en
);
localparam BIT_PERIOD = (1000000000/BAUD_RATE*1000);
logic [7:0] character;
logic [256*8-1:0] stringa;
logic parity;
integer charnum;
integer file;
initial
begin
tx = 1'bZ;
file = $fopen("stdout/uart", "w");
end
always
begin
if (rx_en)
begin
@(negedge rx);
#(BIT_PERIOD/2) ;
for (int i=0;i<=7;i++)
begin
#BIT_PERIOD character[i] = rx;
end
if(PARITY_EN == 1)
begin
// check parity
#BIT_PERIOD parity = rx;
for (int i=7;i>=0;i--)
begin
parity = character[i] ^ parity;
end
if(parity == 1'b1)
begin
$display("Parity error detected");
end
end
// STOP BIT
#BIT_PERIOD;
$fwrite(file, "%c", character);
stringa[(255-charnum)*8 +: 8] = character;
if (character == 8'h0A || charnum == 254) // line feed or max. chars reached
begin
if (character == 8'h0A)
stringa[(255-charnum)*8 +: 8] = 8'h0; // null terminate string, replace line feed
else
stringa[(255-charnum-1)*8 +: 8] = 8'h0; // null terminate string
$write("RX string: %s\n",stringa);
charnum = 0;
stringa = "";
end
else
begin
charnum = charnum + 1;
end
end
else
begin
charnum = 0;
stringa = "";
#10;
end
end
task send_char(input logic [7:0] c);
int i;
// start bit
tx = 1'b0;
for (i = 0; i < 8; i++) begin
#(BIT_PERIOD);
tx = c[i];
end
// stop bit
#(BIT_PERIOD);
tx = 1'b1;
#(BIT_PERIOD);
endtask
endinterface

59
tb/dpi/SimDTM.cc Normal file
View file

@ -0,0 +1,59 @@
// See LICENSE.SiFive for license details.
#include <fesvr/dtm.h>
#include <vpi_user.h>
#include <svdpi.h>
#include <stdio.h>
dtm_t* dtm;
extern "C" int debug_tick
(
unsigned char* debug_req_valid,
unsigned char debug_req_ready,
int* debug_req_bits_addr,
int* debug_req_bits_op,
int* debug_req_bits_data,
unsigned char debug_resp_valid,
unsigned char* debug_resp_ready,
int debug_resp_bits_resp,
int debug_resp_bits_data
)
{
if (!dtm) {
s_vpi_vlog_info info;
if (!vpi_get_vlog_info(&info))
abort();
// sanitize arguments
for (int i = 0; i < info.argc; i++) {
// remove any two double pluses at the beginning (those are target arguments)
if (info.argv[i][0] == '+' && info.argv[i][1] == '+' && strlen(info.argv[i]) > 3) {
for (int j = 0; j < strlen(info.argv[i]) - 1; j++) {
info.argv[i][j] = info.argv[i][j + 2];
}
}
// printf("Argument %d: %s\n", i, info.argv[i]);
}
dtm = new dtm_t(info.argc, info.argv);
}
dtm_t::resp resp_bits;
resp_bits.resp = debug_resp_bits_resp;
resp_bits.data = debug_resp_bits_data;
dtm->tick
(
debug_req_ready,
debug_resp_valid,
resp_bits
);
*debug_resp_ready = dtm->resp_ready();
*debug_req_valid = dtm->req_valid();
*debug_req_bits_addr = dtm->req_bits().addr;
*debug_req_bits_op = dtm->req_bits().op;
*debug_req_bits_data = dtm->req_bits().data;
return dtm->done() ? (dtm->exit_code() << 1 | 1) : 0;
}

25
tb/dpi/SimJTAG.cc Normal file
View file

@ -0,0 +1,25 @@
// See LICENSE.SiFive for license details.
#include <cstdlib>
#include "remote_bitbang.h"
remote_bitbang_t* jtag;
extern "C" int jtag_tick
(
unsigned char * jtag_TCK,
unsigned char * jtag_TMS,
unsigned char * jtag_TDI,
unsigned char * jtag_TRSTn,
unsigned char jtag_TDO
)
{
if (!jtag) {
// TODO: Pass in real port number
jtag = new remote_bitbang_t(0);
}
jtag->tick(jtag_TCK, jtag_TMS, jtag_TDI, jtag_TRSTn, jtag_TDO);
return jtag->done() ? (jtag->exit_code() << 1 | 1) : 0;
}

202
tb/dpi/remote_bitbang.cc Normal file
View file

@ -0,0 +1,202 @@
// See LICENSE.Berkeley for license details.
#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <algorithm>
#include <cassert>
#include <cstdio>
#include <cstdlib>
#include "remote_bitbang.h"
/////////// remote_bitbang_t
remote_bitbang_t::remote_bitbang_t(uint16_t port) :
socket_fd(0),
client_fd(0),
recv_start(0),
recv_end(0),
err(0)
{
socket_fd = socket(AF_INET, SOCK_STREAM, 0);
if (socket_fd == -1) {
fprintf(stderr, "remote_bitbang failed to make socket: %s (%d)\n",
strerror(errno), errno);
abort();
}
fcntl(socket_fd, F_SETFL, O_NONBLOCK);
int reuseaddr = 1;
if (setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr,
sizeof(int)) == -1) {
fprintf(stderr, "remote_bitbang failed setsockopt: %s (%d)\n",
strerror(errno), errno);
abort();
}
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(port);
if (::bind(socket_fd, (struct sockaddr *) &addr, sizeof(addr)) == -1) {
fprintf(stderr, "remote_bitbang failed to bind socket: %s (%d)\n",
strerror(errno), errno);
abort();
}
if (listen(socket_fd, 1) == -1) {
fprintf(stderr, "remote_bitbang failed to listen on socket: %s (%d)\n",
strerror(errno), errno);
abort();
}
socklen_t addrlen = sizeof(addr);
if (getsockname(socket_fd, (struct sockaddr *) &addr, &addrlen) == -1) {
fprintf(stderr, "remote_bitbang getsockname failed: %s (%d)\n",
strerror(errno), errno);
abort();
}
tck = 1;
tms = 1;
tdi = 1;
trstn = 1;
quit = 0;
fprintf(stderr, "This emulator compiled with JTAG Remote Bitbang client. To enable, use +jtag_rbb_enable=1.\n");
fprintf(stderr, "Listening on port %d\n",
ntohs(addr.sin_port));
}
void remote_bitbang_t::accept()
{
fprintf(stderr,"Attempting to accept client socket\n");
int again = 1;
while (again != 0) {
client_fd = ::accept(socket_fd, NULL, NULL);
if (client_fd == -1) {
if (errno == EAGAIN) {
// No client waiting to connect right now.
} else {
fprintf(stderr, "failed to accept on socket: %s (%d)\n", strerror(errno),
errno);
again = 0;
abort();
}
} else {
fcntl(client_fd, F_SETFL, O_NONBLOCK);
fprintf(stderr, "Accepted successfully.");
again = 0;
}
}
}
void remote_bitbang_t::tick(
unsigned char * jtag_tck,
unsigned char * jtag_tms,
unsigned char * jtag_tdi,
unsigned char * jtag_trstn,
unsigned char jtag_tdo
)
{
if (client_fd > 0) {
tdo = jtag_tdo;
execute_command();
} else {
this->accept();
}
* jtag_tck = tck;
* jtag_tms = tms;
* jtag_tdi = tdi;
* jtag_trstn = trstn;
}
void remote_bitbang_t::reset(){
//trstn = 0;
}
void remote_bitbang_t::set_pins(char _tck, char _tms, char _tdi){
tck = _tck;
tms = _tms;
tdi = _tdi;
}
void remote_bitbang_t::execute_command()
{
char command;
int again = 1;
while (again) {
ssize_t num_read = read(client_fd, &command, sizeof(command));
if (num_read == -1) {
if (errno == EAGAIN) {
// We'll try again the next call.
//fprintf(stderr, "Received no command. Will try again on the next call\n");
} else {
fprintf(stderr, "remote_bitbang failed to read on socket: %s (%d)\n",
strerror(errno), errno);
again = 0;
abort();
}
} else if (num_read == 0) {
fprintf(stderr, "No Command Received.\n");
again = 1;
} else {
again = 0;
}
}
//fprintf(stderr, "Received a command %c\n", command);
int dosend = 0;
char tosend = '?';
switch (command) {
case 'B': /* fprintf(stderr, "*BLINK*\n"); */ break;
case 'b': /* fprintf(stderr, "_______\n"); */ break;
case 'r': reset(); break; // This is wrong. 'r' has other bits that indicated TRST and SRST.
case '0': set_pins(0, 0, 0); break;
case '1': set_pins(0, 0, 1); break;
case '2': set_pins(0, 1, 0); break;
case '3': set_pins(0, 1, 1); break;
case '4': set_pins(1, 0, 0); break;
case '5': set_pins(1, 0, 1); break;
case '6': set_pins(1, 1, 0); break;
case '7': set_pins(1, 1, 1); break;
case 'R': dosend = 1; tosend = tdo ? '1' : '0'; break;
case 'Q': quit = 1; break;
default:
fprintf(stderr, "remote_bitbang got unsupported command '%c'\n",
command);
}
if (dosend){
while (1) {
ssize_t bytes = write(client_fd, &tosend, sizeof(tosend));
if (bytes == -1) {
fprintf(stderr, "failed to write to socket: %s (%d)\n", strerror(errno), errno);
abort();
}
if (bytes > 0) {
break;
}
}
}
if (quit) {
// The remote disconnected.
fprintf(stderr, "Remote end disconnected\n");
close(client_fd);
client_fd = 0;
}
}

59
tb/dpi/remote_bitbang.h Normal file
View file

@ -0,0 +1,59 @@
// See LICENSE.Berkeley for license details.
#ifndef REMOTE_BITBANG_H
#define REMOTE_BITBANG_H
#include <stdint.h>
#include <sys/types.h>
class remote_bitbang_t
{
public:
// Create a new server, listening for connections from localhost on the given
// port.
remote_bitbang_t(uint16_t port);
// Do a bit of work.
void tick(unsigned char * jtag_tck,
unsigned char * jtag_tms,
unsigned char * jtag_tdi,
unsigned char * jtag_trstn,
unsigned char jtag_tdo);
unsigned char done() {return quit;}
int exit_code() {return err;}
private:
int err;
unsigned char tck;
unsigned char tms;
unsigned char tdi;
unsigned char trstn;
unsigned char tdo;
unsigned char quit;
int socket_fd;
int client_fd;
static const ssize_t buf_size = 64 * 1024;
char recv_buf[buf_size];
ssize_t recv_start, recv_end;
// Check for a client connecting, and accept if there is one.
void accept();
// Execute any commands the client has for us.
// But we only execute 1 because we need time for the
// simulation to run.
void execute_command();
// Reset. Currently does nothing.
void reset();
void set_pins(char _tck, char _tms, char _tdi);
};
#endif

29
tb/dpi/verilator.h Normal file
View file

@ -0,0 +1,29 @@
#ifndef _ROCKET_VERILATOR_H
#define _ROCKET_VERILATOR_H
#include "verilated_vcd_c.h"
#include <stdlib.h>
#include <stdio.h>
extern bool verbose;
extern bool done_reset;
class VerilatedVcdFILE : public VerilatedVcdFile {
public:
VerilatedVcdFILE(FILE* file) : file(file) {}
~VerilatedVcdFILE() {}
bool open(const std::string& name) override {
// file should already be open
return file != NULL;
}
void close() override {
// file should be closed elsewhere
}
ssize_t write(const char* bufp, ssize_t len) override {
return fwrite(bufp, 1, len, file);
}
private:
FILE* file;
};
#endif

81
tb/wave/wave_core.do Normal file
View file

@ -0,0 +1,81 @@
add wave -noupdate -group core /ariane_tb/dut/i_ariane/*
add wave -noupdate -group frontend /ariane_tb/dut/i_ariane/i_frontend/*
add wave -noupdate -group frontend -group icache /ariane_tb/dut/i_ariane/i_frontend/i_icache/*
add wave -noupdate -group frontend -group ras /ariane_tb/dut/i_ariane/i_frontend/i_ras/*
add wave -noupdate -group frontend -group btb /ariane_tb/dut/i_ariane/i_frontend/i_btb/*
add wave -noupdate -group frontend -group bht /ariane_tb/dut/i_ariane/i_frontend/i_bht/*
# add wave -noupdate -group frontend -group instr_scan /ariane_tb/dut/i_ariane/i_frontend/*i_instr_scan/*
add wave -noupdate -group frontend -group fetch_fifo /ariane_tb/dut/i_ariane/i_frontend/i_fetch_fifo/*
add wave -noupdate -group id_stage -group decoder /ariane_tb/dut/i_ariane/id_stage_i/decoder_i/*
add wave -noupdate -group id_stage -group compressed_decoder /ariane_tb/dut/i_ariane/id_stage_i/compressed_decoder_i/*
add wave -noupdate -group id_stage -group instr_realigner /ariane_tb/dut/i_ariane/id_stage_i/instr_realigner_i/*
add wave -noupdate -group id_stage /ariane_tb/dut/i_ariane/id_stage_i/*
add wave -noupdate -group issue_stage -group scoreboard /ariane_tb/dut/i_ariane/issue_stage_i/i_scoreboard/*
add wave -noupdate -group issue_stage -group issue_read_operands /ariane_tb/dut/i_ariane/issue_stage_i/i_issue_read_operands/*
add wave -noupdate -group issue_stage -group rename /ariane_tb/dut/i_ariane/issue_stage_i/i_re_name/*
add wave -noupdate -group issue_stage /ariane_tb/dut/i_ariane/issue_stage_i/*
add wave -noupdate -group ex_stage -group alu /ariane_tb/dut/i_ariane/ex_stage_i/alu_i/*
add wave -noupdate -group ex_stage -group mult /ariane_tb/dut/i_ariane/ex_stage_i/i_mult/*
add wave -noupdate -group ex_stage -group mult -group mul /ariane_tb/dut/i_ariane/ex_stage_i/i_mult/i_mul/*
add wave -noupdate -group ex_stage -group mult -group div /ariane_tb/dut/i_ariane/ex_stage_i/i_mult/i_div/*
add wave -noupdate -group ex_stage -group mult -group ff1 /ariane_tb/dut/i_ariane/ex_stage_i/i_mult/i_ff1/*
add wave -noupdate -group ex_stage -group lsu /ariane_tb/dut/i_ariane/ex_stage_i/lsu_i/*
add wave -noupdate -group ex_stage -group lsu -group lsu_bypass /ariane_tb/dut/i_ariane/ex_stage_i/lsu_i/lsu_bypass_i/*
add wave -noupdate -group ex_stage -group lsu -group mmu /ariane_tb/dut/i_ariane/ex_stage_i/lsu_i/i_mmu/*
add wave -noupdate -group ex_stage -group lsu -group mmu -group itlb /ariane_tb/dut/i_ariane/ex_stage_i/lsu_i/i_mmu/i_itlb/*
add wave -noupdate -group ex_stage -group lsu -group mmu -group dtlb /ariane_tb/dut/i_ariane/ex_stage_i/lsu_i/i_mmu/i_dtlb/*
add wave -noupdate -group ex_stage -group lsu -group mmu -group ptw /ariane_tb/dut/i_ariane/ex_stage_i/lsu_i/i_mmu/i_ptw/*
add wave -noupdate -group ex_stage -group lsu -group store_unit /ariane_tb/dut/i_ariane/ex_stage_i/lsu_i/i_store_unit/*
add wave -noupdate -group ex_stage -group lsu -group store_unit -group store_buffer /ariane_tb/dut/i_ariane/ex_stage_i/lsu_i/i_store_unit/store_buffer_i/*
add wave -noupdate -group ex_stage -group lsu -group load_unit /ariane_tb/dut/i_ariane/ex_stage_i/lsu_i/i_load_unit/*
add wave -noupdate -group ex_stage -group lsu -group lsu_arbiter /ariane_tb/dut/i_ariane/ex_stage_i/lsu_i/i_lsu_arbiter/*
add wave -noupdate -group ex_stage -group branch_unit /ariane_tb/dut/i_ariane/ex_stage_i/branch_unit_i/*
add wave -noupdate -group ex_stage -group csr_buffer /ariane_tb/dut/i_ariane/ex_stage_i/csr_buffer_i/*
add wave -noupdate -group ex_stage /ariane_tb/dut/i_ariane/ex_stage_i/*
add wave -noupdate -group commit_stage /ariane_tb/dut/i_ariane/commit_stage_i/*
add wave -noupdate -group csr_file /ariane_tb/dut/i_ariane/csr_regfile_i/*
add wave -noupdate -group controller /ariane_tb/dut/i_ariane/controller_i/*
add wave -noupdate -group nbdcache /ariane_tb/dut/i_ariane/ex_stage_i/lsu_i/i_nbdcache/*
add wave -noupdate -group nbdcache -group miss_handler /ariane_tb/dut/i_ariane/ex_stage_i/lsu_i/i_nbdcache/i_miss_handler/*
add wave -noupdate -group nbdcache -group bypass_arbiter /ariane_tb/dut/i_ariane/ex_stage_i/lsu_i/i_nbdcache/i_miss_handler/i_bypass_arbiter/*
add wave -noupdate -group nbdcache -group bypass_axi /ariane_tb/dut/i_ariane/ex_stage_i/lsu_i/i_nbdcache/i_miss_handler/i_bypass_axi_adapter/*
add wave -noupdate -group nbdcache -group miss_axi /ariane_tb/dut/i_ariane/ex_stage_i/lsu_i/i_nbdcache/i_miss_handler/i_miss_axi_adapter/*
add wave -noupdate -group nbdcache -group lfsr /ariane_tb/dut/i_ariane/ex_stage_i/lsu_i/i_nbdcache/i_miss_handler/i_lfsr/*
add wave -noupdate -group nbdcache -group dirty_ram /ariane_tb/dut/i_ariane/ex_stage_i/lsu_i/i_nbdcache/dirty_sram/*
add wave -noupdate -group nbdcache -group tag_cmp /ariane_tb/dut/i_ariane/ex_stage_i/lsu_i/i_nbdcache/i_tag_cmp/*
add wave -noupdate -group nbdcache -group ptw {/ariane_tb/dut/i_ariane/ex_stage_i/lsu_i/i_nbdcache/master_ports[0]/i_cache_ctrl/*}
add wave -noupdate -group nbdcache -group load {/ariane_tb/dut/i_ariane/ex_stage_i/lsu_i/i_nbdcache/master_ports[1]/i_cache_ctrl/*}
add wave -noupdate -group nbdcache -group store {/ariane_tb/dut/i_ariane/ex_stage_i/lsu_i/i_nbdcache/master_ports[2]/i_cache_ctrl/*}
add wave -noupdate -group perf_counters {/ariane_tb/dut/i_ariane/i_perf_counters/*}
add wave -noupdate -group dm_top /ariane_tb/dut/i_dm_top/*
add wave -noupdate -group dm_top -group dm_csrs /ariane_tb/dut/i_dm_top/i_dm_csrs/*
add wave -noupdate -group dm_top -group dm_mem /ariane_tb/dut/i_dm_top/i_dm_mem/*
add wave -noupdate -group bootrom /ariane_tb/dut/i_bootrom/*
add wave -noupdate -group tracer_if /ariane_tb/dut/i_ariane/instr_tracer_i/tracer_if/*
add wave -group SimJTAG /ariane_tb/dut/i_SimJTAG/*
add wave -group dmi_jtag /ariane_tb/dut/i_dmi_jtag/*
add wave -group dmi_jtag -group dmi_jtag_tap /ariane_tb/dut/i_dmi_jtag/i_dmi_jtag_tap/*
add wave -group dmi_jtag -group dmi_cdc /ariane_tb/dut/i_dmi_jtag/i_dmi_cdc/*