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

47
csrc/SimDTM.cc Normal file
View File

@ -0,0 +1,47 @@
// See LICENSE for license details.
#include <fesvr/dtm.h>
#include <vpi_user.h>
#include <svdpi.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,
long long* debug_req_bits_data,
unsigned char debug_resp_valid,
unsigned char* debug_resp_ready,
int debug_resp_bits_resp,
long long debug_resp_bits_data
)
{
if (!dtm) {
s_vpi_vlog_info info;
if (!vpi_get_vlog_info(&info))
abort();
dtm = new dtm_t(std::vector<std::string>(info.argv + 1, info.argv + info.argc));
}
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;
}

View File

@ -1,15 +1,9 @@
// See LICENSE for license details.
#ifndef VERILATOR
#include "emulator.h"
#else
#include "verilated.h"
#if VM_TRACE
#include "verilated_vcd_c.h"
#endif
#endif
#include "mm.h"
#include "mm_dramsim2.h"
#include <fesvr/dtm.h>
#include <iostream>
#include <fcntl.h>
@ -18,13 +12,7 @@
#include <stdlib.h>
#include <unistd.h>
#define MEM_SIZE_BITS 3
#define MEM_LEN_BITS 8
#define MEM_RESP_BITS 2
#include "emulator_type.h"
static dtm_t* dtm;
extern dtm_t* dtm;
static uint64_t trace_count = 0;
bool verbose;
@ -38,18 +26,19 @@ double sc_time_stamp()
return trace_count;
}
extern "C" int vpi_get_vlog_info(void* arg)
{
return 0;
}
int main(int argc, char** argv)
{
unsigned random_seed = (unsigned)time(NULL) ^ (unsigned)getpid();
uint64_t max_cycles = -1;
uint64_t start = 0;
int ret = 0;
const char* loadmem = NULL;
FILE *vcdfile = NULL;
bool dramsim2 = false;
bool print_cycles = false;
uint64_t memsz_mb = MEM_SIZE / (1024*1024);
mm_t *mm[N_MEM_CHANNELS];
for (int i = 1; i < argc; i++)
{
@ -59,18 +48,12 @@ int main(int argc, char** argv)
vcdfile = strcmp(filename, "-") == 0 ? stdout : fopen(filename, "w");
if (!vcdfile)
abort();
} else if (arg.substr(0, 9) == "+memsize=")
memsz_mb = atoll(argv[i]+9);
else if (arg.substr(0, 2) == "-s")
} else if (arg.substr(0, 2) == "-s")
random_seed = atoi(argv[i]+2);
else if (arg == "+dramsim")
dramsim2 = true;
else if (arg == "+verbose")
verbose = true;
else if (arg.substr(0, 12) == "+max-cycles=")
max_cycles = atoll(argv[i]+12);
else if (arg.substr(0, 9) == "+loadmem=")
loadmem = argv[i]+9;
else if (arg.substr(0, 7) == "+start=")
start = atoll(argv[i]+7);
else if (arg.substr(0, 12) == "+cycle-count")
@ -80,12 +63,8 @@ int main(int argc, char** argv)
srand(random_seed);
srand48(random_seed);
#ifndef VERILATOR
Top_t tile;
tile.init(random_seed);
#else
Verilated::randReset(2);
VTop tile;
VTestHarness tile;
#if VM_TRACE
Verilated::traceEverOn(true); // Verilator must compute traced signals
@ -96,30 +75,6 @@ int main(int argc, char** argv)
tfp->open("");
}
#endif
#endif
uint64_t mem_width = MEM_DATA_BITS / 8;
// Instantiate and initialize main memory
for (int i = 0; i < N_MEM_CHANNELS; i++) {
mm[i] = dramsim2 ? (mm_t*)(new mm_dramsim2_t) : (mm_t*)(new mm_magic_t);
try {
mm[i]->init(memsz_mb*1024*1024 / N_MEM_CHANNELS, mem_width, CACHE_BLOCK_BYTES);
} catch (const std::bad_alloc& e) {
fprintf(stderr,
"Failed to allocate %ld bytes (%ld MiB) of memory\n"
"Set smaller amount of memory using +memsize=<N> (in MiB)\n",
memsz_mb*1024*1024, memsz_mb);
exit(-1);
}
}
if (loadmem) {
void *mems[N_MEM_CHANNELS];
for (int i = 0; i < N_MEM_CHANNELS; i++)
mems[i] = mm[i]->get_data();
load_mem(mems, loadmem, CACHE_BLOCK_BYTES, N_MEM_CHANNELS);
}
dtm = new dtm_t(std::vector<std::string>(argv + 1, argv + argc));
@ -127,155 +82,35 @@ int main(int argc, char** argv)
// reset for several cycles to handle pipelined reset
for (int i = 0; i < 10; i++) {
#ifndef VERILATOR
tile.clock_lo(LIT<1>(1));
tile.clock_hi(LIT<1>(1));
#else
tile.reset = 1;
tile.clk = 0;
tile.eval();
tile.clk = 1;
tile.eval();
tile.reset = 0;
#endif
}
bool_t *mem_ar_valid[N_MEM_CHANNELS];
bool_t *mem_ar_ready[N_MEM_CHANNELS];
mem_addr_t *mem_ar_bits_addr[N_MEM_CHANNELS];
mem_id_t *mem_ar_bits_id[N_MEM_CHANNELS];
mem_size_t *mem_ar_bits_size[N_MEM_CHANNELS];
mem_len_t *mem_ar_bits_len[N_MEM_CHANNELS];
bool_t *mem_aw_valid[N_MEM_CHANNELS];
bool_t *mem_aw_ready[N_MEM_CHANNELS];
mem_addr_t *mem_aw_bits_addr[N_MEM_CHANNELS];
mem_id_t *mem_aw_bits_id[N_MEM_CHANNELS];
mem_size_t *mem_aw_bits_size[N_MEM_CHANNELS];
mem_len_t *mem_aw_bits_len[N_MEM_CHANNELS];
bool_t *mem_w_valid[N_MEM_CHANNELS];
bool_t *mem_w_ready[N_MEM_CHANNELS];
mem_data_t *mem_w_bits_data[N_MEM_CHANNELS];
mem_strb_t *mem_w_bits_strb[N_MEM_CHANNELS];
bool_t *mem_w_bits_last[N_MEM_CHANNELS];
bool_t *mem_b_valid[N_MEM_CHANNELS];
bool_t *mem_b_ready[N_MEM_CHANNELS];
mem_resp_t *mem_b_bits_resp[N_MEM_CHANNELS];
mem_id_t *mem_b_bits_id[N_MEM_CHANNELS];
bool_t *mem_r_valid[N_MEM_CHANNELS];
bool_t *mem_r_ready[N_MEM_CHANNELS];
mem_resp_t *mem_r_bits_resp[N_MEM_CHANNELS];
mem_id_t *mem_r_bits_id[N_MEM_CHANNELS];
mem_data_t *mem_r_bits_data[N_MEM_CHANNELS];
bool_t *mem_r_bits_last[N_MEM_CHANNELS];
#include TBFRAG
while (!dtm->done() && trace_count < max_cycles && ret == 0)
{
for (int i = 0; i < N_MEM_CHANNELS; i++) {
value(mem_ar_ready[i]) = mm[i]->ar_ready();
value(mem_aw_ready[i]) = mm[i]->aw_ready();
value(mem_w_ready[i]) = mm[i]->w_ready();
value(mem_b_valid[i]) = mm[i]->b_valid();
value(mem_b_bits_resp[i]) = mm[i]->b_resp();
value(mem_b_bits_id[i]) = mm[i]->b_id();
value(mem_r_valid[i]) = mm[i]->r_valid();
value(mem_r_bits_resp[i]) = mm[i]->r_resp();
value(mem_r_bits_id[i]) = mm[i]->r_id();
value(mem_r_bits_last[i]) = mm[i]->r_last();
memcpy(values(mem_r_bits_data[i]), mm[i]->r_data(), mem_width);
}
value(field(io_debug_resp_ready)) = dtm->resp_ready();
value(field(io_debug_req_valid)) = dtm->req_valid();
value(field(io_debug_req_bits_addr)) = dtm->req_bits().addr;
value(field(io_debug_req_bits_op)) = dtm->req_bits().op;
value(field(io_debug_req_bits_data)) = dtm->req_bits().data;
try {
#ifndef VERILATOR
tile.clock_lo(LIT<1>(0));
#else
tile.clk = 0;
tile.eval();
// make sure we dump on cycle 0 to get dump_init
while (!dtm->done() && !tile.io_success && trace_count < max_cycles) {
tile.clk = 0;
tile.eval();
#if VM_TRACE
if (tfp && (trace_count == 0 || trace_count >= start))
tfp->dump(trace_count * 2);
bool dump = tfp && trace_count >= start;
if (dump)
tfp->dump(trace_count * 2);
#endif
#endif
} catch (std::runtime_error& e) {
max_cycles = trace_count; // terminate cleanly after this cycle
ret = 1;
std::cerr << e.what() << std::endl;
}
dtm_t::resp debug_resp_bits;
debug_resp_bits.resp = value(field(io_debug_resp_bits_resp));
debug_resp_bits.data = value(field(io_debug_resp_bits_data));
dtm->tick(
value(field(io_debug_req_ready)),
value(field(io_debug_resp_valid)),
debug_resp_bits
);
for (int i = 0; i < N_MEM_CHANNELS; i++) {
mm[i]->tick(
value(mem_ar_valid[i]),
value(mem_ar_bits_addr[i]) - MEM_BASE,
value(mem_ar_bits_id[i]),
value(mem_ar_bits_size[i]),
value(mem_ar_bits_len[i]),
value(mem_aw_valid[i]),
value(mem_aw_bits_addr[i]) - MEM_BASE,
value(mem_aw_bits_id[i]),
value(mem_aw_bits_size[i]),
value(mem_aw_bits_len[i]),
value(mem_w_valid[i]),
value(mem_w_bits_strb[i]),
values(mem_w_bits_data[i]),
value(mem_w_bits_last[i]),
value(mem_r_ready[i]),
value(mem_b_ready[i])
);
}
#ifndef VERILATOR
if (verbose && trace_count >= start)
tile.print(stderr);
// make sure we dump on cycle 0 to get dump_init
if (vcdfile && (trace_count == 0 || trace_count >= start))
tile.dump(vcdfile, trace_count);
tile.clock_hi(LIT<1>(0));
#else
tile.clk = 1;
tile.eval();
#if VM_TRACE
if (tfp && (trace_count == 0 || trace_count >= start))
if (dump)
tfp->dump(trace_count * 2 + 1);
#endif
#endif
trace_count++;
}
#ifdef VERILATOR
#if VM_TRACE
if (tfp)
tfp->close();
#endif
#endif
if (vcdfile)

View File

@ -1,110 +0,0 @@
// See LICENSE for license details.
#ifndef VERILATOR
# define bool_t dat_t<1>
# define values(x) ((x)->values)
# define field(name) &(tile.Top__ ## name)
#else
# define bool_t CData
# define values(x) (x)
# define field(name) &(tile.name)
#endif
#define value(x) (*values(x))
#ifndef VERILATOR
#define mem_addr_t dat_t<MEM_ADDR_BITS>
#elif MEM_ADDR_BITS <= 8
#define mem_addr_t CData
#elif MEM_ADDR_BITS <= 16
#define mem_addr_t SData
#elif MEM_ADDR_BITS <= 32
#define mem_addr_t IData
#elif MEM_ADDR_BITS <= 64
#define mem_addr_t QData
#else // MEM_ADDR_BITS > 64
#define mem_addr_t WData*
#endif
#ifndef VERILATOR
#define mem_id_t dat_t<MEM_ID_BITS>
#elif MEM_ID_BITS <= 8
#define mem_id_t CData
#elif MEM_ID_BITS <= 16
#define mem_id_t SData
#elif MEM_ID_BITS <= 32
#define mem_id_t IData
#elif MEM_ID_BITS <= 64
#define mem_id_t QData
#else // MEM_ID_BITS > 64
#define mem_id_t WData*
#endif
#ifndef VERILATOR
#define mem_size_t dat_t<MEM_SIZE_BITS>
#elif MEM_SIZE_BITS <= 8
#define mem_size_t CData
#elif MEM_SIZE_BITS <= 16
#define mem_size_t SData
#elif MEM_SIZE_BITS <= 32
#define mem_size_t IData
#elif MEM_SIZE_BITS <= 64
#define mem_size_t QData
#else // MEM_SIZE_BITS > 64
#define mem_size_t WData*
#endif
#ifndef VERILATOR
#define mem_len_t dat_t<MEM_LEN_BITS>
#elif MEM_LEN_BITS <= 8
#define mem_len_t CData
#elif MEM_LEN_BITS <= 16
#define mem_len_t SData
#elif MEM_LEN_BITS <= 32
#define mem_len_t IData
#elif MEM_LEN_BITS <= 64
#define mem_len_t QData
#else // MEM_LEN_BITS > 64
#define mem_len_t WData*
#endif
#ifndef VERILATOR
#define mem_strb_t dat_t<MEM_STRB_BITS>
#elif MEM_STRB_BITS <= 8
#define mem_strb_t CData
#elif MEM_STRB_BITS <= 16
#define mem_strb_t SData
#elif MEM_STRB_BITS <= 32
#define mem_strb_t IData
#elif MEM_STRB_BITS <= 64
#define mem_strb_t QData
#else // MEM_STRB_BITS > 64
#define mem_strb_t WData*
#endif
#ifndef VERILATOR
#define mem_data_t dat_t<MEM_DATA_BITS>
#elif MEM_DATA_BITS <= 8
#define mem_data_t CData
#elif MEM_DATA_BITS <= 16
#define mem_data_t SData
#elif MEM_DATA_BITS <= 32
#define mem_data_t IData
#elif MEM_DATA_BITS <= 64
#define mem_data_t QData
#else // MEM_DATA_BITS > 64
#define mem_data_t WData*
#endif
#ifndef VERILATOR
#define mem_resp_t dat_t<MEM_RESP_BITS>
#elif MEM_RESP_BITS <= 8
#define mem_resp_t CData
#elif MEM_RESP_BITS <= 16
#define mem_resp_t SData
#elif MEM_RESP_BITS <= 32
#define mem_resp_t IData
#elif MEM_RESP_BITS <= 64
#define mem_resp_t QData
#else // MEM_RESP_BITS > 64
#define mem_resp_t WData*
#endif

View File

@ -1,140 +0,0 @@
// See LICENSE for license details.
#include "mm.h"
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <cstring>
#include <cassert>
void mm_t::write(uint64_t addr, uint8_t *data, uint64_t strb, uint64_t size)
{
strb &= ((1 << size) - 1) << (addr % word_size);
addr %= this->size;
uint8_t *base = this->data + (addr / word_size) * word_size;
for (int i = 0; i < word_size; i++) {
if (strb & 1)
base[i] = data[i];
strb >>= 1;
}
}
std::vector<char> mm_t::read(uint64_t addr)
{
addr %= this->size;
uint8_t *base = this->data + addr;
return std::vector<char>(base, base + word_size);
}
void mm_t::init(size_t sz, int wsz, int lsz)
{
assert(wsz > 0 && lsz > 0 && (lsz & (lsz-1)) == 0 && lsz % wsz == 0);
word_size = wsz;
line_size = lsz;
data = new uint8_t[sz];
size = sz;
}
mm_t::~mm_t()
{
delete [] data;
}
void mm_magic_t::init(size_t sz, int wsz, int lsz)
{
mm_t::init(sz, wsz, lsz);
dummy_data.resize(word_size);
}
void mm_magic_t::tick(
bool ar_valid,
uint64_t ar_addr,
uint64_t ar_id,
uint64_t ar_size,
uint64_t ar_len,
bool aw_valid,
uint64_t aw_addr,
uint64_t aw_id,
uint64_t aw_size,
uint64_t aw_len,
bool w_valid,
uint64_t w_strb,
void *w_data,
bool w_last,
bool r_ready,
bool b_ready)
{
bool ar_fire = ar_valid && ar_ready();
bool aw_fire = aw_valid && aw_ready();
bool w_fire = w_valid && w_ready();
bool r_fire = r_valid() && r_ready;
bool b_fire = b_valid() && b_ready;
if (ar_fire) {
uint64_t start_addr = (ar_addr / word_size) * word_size;
for (int i = 0; i <= ar_len; i++) {
auto dat = read(start_addr + i * word_size);
rresp.push(mm_rresp_t(ar_id, dat, i == ar_len));
}
}
if (aw_fire) {
store_addr = aw_addr;
store_id = aw_id;
store_count = aw_len + 1;
store_size = 1 << aw_size;
store_inflight = true;
}
if (w_fire) {
write(store_addr, (uint8_t *) w_data, w_strb, store_size);
store_addr += store_size;
store_count--;
if (store_count == 0) {
store_inflight = false;
bresp.push(store_id);
assert(w_last);
}
}
if (b_fire)
bresp.pop();
if (r_fire)
rresp.pop();
cycle++;
}
void load_mem(void** mems, const char* fn, int line_size, int nchannels)
{
char* m;
ssize_t start = 0;
std::ifstream in(fn);
if (!in)
{
std::cerr << "could not open " << fn << std::endl;
exit(-1);
}
std::string line;
while (std::getline(in, line))
{
#define parse_nibble(c) ((c) >= 'a' ? (c)-'a'+10 : (c)-'0')
for (ssize_t i = line.length()-2, j = 0; i >= 0; i -= 2, j++) {
char data = (parse_nibble(line[i]) << 4) | parse_nibble(line[i+1]);
ssize_t addr = start + j;
int channel = (addr / line_size) % nchannels;
m = (char *) mems[channel];
addr = (addr / line_size / nchannels) * line_size + (addr % line_size);
m[addr] = data;
}
start += line.length()/2;
}
}

146
csrc/mm.h
View File

@ -1,146 +0,0 @@
// See LICENSE for license details.
#ifndef MM_EMULATOR_H
#define MM_EMULATOR_H
#include <stdint.h>
#include <cstring>
#include <queue>
class mm_t
{
public:
mm_t() : data(0), size(0) {}
virtual void init(size_t sz, int word_size, int line_size);
virtual bool ar_ready() = 0;
virtual bool aw_ready() = 0;
virtual bool w_ready() = 0;
virtual bool b_valid() = 0;
virtual uint64_t b_resp() = 0;
virtual uint64_t b_id() = 0;
virtual bool r_valid() = 0;
virtual uint64_t r_resp() = 0;
virtual uint64_t r_id() = 0;
virtual void *r_data() = 0;
virtual bool r_last() = 0;
virtual void tick
(
bool ar_valid,
uint64_t ar_addr,
uint64_t ar_id,
uint64_t ar_size,
uint64_t ar_len,
bool aw_valid,
uint64_t aw_addr,
uint64_t aw_id,
uint64_t aw_size,
uint64_t aw_len,
bool w_valid,
uint64_t w_strb,
void *w_data,
bool w_last,
bool r_ready,
bool b_ready
) = 0;
virtual void* get_data() { return data; }
virtual size_t get_size() { return size; }
virtual size_t get_word_size() { return word_size; }
virtual size_t get_line_size() { return line_size; }
void write(uint64_t addr, uint8_t *data, uint64_t strb, uint64_t size);
std::vector<char> read(uint64_t addr);
virtual ~mm_t();
protected:
uint8_t* data;
size_t size;
int word_size;
int line_size;
};
struct mm_rresp_t
{
uint64_t id;
std::vector<char> data;
bool last;
mm_rresp_t(uint64_t id, std::vector<char> data, bool last)
{
this->id = id;
this->data = data;
this->last = last;
}
mm_rresp_t()
{
this->id = 0;
this->last = false;
}
};
class mm_magic_t : public mm_t
{
public:
mm_magic_t() : store_inflight(false) {}
virtual void init(size_t sz, int word_size, int line_size);
virtual bool ar_ready() { return true; }
virtual bool aw_ready() { return !store_inflight; }
virtual bool w_ready() { return store_inflight; }
virtual bool b_valid() { return !bresp.empty(); }
virtual uint64_t b_resp() { return 0; }
virtual uint64_t b_id() { return b_valid() ? bresp.front() : 0; }
virtual bool r_valid() { return !rresp.empty(); }
virtual uint64_t r_resp() { return 0; }
virtual uint64_t r_id() { return r_valid() ? rresp.front().id: 0; }
virtual void *r_data() { return r_valid() ? &rresp.front().data[0] : &dummy_data[0]; }
virtual bool r_last() { return r_valid() ? rresp.front().last : false; }
virtual void tick
(
bool ar_valid,
uint64_t ar_addr,
uint64_t ar_id,
uint64_t ar_size,
uint64_t ar_len,
bool aw_valid,
uint64_t aw_addr,
uint64_t aw_id,
uint64_t aw_size,
uint64_t aw_len,
bool w_valid,
uint64_t w_strb,
void *w_data,
bool w_last,
bool r_ready,
bool b_ready
);
protected:
bool store_inflight;
uint64_t store_addr;
uint64_t store_id;
uint64_t store_size;
uint64_t store_count;
std::vector<char> dummy_data;
std::queue<uint64_t> bresp;
std::queue<mm_rresp_t> rresp;
uint64_t cycle;
};
void load_mem(void** mems, const char* fn, int line_size, int nchannels);
#endif

View File

@ -1,124 +0,0 @@
// See LICENSE for license details.
#include "mm_dramsim2.h"
#include "mm.h"
#include <DRAMSim.h>
#include <iostream>
#include <fstream>
#include <list>
#include <queue>
#include <cstring>
#include <cstdlib>
#include <cassert>
//#define DEBUG_DRAMSIM2
using namespace DRAMSim;
void mm_dramsim2_t::read_complete(unsigned id, uint64_t address, uint64_t clock_cycle)
{
mm_rresp_t resp;
do {
resp = rreq[address].front();
rresp.push(resp);
rreq[address].pop();
} while (!resp.last);
}
void mm_dramsim2_t::write_complete(unsigned id, uint64_t address, uint64_t clock_cycle)
{
auto b_id = wreq[address].front();
bresp.push(b_id);
wreq[address].pop();
}
void power_callback(double a, double b, double c, double d)
{
//fprintf(stderr, "power callback: %0.3f, %0.3f, %0.3f, %0.3f\n",a,b,c,d);
}
void mm_dramsim2_t::init(size_t sz, int wsz, int lsz)
{
assert(lsz == 64); // assumed by dramsim2
mm_t::init(sz, wsz, lsz);
dummy_data.resize(word_size);
assert(size % (1024*1024) == 0);
mem = getMemorySystemInstance("DDR3_micron_64M_8B_x4_sg15.ini", "system.ini", "dramsim2_ini", "results", size/(1024*1024));
TransactionCompleteCB *read_cb = new Callback<mm_dramsim2_t, void, unsigned, uint64_t, uint64_t>(this, &mm_dramsim2_t::read_complete);
TransactionCompleteCB *write_cb = new Callback<mm_dramsim2_t, void, unsigned, uint64_t, uint64_t>(this, &mm_dramsim2_t::write_complete);
mem->RegisterCallbacks(read_cb, write_cb, power_callback);
#ifdef DEBUG_DRAMSIM2
fprintf(stderr,"Dramsim2 init successful\n");
#endif
}
void mm_dramsim2_t::tick(
bool ar_valid,
uint64_t ar_addr,
uint64_t ar_id,
uint64_t ar_size,
uint64_t ar_len,
bool aw_valid,
uint64_t aw_addr,
uint64_t aw_id,
uint64_t aw_size,
uint64_t aw_len,
bool w_valid,
uint64_t w_strb,
void *w_data,
bool w_last,
bool r_ready,
bool b_ready)
{
bool ar_fire = ar_valid && ar_ready();
bool aw_fire = aw_valid && aw_ready();
bool w_fire = w_valid && w_ready();
bool r_fire = r_valid() && r_ready;
bool b_fire = b_valid() && b_ready;
if (ar_fire) {
uint64_t start_addr = (ar_addr / word_size) * word_size;
for (int i = 0; i <= ar_len; i++) {
auto dat = read(start_addr + i * word_size);
rreq[ar_addr].push(mm_rresp_t(ar_id, dat, (i == ar_len)));
}
mem->addTransaction(false, ar_addr);
}
if (aw_fire) {
store_addr = aw_addr;
store_id = aw_id;
store_count = aw_len + 1;
store_size = 1 << aw_size;
store_inflight = true;
}
if (w_fire) {
write(store_addr, (uint8_t *) w_data, w_strb, store_size);
store_addr += store_size;
store_count--;
if (store_count == 0) {
store_inflight = false;
mem->addTransaction(true, store_addr);
wreq[store_addr].push(store_id);
assert(w_last);
}
}
if (b_fire)
bresp.pop();
if (r_fire)
rresp.pop();
mem->update();
cycle++;
}

View File

@ -1,75 +0,0 @@
// See LICENSE for license details.
#ifndef _MM_EMULATOR_DRAMSIM2_H
#define _MM_EMULATOR_DRAMSIM2_H
#include "mm.h"
#include <DRAMSim.h>
#include <map>
#include <queue>
#include <stdint.h>
class mm_dramsim2_t : public mm_t
{
public:
mm_dramsim2_t() : store_inflight(false) {}
virtual void init(size_t sz, int word_size, int line_size);
virtual bool ar_ready() { return mem->willAcceptTransaction(); }
virtual bool aw_ready() { return mem->willAcceptTransaction() && !store_inflight; }
virtual bool w_ready() { return store_inflight; }
virtual bool b_valid() { return !bresp.empty(); }
virtual uint64_t b_resp() { return 0; }
virtual uint64_t b_id() { return b_valid() ? bresp.front() : 0; }
virtual bool r_valid() { return !rresp.empty(); }
virtual uint64_t r_resp() { return 0; }
virtual uint64_t r_id() { return r_valid() ? rresp.front().id: 0; }
virtual void *r_data() { return r_valid() ? &rresp.front().data[0] : &dummy_data[0]; }
virtual bool r_last() { return r_valid() ? rresp.front().last : false; }
virtual void tick
(
bool ar_valid,
uint64_t ar_addr,
uint64_t ar_id,
uint64_t ar_size,
uint64_t ar_len,
bool aw_valid,
uint64_t aw_addr,
uint64_t aw_id,
uint64_t aw_size,
uint64_t aw_len,
bool w_valid,
uint64_t w_strb,
void *w_data,
bool w_last,
bool r_ready,
bool b_ready
);
protected:
DRAMSim::MultiChannelMemorySystem *mem;
uint64_t cycle;
bool store_inflight;
uint64_t store_addr;
uint64_t store_id;
uint64_t store_size;
uint64_t store_count;
std::vector<char> dummy_data;
std::queue<uint64_t> bresp;
std::map<uint64_t, std::queue<uint64_t> > wreq;
std::map<uint64_t, std::queue<mm_rresp_t> > rreq;
std::queue<mm_rresp_t> rresp;
void read_complete(unsigned id, uint64_t address, uint64_t clock_cycle);
void write_complete(unsigned id, uint64_t address, uint64_t clock_cycle);
};
#endif

View File

@ -1,209 +0,0 @@
// See LICENSE for license details.
#include "mm.h"
#include "mm_dramsim2.h"
#include <fesvr/dtm.h>
#include <assert.h>
#include <DirectC.h>
#include <stdio.h>
#include <stdlib.h>
#include <vector>
#include <sstream>
#include <iterator>
extern "C" {
extern int vcs_main(int argc, char** argv);
static dtm_t* dtm;
static mm_t* mm[N_MEM_CHANNELS];
static const char* loadmem;
static bool dramsim = false;
static int memory_channel_mux_select = 0;
int main(int argc, char** argv)
{
for (int i = 1; i < argc; i++)
{
if (!strcmp(argv[i], "+dramsim"))
dramsim = true;
else if (!strncmp(argv[i], "+loadmem=", 9))
loadmem = argv[i]+9;
else if (!strncmp(argv[i], "+memory_channel_mux_select=", 27))
memory_channel_mux_select = atoi(argv[i]+27);
}
dtm = new dtm_t(std::vector<std::string>(argv + 1, argv + argc));
for (int i=0; i<N_MEM_CHANNELS; i++) {
mm[i] = dramsim ? (mm_t*)(new mm_dramsim2_t) : (mm_t*)(new mm_magic_t);
mm[i]->init(MEM_SIZE / N_MEM_CHANNELS, MEM_DATA_BITS / 8, CACHE_BLOCK_BYTES);
}
if (loadmem) {
void *mems[N_MEM_CHANNELS];
for (int i = 0; i < N_MEM_CHANNELS; i++)
mems[i] = mm[i]->get_data();
load_mem(mems, loadmem, CACHE_BLOCK_BYTES, N_MEM_CHANNELS);
}
vcs_main(argc, argv);
abort(); // should never get here
}
void memory_tick(
vc_handle channel,
vc_handle ar_valid,
vc_handle ar_ready,
vc_handle ar_addr,
vc_handle ar_id,
vc_handle ar_size,
vc_handle ar_len,
vc_handle aw_valid,
vc_handle aw_ready,
vc_handle aw_addr,
vc_handle aw_id,
vc_handle aw_size,
vc_handle aw_len,
vc_handle w_valid,
vc_handle w_ready,
vc_handle w_strb,
vc_handle w_data,
vc_handle w_last,
vc_handle r_valid,
vc_handle r_ready,
vc_handle r_resp,
vc_handle r_id,
vc_handle r_data,
vc_handle r_last,
vc_handle b_valid,
vc_handle b_ready,
vc_handle b_resp,
vc_handle b_id)
{
int c = vc_4stVectorRef(channel)->d;
assert(c < N_MEM_CHANNELS);
mm_t* mmc = mm[c];
uint32_t write_data[mmc->get_word_size()/sizeof(uint32_t)];
for (size_t i = 0; i < mmc->get_word_size()/sizeof(uint32_t); i++)
write_data[i] = vc_4stVectorRef(w_data)[i].d;
uint32_t aw_id_val, ar_id_val;
if (MEM_ID_BITS == 1) {
aw_id_val = vc_getScalar(aw_id);
ar_id_val = vc_getScalar(ar_id);
} else {
aw_id_val = vc_4stVectorRef(aw_id)->d;
ar_id_val = vc_4stVectorRef(ar_id)->d;
}
mmc->tick
(
vc_getScalar(ar_valid),
vc_4stVectorRef(ar_addr)->d - MEM_BASE,
ar_id_val,
vc_4stVectorRef(ar_size)->d,
vc_4stVectorRef(ar_len)->d,
vc_getScalar(aw_valid),
vc_4stVectorRef(aw_addr)->d - MEM_BASE,
aw_id_val,
vc_4stVectorRef(aw_size)->d,
vc_4stVectorRef(aw_len)->d,
vc_getScalar(w_valid),
vc_4stVectorRef(w_strb)->d,
write_data,
vc_getScalar(w_last),
vc_getScalar(r_ready),
vc_getScalar(b_ready)
);
vc_putScalar(ar_ready, mmc->ar_ready());
vc_putScalar(aw_ready, mmc->aw_ready());
vc_putScalar(w_ready, mmc->w_ready());
vc_putScalar(b_valid, mmc->b_valid());
vc_putScalar(r_valid, mmc->r_valid());
vc_putScalar(r_last, mmc->r_last());
vec32 d[mmc->get_word_size()/sizeof(uint32_t)];
d[0].c = 0;
d[0].d = mmc->b_resp();
vc_put4stVector(b_resp, d);
d[0].c = 0;
d[0].d = mmc->r_resp();
vc_put4stVector(r_resp, d);
if (MEM_ID_BITS > 1) {
d[0].c = 0;
d[0].d = mmc->b_id();
vc_put4stVector(b_id, d);
d[0].c = 0;
d[0].d = mmc->r_id();
vc_put4stVector(r_id, d);
} else {
vc_putScalar(b_id, mmc->b_id());
vc_putScalar(r_id, mmc->r_id());
}
for (size_t i = 0; i < mmc->get_word_size()/sizeof(uint32_t); i++)
{
d[i].c = 0;
d[i].d = ((uint32_t*)mmc->r_data())[i];
}
vc_put4stVector(r_data, d);
}
void debug_tick
(
vc_handle debug_req_valid,
vc_handle debug_req_ready,
vc_handle debug_req_bits_addr,
vc_handle debug_req_bits_op,
vc_handle debug_req_bits_data,
vc_handle debug_resp_valid,
vc_handle debug_resp_ready,
vc_handle debug_resp_bits_resp,
vc_handle debug_resp_bits_data,
vc_handle exit
)
{
vec32 tmp[2];
dtm_t::resp resp_bits;
vc_get4stVector(debug_resp_bits_resp, tmp);
resp_bits.resp = tmp[0].d;
vc_get4stVector(debug_resp_bits_data, tmp);
resp_bits.data = tmp[0].d | ((uint64_t)tmp[1].d << 32);
dtm->tick
(
vc_getScalar(debug_req_ready),
vc_getScalar(debug_resp_valid),
resp_bits
);
vc_putScalar(debug_resp_ready, dtm->resp_ready());
vc_putScalar(debug_req_valid, dtm->req_valid());
tmp[0].d = dtm->req_bits().addr;
vc_put4stVector(debug_req_bits_addr, tmp);
tmp[0].d = dtm->req_bits().op;
vc_put4stVector(debug_req_bits_op, tmp);
tmp[0].d = dtm->req_bits().data;
tmp[1].d = dtm->req_bits().data >> 32;
vc_put4stVector(debug_req_bits_data, tmp);
tmp[0].d = dtm->done() ? (dtm->exit_code() << 1 | 1) : 0;
vc_put4stVector(exit, tmp);
}
}