blob: 4a2c0a53abfba85dbd40e5ab7d059c466a7e1056 [file] [log] [blame]
// Copyright 2023 Google LLC
#include "tests/verilator_sim/sysc_tb.h"
#include "VL1ICache.h"
#include "tests/verilator_sim/kelvin/kelvin_cfg.h"
struct L1ICache_tb : Sysc_tb
{
sc_out<bool> io_flush_valid;
sc_in<bool> io_flush_ready;
sc_out<bool> io_ibus_valid;
sc_in<bool> io_ibus_ready;
sc_out<sc_bv<32> > io_ibus_addr;
sc_in<sc_bv<kL1IAxiBits> > io_ibus_rdata;
sc_in<bool> io_axi_read_addr_valid;
sc_out<bool> io_axi_read_addr_ready;
sc_in<sc_bv<kL1IAxiId> > io_axi_read_addr_bits_id;
sc_in<sc_bv<32> > io_axi_read_addr_bits_addr;
sc_out<bool> io_axi_read_data_valid;
sc_in<bool> io_axi_read_data_ready;
sc_out<sc_bv<2> > io_axi_read_data_bits_resp;
sc_out<sc_bv<kL1IAxiId> > io_axi_read_data_bits_id;
sc_out<sc_bv<kL1IAxiBits> > io_axi_read_data_bits_data;
sc_in<bool> io_volt_sel;
using Sysc_tb::Sysc_tb;
void posedge() {
// flush
io_flush_valid = rand_int(0, 255) == 0;
// ibus
if (ibus_resp_pipeline_) {
ibus_resp_pipeline_ = false;
for (int i = 0; i < ibusw_; ++i) {
uint32_t ref = ibus_resp_data_ + i * 4;
uint32_t dut = io_ibus_rdata.read().get_word(i);
check(ref == dut, "ibus read data");
}
}
if (io_ibus_valid && io_ibus_ready) {
ibus_resp_pipeline_ = true;
ibus_resp_data_ = io_ibus_addr.read().get_word(0) & ~(ibusb_ - 1);
command_t cmd({io_ibus_addr.read().get_word(0)});
history_.write(cmd);
if (history_.count() > 16) {
history_.remove();
}
}
if (!io_ibus_valid || io_ibus_ready) { // latch transaction
command_t cmd;
bool newaddr = rand_int(0, 3) == 0 || !history_.rand(cmd);
uint32_t addr = newaddr ? rand_uint32() : cmd.addr;
if (rand_int(0, 7) == 0) {
addr &= 0x3fff;
}
io_ibus_valid = rand_bool();
io_ibus_addr = addr;
}
timeout_ = io_ibus_ready ? 0 : timeout_ + io_ibus_valid;
check(timeout_ < 100, "ibus timeout");
// kxi_read_addr
io_axi_read_addr_ready = rand_bool();
if (io_axi_read_addr_valid && io_axi_read_addr_ready) {
uint32_t id = io_axi_read_addr_bits_id.read().get_word(0);
uint32_t addr = io_axi_read_addr_bits_addr.read().get_word(0);
response_t resp({id, addr});
resp_.write(resp);
}
// kxi_read_data
io_axi_read_data_valid = false;
io_axi_read_data_bits_id = 0;
io_axi_read_data_bits_data = 0;
if (io_axi_read_data_valid && io_axi_read_data_ready) {
check(resp_.remove(), "no response to erase");
resp_.shuffle();
}
response_t resp;
if (resp_.next(resp)) {
io_axi_read_data_valid = rand_bool();
io_axi_read_data_bits_id = resp.id;
uint32_t data = resp.data;
sc_bv<kL1IAxiBits> out;
for (int i = 0; i < axiw_; ++i) {
out.set_word(i, data);
data += 4;
}
io_axi_read_data_bits_data = out;
}
}
private:
struct command_t {
uint32_t addr;
};
struct response_t {
uint32_t id;
uint32_t data;
};
const int ibusb_ = kL1IAxiBits / 8;
const int ibusw_ = kL1IAxiBits / 32;
const int axib_ = kL1IAxiBits / 8;
const int axiw_ = kL1IAxiBits / 32;
int timeout_ = 0;
bool ibus_resp_pipeline_ = false;
uint32_t ibus_resp_data_ = 0;
fifo_t<command_t> history_;
fifo_t<response_t> resp_;
};
static void L1ICache_test(char* name, int loops, bool trace) {
sc_signal<bool> io_flush_valid;
sc_signal<bool> io_flush_ready;
sc_signal<bool> io_ibus_valid;
sc_signal<bool> io_ibus_ready;
sc_signal<sc_bv<32> > io_ibus_addr;
sc_signal<sc_bv<kL1IAxiBits> > io_ibus_rdata;
sc_signal<bool> io_axi_read_addr_valid;
sc_signal<bool> io_axi_read_addr_ready;
sc_signal<sc_bv<kL1IAxiId> > io_axi_read_addr_bits_id;
sc_signal<sc_bv<32> > io_axi_read_addr_bits_addr;
sc_signal<bool> io_axi_read_data_valid;
sc_signal<bool> io_axi_read_data_ready;
sc_signal<sc_bv<2> > io_axi_read_data_bits_resp;
sc_signal<sc_bv<kL1IAxiId> > io_axi_read_data_bits_id;
sc_signal<sc_bv<kL1IAxiBits> > io_axi_read_data_bits_data;
sc_signal<bool> io_volt_sel;
L1ICache_tb tb("L1ICache_tb", loops, true /*random*/);
VL1ICache l1icache(name);
if (trace) {
tb.trace(l1icache);
}
l1icache.clock(tb.clock);
l1icache.reset(tb.reset);
BIND2(tb, l1icache, io_flush_valid);
BIND2(tb, l1icache, io_flush_ready);
BIND2(tb, l1icache, io_ibus_valid);
BIND2(tb, l1icache, io_ibus_ready);
BIND2(tb, l1icache, io_ibus_addr);
BIND2(tb, l1icache, io_ibus_rdata);
BIND2(tb, l1icache, io_axi_read_addr_valid);
BIND2(tb, l1icache, io_axi_read_addr_ready);
BIND2(tb, l1icache, io_axi_read_addr_bits_id);
BIND2(tb, l1icache, io_axi_read_addr_bits_addr);
BIND2(tb, l1icache, io_axi_read_data_ready);
BIND2(tb, l1icache, io_axi_read_data_valid);
BIND2(tb, l1icache, io_axi_read_data_bits_data);
BIND2(tb, l1icache, io_axi_read_data_bits_id);
BIND2(tb, l1icache, io_axi_read_data_bits_resp);
BIND2(tb, l1icache, io_volt_sel);
tb.start();
}
int sc_main(int argc, char *argv[]) {
L1ICache_test(Sysc_tb::get_name(argv[0]), 1000000, false);
return 0;
}