1
0

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:
Andrew Waterman
2016-08-15 22:03:03 -07:00
parent 2d1d7266f5
commit ed827678ac
38 changed files with 483 additions and 1792 deletions

View File

@ -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)

View File

@ -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 }

View File

@ -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
}
}

View File

@ -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
})

View 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)
}
}