Write test harness in Chisel
This is an unavoidably invasive commit, because it affects the unit tests (which formerly exited using stop()), the test harness Verilog generator (since it is no longer necessary), and the DRAM model (since it is no longer connected). However, this should substantially reduce the effort of building test harnesses in the future, since manual or semi-automatic Verilog writing should no longer be necessary. Furthermore, there is now very little duplication of effort between the Verilator and VCS test harnesses. This commit removes support for DRAMsim, which is a bit of an unfortunate consequence. The main blocker is the lack of Verilog parameterization for BlackBox. It would be straightforward to revive DRAMsim once support for that feature is added to Chisel and FIRRTL. But that might not even be necessary, as we move towards synthesizable DRAM models and FAME-1 transformations.
This commit is contained in:
@ -77,10 +77,6 @@ object RocketChipGenerator extends App {
|
||||
|
||||
TestGeneration.addSuite(new RegressionTestSuite(paramsFromConfig(RegressionTestNames)))
|
||||
TestGeneration.generateMakefrag(topModuleName, configClassName)
|
||||
TestBenchGeneration.generateVerilogFragment(
|
||||
topModuleName, configClassName, paramsFromConfig)
|
||||
TestBenchGeneration.generateCPPFragment(
|
||||
topModuleName, configClassName, paramsFromConfig)
|
||||
|
||||
dumpParameters(s"$topModuleName.$configClassName.prm")
|
||||
dumpKnobs(configClassName, world)
|
||||
|
@ -122,11 +122,15 @@ object TopUtils {
|
||||
//TODO: Remove this wrapper once multichannel DRAM controller is provided
|
||||
class Top(topParams: Parameters) extends Module with HasTopLevelParameters {
|
||||
implicit val p = topParams
|
||||
val io = new TopIO
|
||||
|
||||
val coreplex = p(BuildCoreplex)(p)
|
||||
val periphery = Module(new Periphery()(innerParams))
|
||||
|
||||
val io = new TopIO {
|
||||
val success = if (coreplex.hasSuccessFlag) Some(Bool(OUTPUT)) else None
|
||||
}
|
||||
io.success zip coreplex.io.success map { case (x, y) => x := y }
|
||||
|
||||
if (exportMMIO) { periphery.io.mmio_in.get <> coreplex.io.mmio.get }
|
||||
periphery.io.mem_in <> coreplex.io.mem
|
||||
if (exportBus) { coreplex.io.bus.get <> periphery.io.bus_out.get }
|
||||
|
@ -1,400 +0,0 @@
|
||||
// See LICENSE for license details.
|
||||
|
||||
package rocketchip
|
||||
|
||||
import Chisel._
|
||||
import cde.Parameters
|
||||
import uncore.devices.{DbBusConsts, DMKey}
|
||||
import coreplex._
|
||||
|
||||
object TestBenchGeneration {
|
||||
def generateVerilogFragment(
|
||||
topModuleName: String, configClassName: String, p: Parameters) = {
|
||||
val nMemChannel = p(NMemoryChannels)
|
||||
// YUNSUP:
|
||||
// I originally wrote this using a 2d wire array, but of course Synopsys'
|
||||
// DirectC implementation totally chokes on it when the 2d array is
|
||||
// referenced by the first dimension: the wire shows up as a contiguous
|
||||
// bit collection on the DirectC side. I had to individually define the
|
||||
// wires.
|
||||
|
||||
val daw = p(DMKey).nDebugBusAddrSize
|
||||
val dow = DbBusConsts.dbOpSize
|
||||
val ddw = DbBusConsts.dbDataSize
|
||||
val drw = DbBusConsts.dbRespSize
|
||||
|
||||
val debugDefs = s"""
|
||||
wire debug_req_valid_delay;
|
||||
reg debug_req_valid;
|
||||
assign #0.1 debug_req_valid_delay = debug_req_valid;
|
||||
|
||||
wire debug_req_ready, debug_req_ready_delay;
|
||||
assign #0.1 debug_req_ready = debug_req_ready_delay;
|
||||
|
||||
wire [${daw-1}:0] debug_req_bits_addr_delay;
|
||||
reg [${daw-1}:0] debug_req_bits_addr;
|
||||
assign #0.1 debug_req_bits_addr_delay = debug_req_bits_addr;
|
||||
|
||||
wire [${dow-1}:0] debug_req_bits_op_delay;
|
||||
reg [${dow-1}:0] debug_req_bits_op;
|
||||
assign #0.1 debug_req_bits_op_delay = debug_req_bits_op;
|
||||
|
||||
wire [${ddw-1}:0] debug_req_bits_data_delay;
|
||||
reg [${ddw-1}:0] debug_req_bits_data;
|
||||
assign #0.1 debug_req_bits_data_delay = debug_req_bits_data;
|
||||
|
||||
wire debug_resp_valid, debug_resp_valid_delay;
|
||||
assign #0.1 debug_resp_valid = debug_resp_valid_delay;
|
||||
|
||||
wire debug_resp_ready_delay;
|
||||
reg debug_resp_ready;
|
||||
assign #0.1 debug_resp_ready_delay = debug_resp_ready;
|
||||
|
||||
wire [${drw-1}:0] debug_resp_bits_resp, debug_resp_bits_resp_delay;
|
||||
assign #0.1 debug_resp_bits_resp = debug_resp_bits_resp_delay;
|
||||
|
||||
wire [${ddw-1}:0] debug_resp_bits_data, debug_resp_bits_data_delay;
|
||||
assign #0.1 debug_resp_bits_data = debug_resp_bits_data_delay;
|
||||
"""
|
||||
|
||||
val debugBus = s"""
|
||||
.io_debug_req_ready(debug_req_ready_delay),
|
||||
.io_debug_req_valid(debug_req_valid_delay),
|
||||
.io_debug_req_bits_addr(debug_req_bits_addr_delay),
|
||||
.io_debug_req_bits_op(debug_req_bits_op_delay),
|
||||
.io_debug_req_bits_data(debug_req_bits_data_delay),
|
||||
.io_debug_resp_ready(debug_resp_ready_delay),
|
||||
.io_debug_resp_valid(debug_resp_valid_delay),
|
||||
.io_debug_resp_bits_resp(debug_resp_bits_resp_delay),
|
||||
.io_debug_resp_bits_data(debug_resp_bits_data_delay)
|
||||
"""
|
||||
val nasti_defs = (0 until nMemChannel) map { i => s"""
|
||||
wire ar_valid_$i;
|
||||
reg ar_ready_$i;
|
||||
wire [`MEM_ADDR_BITS-1:0] ar_addr_$i;
|
||||
wire [`MEM_ID_BITS-1:0] ar_id_$i;
|
||||
wire [2:0] ar_size_$i;
|
||||
wire [7:0] ar_len_$i;
|
||||
|
||||
wire aw_valid_$i;
|
||||
reg aw_ready_$i;
|
||||
wire [`MEM_ADDR_BITS-1:0] aw_addr_$i;
|
||||
wire [`MEM_ID_BITS-1:0] aw_id_$i;
|
||||
wire [2:0] aw_size_$i;
|
||||
wire [7:0] aw_len_$i;
|
||||
|
||||
wire w_valid_$i;
|
||||
reg w_ready_$i;
|
||||
wire [`MEM_STRB_BITS-1:0] w_strb_$i;
|
||||
wire [`MEM_DATA_BITS-1:0] w_data_$i;
|
||||
wire w_last_$i;
|
||||
|
||||
reg r_valid_$i;
|
||||
wire r_ready_$i;
|
||||
reg [1:0] r_resp_$i;
|
||||
reg [`MEM_ID_BITS-1:0] r_id_$i;
|
||||
reg [`MEM_DATA_BITS-1:0] r_data_$i;
|
||||
reg r_last_$i;
|
||||
|
||||
reg b_valid_$i;
|
||||
wire b_ready_$i;
|
||||
reg [1:0] b_resp_$i;
|
||||
reg [`MEM_ID_BITS-1:0] b_id_$i;
|
||||
|
||||
""" } mkString
|
||||
|
||||
val nasti_delays = (0 until nMemChannel) map { i => s"""
|
||||
wire ar_valid_delay_$i;
|
||||
wire ar_ready_delay_$i;
|
||||
wire [`MEM_ADDR_BITS-1:0] ar_addr_delay_$i;
|
||||
wire [`MEM_ID_BITS-1:0] ar_id_delay_$i;
|
||||
wire [2:0] ar_size_delay_$i;
|
||||
wire [7:0] ar_len_delay_$i;
|
||||
|
||||
wire aw_valid_delay_$i;
|
||||
wire aw_ready_delay_$i;
|
||||
wire [`MEM_ADDR_BITS-1:0] aw_addr_delay_$i;
|
||||
wire [`MEM_ID_BITS-1:0] aw_id_delay_$i;
|
||||
wire [2:0] aw_size_delay_$i;
|
||||
wire [7:0] aw_len_delay_$i;
|
||||
|
||||
wire w_valid_delay_$i;
|
||||
wire w_ready_delay_$i;
|
||||
wire [`MEM_STRB_BITS-1:0] w_strb_delay_$i;
|
||||
wire [`MEM_DATA_BITS-1:0] w_data_delay_$i;
|
||||
wire w_last_delay_$i;
|
||||
|
||||
wire r_valid_delay_$i;
|
||||
wire r_ready_delay_$i;
|
||||
wire [1:0] r_resp_delay_$i;
|
||||
wire [`MEM_ID_BITS-1:0] r_id_delay_$i;
|
||||
wire [`MEM_DATA_BITS-1:0] r_data_delay_$i;
|
||||
wire r_last_delay_$i;
|
||||
|
||||
wire b_valid_delay_$i;
|
||||
wire b_ready_delay_$i;
|
||||
wire [1:0] b_resp_delay_$i;
|
||||
wire [`MEM_ID_BITS-1:0] b_id_delay_$i;
|
||||
|
||||
assign #0.1 ar_valid_$i = ar_valid_delay_$i;
|
||||
assign #0.1 ar_ready_delay_$i = ar_ready_$i;
|
||||
assign #0.1 ar_addr_$i = ar_addr_delay_$i;
|
||||
assign #0.1 ar_id_$i = ar_id_delay_$i;
|
||||
assign #0.1 ar_size_$i = ar_size_delay_$i;
|
||||
assign #0.1 ar_len_$i = ar_len_delay_$i;
|
||||
|
||||
assign #0.1 aw_valid_$i = aw_valid_delay_$i;
|
||||
assign #0.1 aw_ready_delay_$i = aw_ready_$i;
|
||||
assign #0.1 aw_addr_$i = aw_addr_delay_$i;
|
||||
assign #0.1 aw_id_$i = aw_id_delay_$i;
|
||||
assign #0.1 aw_size_$i = aw_size_delay_$i;
|
||||
assign #0.1 aw_len_$i = aw_len_delay_$i;
|
||||
|
||||
assign #0.1 w_valid_$i = w_valid_delay_$i;
|
||||
assign #0.1 w_ready_delay_$i = w_ready_$i;
|
||||
assign #0.1 w_strb_$i = w_strb_delay_$i;
|
||||
assign #0.1 w_data_$i = w_data_delay_$i;
|
||||
assign #0.1 w_last_$i = w_last_delay_$i;
|
||||
|
||||
assign #0.1 r_valid_delay_$i = r_valid_$i;
|
||||
assign #0.1 r_ready_$i = r_ready_delay_$i;
|
||||
assign #0.1 r_resp_delay_$i = r_resp_$i;
|
||||
assign #0.1 r_id_delay_$i = r_id_$i;
|
||||
assign #0.1 r_data_delay_$i = r_data_$i;
|
||||
assign #0.1 r_last_delay_$i = r_last_$i;
|
||||
|
||||
assign #0.1 b_valid_delay_$i = b_valid_$i;
|
||||
assign #0.1 b_ready_$i = b_ready_delay_$i;
|
||||
assign #0.1 b_resp_delay_$i = b_resp_$i;
|
||||
assign #0.1 b_id_delay_$i = b_id_$i;
|
||||
|
||||
""" } mkString
|
||||
|
||||
val nasti_connections = (0 until nMemChannel) map { i => s"""
|
||||
.io_mem_axi_${i}_ar_valid (ar_valid_delay_$i),
|
||||
.io_mem_axi_${i}_ar_ready (ar_ready_delay_$i),
|
||||
.io_mem_axi_${i}_ar_bits_addr (ar_addr_delay_$i),
|
||||
.io_mem_axi_${i}_ar_bits_id (ar_id_delay_$i),
|
||||
.io_mem_axi_${i}_ar_bits_size (ar_size_delay_$i),
|
||||
.io_mem_axi_${i}_ar_bits_len (ar_len_delay_$i),
|
||||
.io_mem_axi_${i}_ar_bits_burst (),
|
||||
.io_mem_axi_${i}_ar_bits_lock (),
|
||||
.io_mem_axi_${i}_ar_bits_cache (),
|
||||
.io_mem_axi_${i}_ar_bits_prot (),
|
||||
.io_mem_axi_${i}_ar_bits_qos (),
|
||||
.io_mem_axi_${i}_ar_bits_region (),
|
||||
.io_mem_axi_${i}_ar_bits_user (),
|
||||
|
||||
.io_mem_axi_${i}_aw_valid (aw_valid_delay_$i),
|
||||
.io_mem_axi_${i}_aw_ready (aw_ready_delay_$i),
|
||||
.io_mem_axi_${i}_aw_bits_addr (aw_addr_delay_$i),
|
||||
.io_mem_axi_${i}_aw_bits_id (aw_id_delay_$i),
|
||||
.io_mem_axi_${i}_aw_bits_size (aw_size_delay_$i),
|
||||
.io_mem_axi_${i}_aw_bits_len (aw_len_delay_$i),
|
||||
.io_mem_axi_${i}_aw_bits_burst (),
|
||||
.io_mem_axi_${i}_aw_bits_lock (),
|
||||
.io_mem_axi_${i}_aw_bits_cache (),
|
||||
.io_mem_axi_${i}_aw_bits_prot (),
|
||||
.io_mem_axi_${i}_aw_bits_qos (),
|
||||
.io_mem_axi_${i}_aw_bits_region (),
|
||||
.io_mem_axi_${i}_aw_bits_user (),
|
||||
|
||||
.io_mem_axi_${i}_w_valid (w_valid_delay_$i),
|
||||
.io_mem_axi_${i}_w_ready (w_ready_delay_$i),
|
||||
.io_mem_axi_${i}_w_bits_id (),
|
||||
.io_mem_axi_${i}_w_bits_strb (w_strb_delay_$i),
|
||||
.io_mem_axi_${i}_w_bits_data (w_data_delay_$i),
|
||||
.io_mem_axi_${i}_w_bits_last (w_last_delay_$i),
|
||||
.io_mem_axi_${i}_w_bits_user (),
|
||||
|
||||
.io_mem_axi_${i}_r_valid (r_valid_delay_$i),
|
||||
.io_mem_axi_${i}_r_ready (r_ready_delay_$i),
|
||||
.io_mem_axi_${i}_r_bits_resp (r_resp_delay_$i),
|
||||
.io_mem_axi_${i}_r_bits_id (r_id_delay_$i),
|
||||
.io_mem_axi_${i}_r_bits_data (r_data_delay_$i),
|
||||
.io_mem_axi_${i}_r_bits_last (r_last_delay_$i),
|
||||
.io_mem_axi_${i}_r_bits_user (1'b0),
|
||||
|
||||
.io_mem_axi_${i}_b_valid (b_valid_delay_$i),
|
||||
.io_mem_axi_${i}_b_ready (b_ready_delay_$i),
|
||||
.io_mem_axi_${i}_b_bits_resp (b_resp_delay_$i),
|
||||
.io_mem_axi_${i}_b_bits_id (b_id_delay_$i),
|
||||
.io_mem_axi_${i}_b_bits_user (1'b0),
|
||||
|
||||
""" } mkString
|
||||
|
||||
val interrupts = (0 until p(NExtInterrupts)) map { i => s"""
|
||||
.io_interrupts_$i (1'b0),
|
||||
""" } mkString
|
||||
|
||||
|
||||
val instantiation = s"""
|
||||
${topModuleName} dut
|
||||
(
|
||||
.clk(clk),
|
||||
.reset(reset),
|
||||
|
||||
$nasti_connections
|
||||
|
||||
$interrupts
|
||||
|
||||
$debugBus
|
||||
);
|
||||
"""
|
||||
|
||||
val ticks = (0 until nMemChannel) map { i => s"""
|
||||
reg [31:0] channel_$i = $i;
|
||||
|
||||
always @(posedge clk)
|
||||
begin
|
||||
if (reset || r_reset)
|
||||
begin
|
||||
ar_ready_$i <= 1'b0;
|
||||
aw_ready_$i <= 1'b0;
|
||||
w_ready_$i <= 1'b0;
|
||||
r_valid_$i <= 1'b0;
|
||||
r_resp_$i <= 2'b0;
|
||||
r_id_$i <= {`MEM_ID_BITS {1'b0}};
|
||||
r_data_$i <= {`MEM_DATA_BITS {1'b0}};
|
||||
r_last_$i <= 1'b0;
|
||||
b_valid_$i <= 1'b0;
|
||||
b_resp_$i <= 2'b0;
|
||||
b_id_$i <= {`MEM_ID_BITS {1'b0}};
|
||||
end
|
||||
else
|
||||
begin
|
||||
memory_tick
|
||||
(
|
||||
channel_$i,
|
||||
ar_valid_$i, ar_ready_$i, ar_addr_$i, ar_id_$i, ar_size_$i, ar_len_$i,
|
||||
aw_valid_$i, aw_ready_$i, aw_addr_$i, aw_id_$i, aw_size_$i, aw_len_$i,
|
||||
w_valid_$i, w_ready_$i, w_strb_$i, w_data_$i, w_last_$i,
|
||||
r_valid_$i, r_ready_$i, r_resp_$i, r_id_$i, r_data_$i, r_last_$i,
|
||||
b_valid_$i, b_ready_$i, b_resp_$i, b_id_$i
|
||||
);
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge clk)
|
||||
begin
|
||||
if (verbose)
|
||||
begin
|
||||
if (ar_valid_$i && ar_ready_$i)
|
||||
begin
|
||||
$$fdisplay(stderr, "MC$i: ar addr=%x size=%x", ar_addr_$i, ar_size_$i);
|
||||
end
|
||||
if (aw_valid_$i && aw_ready_$i)
|
||||
begin
|
||||
$$fdisplay(stderr, "MC$i: aw addr=%x size=%x", aw_addr_$i, aw_size_$i);
|
||||
end
|
||||
if (w_valid_$i && w_ready_$i)
|
||||
begin
|
||||
$$fdisplay(stderr, "MC$i: w data=%x strb=%x", w_data_$i, w_strb_$i);
|
||||
end
|
||||
if (r_valid_$i && r_ready_$i)
|
||||
begin
|
||||
$$fdisplay(stderr, "MC$i: r data=%x", r_data_$i);
|
||||
end
|
||||
end
|
||||
end
|
||||
""" } mkString
|
||||
|
||||
val f = TestGeneration.createOutputFile(s"$topModuleName.$configClassName.tb.vfrag")
|
||||
f.write(debugDefs + nasti_defs + nasti_delays + instantiation + ticks)
|
||||
f.close
|
||||
}
|
||||
|
||||
def generateCPPFragment(
|
||||
topModuleName: String, configClassName: String, p: Parameters) = {
|
||||
val nMemChannel = p(NMemoryChannels)
|
||||
|
||||
val assigns = (0 until nMemChannel).map { i => s"""
|
||||
#ifndef VERILATOR
|
||||
mem_ar_valid[$i] = &tile.Top__io_mem_axi_${i}_ar_valid;
|
||||
mem_ar_ready[$i] = &tile.Top__io_mem_axi_${i}_ar_ready;
|
||||
mem_ar_bits_addr[$i] = &tile.Top__io_mem_axi_${i}_ar_bits_addr;
|
||||
mem_ar_bits_id[$i] = &tile.Top__io_mem_axi_${i}_ar_bits_id;
|
||||
mem_ar_bits_size[$i] = &tile.Top__io_mem_axi_${i}_ar_bits_size;
|
||||
mem_ar_bits_len[$i] = &tile.Top__io_mem_axi_${i}_ar_bits_len;
|
||||
|
||||
mem_aw_valid[$i] = &tile.Top__io_mem_axi_${i}_aw_valid;
|
||||
mem_aw_ready[$i] = &tile.Top__io_mem_axi_${i}_aw_ready;
|
||||
mem_aw_bits_addr[$i] = &tile.Top__io_mem_axi_${i}_aw_bits_addr;
|
||||
mem_aw_bits_id[$i] = &tile.Top__io_mem_axi_${i}_aw_bits_id;
|
||||
mem_aw_bits_size[$i] = &tile.Top__io_mem_axi_${i}_aw_bits_size;
|
||||
mem_aw_bits_len[$i] = &tile.Top__io_mem_axi_${i}_aw_bits_len;
|
||||
|
||||
mem_w_valid[$i] = &tile.Top__io_mem_axi_${i}_w_valid;
|
||||
mem_w_ready[$i] = &tile.Top__io_mem_axi_${i}_w_ready;
|
||||
mem_w_bits_data[$i] = &tile.Top__io_mem_axi_${i}_w_bits_data;
|
||||
mem_w_bits_strb[$i] = &tile.Top__io_mem_axi_${i}_w_bits_strb;
|
||||
mem_w_bits_last[$i] = &tile.Top__io_mem_axi_${i}_w_bits_last;
|
||||
|
||||
mem_b_valid[$i] = &tile.Top__io_mem_axi_${i}_b_valid;
|
||||
mem_b_ready[$i] = &tile.Top__io_mem_axi_${i}_b_ready;
|
||||
mem_b_bits_resp[$i] = &tile.Top__io_mem_axi_${i}_b_bits_resp;
|
||||
mem_b_bits_id[$i] = &tile.Top__io_mem_axi_${i}_b_bits_id;
|
||||
|
||||
mem_r_valid[$i] = &tile.Top__io_mem_axi_${i}_r_valid;
|
||||
mem_r_ready[$i] = &tile.Top__io_mem_axi_${i}_r_ready;
|
||||
mem_r_bits_resp[$i] = &tile.Top__io_mem_axi_${i}_r_bits_resp;
|
||||
mem_r_bits_id[$i] = &tile.Top__io_mem_axi_${i}_r_bits_id;
|
||||
mem_r_bits_data[$i] = &tile.Top__io_mem_axi_${i}_r_bits_data;
|
||||
mem_r_bits_last[$i] = &tile.Top__io_mem_axi_${i}_r_bits_last;
|
||||
#else
|
||||
mem_ar_valid[$i] = &tile.io_mem_axi_${i}_ar_valid;
|
||||
mem_ar_ready[$i] = &tile.io_mem_axi_${i}_ar_ready;
|
||||
mem_ar_bits_addr[$i] = &tile.io_mem_axi_${i}_ar_bits_addr;
|
||||
mem_ar_bits_id[$i] = &tile.io_mem_axi_${i}_ar_bits_id;
|
||||
mem_ar_bits_size[$i] = &tile.io_mem_axi_${i}_ar_bits_size;
|
||||
mem_ar_bits_len[$i] = &tile.io_mem_axi_${i}_ar_bits_len;
|
||||
|
||||
mem_aw_valid[$i] = &tile.io_mem_axi_${i}_aw_valid;
|
||||
mem_aw_ready[$i] = &tile.io_mem_axi_${i}_aw_ready;
|
||||
mem_aw_bits_addr[$i] = &tile.io_mem_axi_${i}_aw_bits_addr;
|
||||
mem_aw_bits_id[$i] = &tile.io_mem_axi_${i}_aw_bits_id;
|
||||
mem_aw_bits_size[$i] = &tile.io_mem_axi_${i}_aw_bits_size;
|
||||
mem_aw_bits_len[$i] = &tile.io_mem_axi_${i}_aw_bits_len;
|
||||
|
||||
mem_w_valid[$i] = &tile.io_mem_axi_${i}_w_valid;
|
||||
mem_w_ready[$i] = &tile.io_mem_axi_${i}_w_ready;
|
||||
#if MEM_DATA_BITS > 64
|
||||
mem_w_bits_data[$i] = tile.io_mem_axi_${i}_w_bits_data;
|
||||
#else
|
||||
mem_w_bits_data[$i] = &tile.io_mem_axi_${i}_w_bits_data;
|
||||
#endif
|
||||
mem_w_bits_strb[$i] = &tile.io_mem_axi_${i}_w_bits_strb;
|
||||
mem_w_bits_last[$i] = &tile.io_mem_axi_${i}_w_bits_last;
|
||||
|
||||
mem_b_valid[$i] = &tile.io_mem_axi_${i}_b_valid;
|
||||
mem_b_ready[$i] = &tile.io_mem_axi_${i}_b_ready;
|
||||
mem_b_bits_resp[$i] = &tile.io_mem_axi_${i}_b_bits_resp;
|
||||
mem_b_bits_id[$i] = &tile.io_mem_axi_${i}_b_bits_id;
|
||||
|
||||
mem_r_valid[$i] = &tile.io_mem_axi_${i}_r_valid;
|
||||
mem_r_ready[$i] = &tile.io_mem_axi_${i}_r_ready;
|
||||
mem_r_bits_resp[$i] = &tile.io_mem_axi_${i}_r_bits_resp;
|
||||
mem_r_bits_id[$i] = &tile.io_mem_axi_${i}_r_bits_id;
|
||||
#if MEM_DATA_BITS > 64
|
||||
mem_r_bits_data[$i] = tile.io_mem_axi_${i}_r_bits_data;
|
||||
#else
|
||||
mem_r_bits_data[$i] = &tile.io_mem_axi_${i}_r_bits_data;
|
||||
#endif
|
||||
mem_r_bits_last[$i] = &tile.io_mem_axi_${i}_r_bits_last;
|
||||
#endif
|
||||
""" }.mkString
|
||||
|
||||
val interrupts = (0 until p(NExtInterrupts)) map { i => s"""
|
||||
#ifndef VERILATOR
|
||||
tile.Top__io_interrupts_$i = LIT<1>(0);
|
||||
#else
|
||||
tile.io_interrupts_$i = 0;
|
||||
#endif
|
||||
""" } mkString
|
||||
|
||||
val f = TestGeneration.createOutputFile(s"$topModuleName.$configClassName.tb.cpp")
|
||||
f.write(assigns)
|
||||
f.write(interrupts)
|
||||
f.close
|
||||
}
|
||||
}
|
@ -128,3 +128,49 @@ class DirectMemtestFPGAConfig extends Config(
|
||||
new FPGAConfig ++ new DirectMemtestConfig)
|
||||
class DirectComparatorFPGAConfig extends Config(
|
||||
new FPGAConfig ++ new DirectComparatorConfig)
|
||||
|
||||
class WithGroundTest extends Config(
|
||||
(pname, site, here) => pname match {
|
||||
case BuildCoreplex => (p: Parameters) => Module(new GroundTestCoreplex(p))
|
||||
case TLKey("L1toL2") => {
|
||||
val useMEI = site(NTiles) <= 1 && site(NCachedTileLinkPorts) <= 1
|
||||
TileLinkParameters(
|
||||
coherencePolicy = (
|
||||
if (useMEI) new MEICoherence(site(L2DirectoryRepresentation))
|
||||
else new MESICoherence(site(L2DirectoryRepresentation))),
|
||||
nManagers = site(NBanksPerMemoryChannel)*site(NMemoryChannels) + 1,
|
||||
nCachingClients = site(NCachedTileLinkPorts),
|
||||
nCachelessClients = site(NUncachedTileLinkPorts),
|
||||
maxClientXacts = ((site(NMSHRs) + 1) +:
|
||||
site(GroundTestKey).map(_.maxXacts))
|
||||
.reduce(max(_, _)),
|
||||
maxClientsPerPort = 1,
|
||||
maxManagerXacts = site(NAcquireTransactors) + 2,
|
||||
dataBeats = 8,
|
||||
dataBits = site(CacheBlockBytes)*8)
|
||||
}
|
||||
case BuildTiles => {
|
||||
val groundtest = if (site(XLen) == 64)
|
||||
DefaultTestSuites.groundtest64
|
||||
else
|
||||
DefaultTestSuites.groundtest32
|
||||
TestGeneration.addSuite(groundtest("p"))
|
||||
TestGeneration.addSuite(DefaultTestSuites.emptyBmarks)
|
||||
(0 until site(NTiles)).map { i =>
|
||||
val tileSettings = site(GroundTestKey)(i)
|
||||
(r: Bool, p: Parameters) => {
|
||||
Module(new GroundTestTile(resetSignal = r)(p.alterPartial({
|
||||
case TLId => "L1toL2"
|
||||
case GroundTestId => i
|
||||
case NCachedTileLinkPorts => if(tileSettings.cached > 0) 1 else 0
|
||||
case NUncachedTileLinkPorts => tileSettings.uncached
|
||||
})))
|
||||
}
|
||||
}
|
||||
}
|
||||
case UseFPU => false
|
||||
case UseAtomics => false
|
||||
case UseCompressed => false
|
||||
case RegressionTestNames => LinkedHashSet("rv64ui-p-simple")
|
||||
case _ => throw new CDEMatchError
|
||||
})
|
||||
|
116
src/main/scala/TestHarness.scala
Normal file
116
src/main/scala/TestHarness.scala
Normal file
@ -0,0 +1,116 @@
|
||||
// See LICENSE for license details.
|
||||
|
||||
package rocketchip
|
||||
|
||||
import Chisel._
|
||||
import cde.{Parameters, Field}
|
||||
import rocket.Util._
|
||||
import junctions._
|
||||
|
||||
class TestHarness(implicit p: Parameters) extends Module {
|
||||
val io = new Bundle {
|
||||
val success = Bool(OUTPUT)
|
||||
}
|
||||
val dut = Module(new Top(p))
|
||||
|
||||
// This test harness isn't especially flexible yet
|
||||
require(dut.io.mem_clk.isEmpty)
|
||||
require(dut.io.mem_rst.isEmpty)
|
||||
require(dut.io.mem_ahb.isEmpty)
|
||||
require(dut.io.mem_tl.isEmpty)
|
||||
require(dut.io.bus_clk.isEmpty)
|
||||
require(dut.io.bus_rst.isEmpty)
|
||||
require(dut.io.bus_axi.isEmpty)
|
||||
require(dut.io.mmio_clk.isEmpty)
|
||||
require(dut.io.mmio_rst.isEmpty)
|
||||
require(dut.io.mmio_axi.isEmpty)
|
||||
require(dut.io.mmio_ahb.isEmpty)
|
||||
require(dut.io.mmio_tl.isEmpty)
|
||||
require(dut.io.debug_clk.isEmpty)
|
||||
require(dut.io.debug_rst.isEmpty)
|
||||
require(dut.io.debug_rst.isEmpty)
|
||||
require(dut.io.extra.elements.isEmpty)
|
||||
|
||||
for (int <- dut.io.interrupts)
|
||||
int := false
|
||||
|
||||
if (dut.io.mem_axi.nonEmpty) {
|
||||
val memSize = p(GlobalAddrMap)("mem").size
|
||||
require(memSize % dut.io.mem_axi.size == 0)
|
||||
for (axi <- dut.io.mem_axi)
|
||||
Module(new SimAXIMem(memSize / dut.io.mem_axi.size)).io.axi <> axi
|
||||
}
|
||||
|
||||
val dtm = Module(new SimDTM)
|
||||
dut.io.debug <> dtm.io.debug
|
||||
dtm.io.clk := clock
|
||||
dtm.io.reset := reset
|
||||
io.success := dut.io.success.getOrElse(dtm.io.exit === 1)
|
||||
when (dtm.io.exit >= 2) {
|
||||
printf("*** FAILED *** (exit code = %d)\n", dtm.io.exit >> 1)
|
||||
stop(1)
|
||||
}
|
||||
}
|
||||
|
||||
class SimAXIMem(size: BigInt)(implicit p: Parameters) extends Module {
|
||||
val io = new Bundle {
|
||||
val axi = new NastiIO().flip
|
||||
}
|
||||
|
||||
val rValid = Reg(init = Bool(false))
|
||||
val ar = RegEnable(io.axi.ar.bits, io.axi.ar.fire())
|
||||
io.axi.ar.ready := !rValid
|
||||
when (io.axi.ar.fire()) { rValid := true }
|
||||
when (io.axi.r.fire()) {
|
||||
assert(ar.burst === NastiConstants.BURST_INCR)
|
||||
ar.addr := ar.addr + (UInt(1) << ar.size)
|
||||
ar.len := ar.len - 1
|
||||
when (ar.len === UInt(0)) { rValid := false }
|
||||
}
|
||||
|
||||
val w = io.axi.w.bits
|
||||
require((size * 8) % w.data.getWidth == 0)
|
||||
val depth = (size * 8) / w.data.getWidth
|
||||
val mem = Mem(depth.toInt, w.data)
|
||||
|
||||
val wValid = Reg(init = Bool(false))
|
||||
val bValid = Reg(init = Bool(false))
|
||||
val aw = RegEnable(io.axi.aw.bits, io.axi.aw.fire())
|
||||
io.axi.aw.ready := !wValid && !bValid
|
||||
io.axi.w.ready := wValid
|
||||
when (io.axi.b.fire()) { bValid := false }
|
||||
when (io.axi.aw.fire()) { wValid := true }
|
||||
when (io.axi.w.fire()) {
|
||||
assert(aw.burst === NastiConstants.BURST_INCR)
|
||||
aw.addr := aw.addr + (UInt(1) << aw.size)
|
||||
aw.len := aw.len - 1
|
||||
when (aw.len === UInt(0)) {
|
||||
wValid := false
|
||||
bValid := true
|
||||
}
|
||||
|
||||
def row = mem((aw.addr >> log2Ceil(w.data.getWidth/8))(log2Ceil(depth)-1, 0))
|
||||
val mask = FillInterleaved(8, w.strb)
|
||||
val newData = mask & w.data | ~mask & row
|
||||
row := newData
|
||||
}
|
||||
|
||||
io.axi.b.valid := bValid
|
||||
io.axi.b.bits.id := aw.id
|
||||
io.axi.b.bits.resp := UInt(0)
|
||||
|
||||
io.axi.r.valid := rValid
|
||||
io.axi.r.bits.id := ar.id
|
||||
io.axi.r.bits.data := mem((ar.addr >> log2Ceil(w.data.getWidth/8))(log2Ceil(depth)-1, 0))
|
||||
io.axi.r.bits.resp := UInt(0)
|
||||
io.axi.r.bits.last := ar.len === UInt(0)
|
||||
}
|
||||
|
||||
class SimDTM(implicit p: Parameters) extends BlackBox {
|
||||
val io = new Bundle {
|
||||
val clk = Clock(INPUT)
|
||||
val reset = Bool(INPUT)
|
||||
val debug = new uncore.devices.DebugBusIO
|
||||
val exit = UInt(OUTPUT, 32)
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user