From 46f2fb1d9e33b4cf98c2cc15c2a2da14f0e3580d Mon Sep 17 00:00:00 2001 From: Andrew Waterman Date: Sat, 30 Apr 2011 23:44:59 -0700 Subject: [PATCH] [sim] hacked in a dcache simulator --- riscv/icsim.cc | 91 +++++++++++++++++++++++++++++++----------- riscv/icsim.h | 34 +++++++++++++--- riscv/mmu.h | 34 +++++++++++++++- riscv/processor.cc | 34 +++++++++++++--- riscv/processor.h | 7 +++- riscv/riscv-isa-run.cc | 24 +++++++++-- riscv/sim.cc | 4 +- riscv/sim.h | 2 +- 8 files changed, 187 insertions(+), 43 deletions(-) diff --git a/riscv/icsim.cc b/riscv/icsim.cc index 73d6e9c..308e7ed 100644 --- a/riscv/icsim.cc +++ b/riscv/icsim.cc @@ -3,53 +3,98 @@ #include #include -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; } diff --git a/riscv/icsim.h b/riscv/icsim.h index 122730c..48931f5 100644 --- a/riscv/icsim.h +++ b/riscv/icsim.h @@ -2,29 +2,51 @@ #define _RISCV_ICSIM_H #include +#include #include +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 diff --git a/riscv/mmu.h b/riscv/mmu.h index 289c200..f8ee597 100644 --- a/riscv/mmu.h +++ b/riscv/mmu.h @@ -1,22 +1,42 @@ #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; \ } @@ -30,6 +50,13 @@ public: 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); @@ -59,6 +86,11 @@ private: 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)) diff --git a/riscv/processor.cc b/riscv/processor.cc index 471afab..4494c59 100644 --- a/riscv/processor.cc +++ b/riscv/processor.cc @@ -53,14 +53,32 @@ processor_t::processor_t(sim_t* _sim, char* _mem, size_t _memsz) 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; @@ -74,7 +92,16 @@ void processor_t::init(uint32_t _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 } @@ -134,9 +161,6 @@ void processor_t::step(size_t n, bool noisy) 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); diff --git a/riscv/processor.h b/riscv/processor.h index 5c524c0..e92d093 100644 --- a/riscv/processor.h +++ b/riscv/processor.h @@ -16,7 +16,7 @@ class processor_t 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: @@ -73,8 +73,11 @@ 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; }; diff --git a/riscv/riscv-isa-run.cc b/riscv/riscv-isa-run.cc index 83bb286..c14cbbb 100644 --- a/riscv/riscv-isa-run.cc +++ b/riscv/riscv-isa-run.cc @@ -9,8 +9,9 @@ int main(int argc, char** argv) 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) { @@ -26,15 +27,32 @@ int main(int argc, char** argv) 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); diff --git a/riscv/sim.cc b/riscv/sim.cc index 7ac60c1..c503ccb 100644 --- a/riscv/sim.cc +++ b/riscv/sim.cc @@ -6,7 +6,7 @@ #include #include -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)), @@ -15,7 +15,7 @@ sim_t::sim_t(int _nprocs, size_t _memsz, appserver_link_t* _applink) 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); } diff --git a/riscv/sim.h b/riscv/sim.h index a471500..c3f308e 100644 --- a/riscv/sim.h +++ b/riscv/sim.h @@ -12,7 +12,7 @@ class appserver_link_t; 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); -- 2.30.2