#include <iostream>
#include <iomanip>
-icsim_t::icsim_t(size_t _sets, size_t _ways, size_t _linesz)
+icsim_t::icsim_t(size_t _sets, size_t _ways, size_t _linesz, const char* _name)
+ : sets(_sets), ways(_ways), linesz(_linesz), idx_mask(_sets-1), name(_name)
{
- sets = _sets;
- ways = _ways;
- linesz = _linesz;
-
if(sets == 0 || (sets & (sets-1)))
throw std::logic_error("sets not a power of 2");
if(linesz == 0 || (linesz & (linesz-1)))
throw std::logic_error("linesz not a power of 2");
- if(ways != 1)
- throw std::logic_error("set associativity currently unsupported");
- idx_mask = sets-1;
idx_shift = 0;
while(_linesz >>= 1)
idx_shift++;
tags = new uint64_t[sets*ways];
memset(tags, 0, sets*ways*sizeof(uint64_t));
+
+ read_accesses = 0;
+ read_misses = 0;
+ bytes_read = 0;
+ write_accesses = 0;
+ write_misses = 0;
+ bytes_written = 0;
+ writebacks = 0;
+}
+
+icsim_t::icsim_t(const icsim_t& rhs)
+ : sets(rhs.sets), ways(rhs.ways), linesz(rhs.linesz),
+ idx_shift(rhs.idx_shift), idx_mask(rhs.idx_mask), name(rhs.name)
+{
+ tags = new uint64_t[sets*ways];
+ memcpy(tags, rhs.tags, sets*ways*sizeof(uint64_t));
}
icsim_t::~icsim_t()
{
- float mr = 100.0f*misses/accesses;
- float cr = 100.0f*bytes_fetched/(4*accesses);
+ delete [] tags;
+}
- std::cout << "Instruction cache statsistics" << std::endl;
- std::cout << "Bytes fetched: " << bytes_fetched << std::endl;
- std::cout << "Hits: " << (accesses-misses) << std::endl;
- std::cout << "Misses: " << misses << std::endl;
- std::cout << "Miss rate: " << std::setprecision(3) << mr << '%' << std::endl;
- std::cout << "RVC compression ratio: " << cr << '%' << std::endl;
+void icsim_t::print_stats()
+{
+ if(read_accesses + write_accesses == 0)
+ return;
- delete [] tags;
+ float mr = 100.0f*(read_misses+write_misses)/(read_accesses+write_accesses);
+
+ std::cout << std::setprecision(3) << std::fixed;
+ std::cout << name << " ";
+ std::cout << "Bytes Read: " << bytes_read << std::endl;
+ std::cout << name << " ";
+ std::cout << "Bytes Written: " << bytes_written << std::endl;
+ std::cout << name << " ";
+ std::cout << "Read Accesses: " << read_accesses << std::endl;
+ std::cout << name << " ";
+ std::cout << "Write Accesses: " << write_accesses << std::endl;
+ std::cout << name << " ";
+ std::cout << "Read Misses: " << read_misses << std::endl;
+ std::cout << name << " ";
+ std::cout << "Write Misses: " << write_misses << std::endl;
+ std::cout << name << " ";
+ std::cout << "Writebacks: " << writebacks << std::endl;
+ std::cout << name << " ";
+ std::cout << "Miss Rate: " << mr << '%' << std::endl;
+
+ float cr = read_accesses == 0 ? 0.0f : 100.0f*bytes_read/(4*read_accesses);
+ if(name == "I$")
+ {
+ std::cout << name << " ";
+ std::cout << "RVC compression ratio: " << cr << '%' << std::endl;
+ }
}
-void icsim_t::tick(uint64_t pc, int insnlen)
+void icsim_t::tick(uint64_t pc, int insnlen, bool store)
{
- accesses++;
- bytes_fetched += insnlen;
+ store ? write_accesses++ : read_accesses++;
+ (store ? bytes_written : bytes_read) += insnlen;
size_t idx = (pc >> idx_shift) & idx_mask;
size_t tag = (pc >> idx_shift) | VALID;
- if(tag != tags[idx])
+
+ for(size_t i = 0; i < ways; i++)
{
- misses++;
- tags[idx] = tag;
+ if(tag == (tags[idx + i*sets] & ~DIRTY)) // hit
+ {
+ if(store)
+ tags[idx + i*sets] |= DIRTY;
+ return;
+ }
}
+
+ store ? write_misses++ : read_misses++;
+
+ size_t way = lfsr.next() % ways;
+ if((tags[idx + way*sets] & (VALID | DIRTY)) == (VALID | DIRTY))
+ writebacks++;
+ tags[idx + way*sets] = tag;
}
#define _RISCV_ICSIM_H
#include <cstring>
+#include <string>
#include <stdint.h>
+class lfsr_t
+{
+public:
+ lfsr_t() : reg(1) {}
+ lfsr_t(const lfsr_t& lfsr) : reg(lfsr.reg) {}
+ uint32_t next() { return reg = (reg>>1)^(-(reg&1) & 0xd0000001); }
+private:
+ uint32_t reg;
+};
+
class icsim_t
{
public:
- icsim_t(size_t sets, size_t ways, size_t linesz);
+ icsim_t(size_t sets, size_t ways, size_t linesz, const char* name);
+ icsim_t(const icsim_t& rhs);
~icsim_t();
- void tick(uint64_t pc, int insnlen);
+ void tick(uint64_t pc, int insnlen, bool store);
+ void print_stats();
private:
+ lfsr_t lfsr;
+
size_t sets;
size_t ways;
size_t linesz;
size_t idx_shift;
size_t idx_mask;
-
- uint64_t accesses;
- uint64_t misses;
- uint64_t bytes_fetched;
uint64_t* tags;
+
+ uint64_t read_accesses;
+ uint64_t read_misses;
+ uint64_t bytes_read;
+ uint64_t write_accesses;
+ uint64_t write_misses;
+ uint64_t bytes_written;
+ uint64_t writebacks;
+
+ std::string name;
static const uint64_t VALID = 1ULL << 63;
+ static const uint64_t DIRTY = 1ULL << 62;
};
#endif
#include "decode.h"
#include "trap.h"
+#include "icsim.h"
class processor_t;
class mmu_t
{
public:
- mmu_t(char* _mem, size_t _memsz) : mem(_mem), memsz(_memsz), badvaddr(0) {}
+ mmu_t(char* _mem, size_t _memsz)
+ : mem(_mem), memsz(_memsz), badvaddr(0),
+ icsim(NULL), dcsim(NULL), itlbsim(NULL), dtlbsim(NULL)
+ {
+ }
+
+ void set_icsim(icsim_t* _icsim) { icsim = _icsim; }
+ void set_dcsim(icsim_t* _dcsim) { dcsim = _dcsim; }
+ void set_itlbsim(icsim_t* _itlbsim) { itlbsim = _itlbsim; }
+ void set_dtlbsim(icsim_t* _dtlbsim) { dtlbsim = _dtlbsim; }
+
+ #ifdef RISCV_ENABLE_ICSIM
+ # define dcsim_tick(dcsim, dtlbsim, addr, size, st) \
+ do { if(dcsim) (dcsim)->tick(addr, size, st); \
+ if(dtlbsim) (dtlbsim)->tick(addr, sizeof(reg_t), false); } while(0)
+ #else
+ # define dcsim_tick(dcsim, addr, size)
+ #endif
#define load_func(type) \
type##_t load_##type(reg_t addr) { \
check_align_and_bounds(addr, sizeof(type##_t), false, false); \
+ dcsim_tick(dcsim, dtlbsim, addr, sizeof(type##_t), false); \
return *(type##_t*)(mem+addr); \
}
#define store_func(type) \
void store_##type(reg_t addr, type##_t val) { \
check_align_and_bounds(addr, sizeof(type##_t), true, false); \
+ dcsim_tick(dcsim, dtlbsim, addr, sizeof(type##_t), true); \
*(type##_t*)(mem+addr) = val; \
}
insn_t insn;
insn.bits = lo | ((uint32_t)hi << 16);
+ #ifdef RISCV_ENABLE_ICSIM
+ if(icsim)
+ icsim->tick(addr, insn_length(insn), false);
+ if(itlbsim)
+ itlbsim->tick(addr, sizeof(reg_t), false);
+ #endif
+
return insn;
#else
check_align_and_bounds(addr, 4, false, true);
size_t memsz;
reg_t badvaddr;
+ icsim_t* icsim;
+ icsim_t* dcsim;
+ icsim_t* itlbsim;
+ icsim_t* dtlbsim;
+
void check_align(reg_t addr, int size, bool store, bool fetch)
{
if(addr & (size-1))
static_assert(sizeof(uint128_t) == 16 && sizeof(int128_t) == 16);
icsim = NULL;
+ dcsim = NULL;
+ itlbsim = NULL;
+ dtlbsim = NULL;
}
processor_t::~processor_t()
{
+ if(icsim)
+ icsim->print_stats();
delete icsim;
+
+ if(itlbsim)
+ itlbsim->print_stats();
+ delete itlbsim;
+
+ if(dcsim)
+ dcsim->print_stats();
+ delete dcsim;
+
+ if(dtlbsim)
+ dtlbsim->print_stats();
+ delete dtlbsim;
}
-void processor_t::init(uint32_t _id)
+void processor_t::init(uint32_t _id, icsim_t* default_icache,
+ icsim_t* default_dcache)
{
id = _id;
}
#ifdef RISCV_ENABLE_ICSIM
- icsim = new icsim_t(1024, 1, 32);
+ icsim = new icsim_t(*default_icache);
+ mmu.set_icsim(icsim);
+ itlbsim = new icsim_t(1, 8, 4096, "ITLB");
+ mmu.set_itlbsim(itlbsim);
+ #endif
+ #ifdef RISCV_ENABLE_ICSIM
+ dcsim = new icsim_t(*default_dcache);
+ mmu.set_dcsim(dcsim);
+ dtlbsim = new icsim_t(1, 8, 4096, "DTLB");
+ mmu.set_dtlbsim(dtlbsim);
#endif
}
take_trap(trap_interrupt,noisy);
insn_t insn = mmu.load_insn(pc, sr & SR_EC);
- #ifdef RISCV_ENABLE_ICSIM
- icsim->tick(pc, insn_length(insn));
- #endif
reg_t npc = pc + insn_length(insn);
public:
processor_t(sim_t* _sim, char* _mem, size_t _memsz);
~processor_t();
- void init(uint32_t _id);
+ void init(uint32_t _id, icsim_t* defualt_icache, icsim_t* default_dcache);
void step(size_t n, bool noisy);
private:
int nfpr_use;
processor_t* uts[MAX_UTS];
- // icache sim
+ // cache sim
icsim_t* icsim;
+ icsim_t* dcsim;
+ icsim_t* itlbsim;
+ icsim_t* dtlbsim;
friend class sim_t;
};
bool debug = false;
int nprocs = 1;
int fromhost_fd = -1, tohost_fd = -1;
+ size_t icsim_sets = 1024, icsim_linesz = 32, icsim_ways = 1;
- for(int c; (c = getopt(argc,argv,"dpf:t:")) != -1; )
+ for(int c; (c = getopt(argc,argv,"dp:f:t:i:")) != -1; )
{
switch(c)
{
case 't':
tohost_fd = atoi(optarg);
break;
+ case 'i':
+ switch(optarg[0])
+ {
+ case 's':
+ icsim_sets = atoi(optarg+1);
+ break;
+ case 'l':
+ icsim_linesz = atoi(optarg+1);
+ break;
+ case 'a':
+ icsim_ways = atoi(optarg+1);
+ break;
+ }
+ break;
}
}
demand(fcntl(fromhost_fd,F_GETFD) >= 0, "fromhost file not open");
demand(fcntl(tohost_fd,F_GETFD) >= 0, "tohost file not open");
- appserver_link_t applink(tohost_fd,fromhost_fd);
+ icsim_t icache(icsim_sets, icsim_ways, icsim_linesz, "I$");
+ icsim_t dcache(512, 2, 32, "D$");
+
+ appserver_link_t applink(tohost_fd, fromhost_fd);
- sim_t s(nprocs,MEMSIZE,&applink);
+ sim_t s(nprocs, MEMSIZE, &applink, &icache, &dcache);
try
{
s.run(debug);
#include <iostream>
#include <climits>
-sim_t::sim_t(int _nprocs, size_t _memsz, appserver_link_t* _applink)
+sim_t::sim_t(int _nprocs, size_t _memsz, appserver_link_t* _applink, icsim_t* default_icache, icsim_t* default_dcache)
: applink(_applink),
memsz(_memsz),
mem((char*)mmap64(NULL, memsz, PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0)),
demand(mem != MAP_FAILED, "couldn't allocate target machine's memory");
for(int i = 0; i < (int)procs.size(); i++)
- procs[i].init(i);
+ procs[i].init(i, default_icache, default_dcache);
applink->init(this);
}
class sim_t
{
public:
- sim_t(int _nprocs, size_t _memsz, appserver_link_t* _applink);
+ sim_t(int _nprocs, size_t _memsz, appserver_link_t* _applink, icsim_t* _default_icache, icsim_t* default_dcache);
~sim_t();
void run(bool debug);