hw unit tests fixes
This commit is contained in:
77
hw/unittest/cache/Makefile
vendored
Normal file
77
hw/unittest/cache/Makefile
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
DESTDIR ?= .
|
||||
RTL_DIR = ../../rtl
|
||||
DPI_DIR = ../../dpi
|
||||
|
||||
CONFIGS +=
|
||||
PARAMS +=
|
||||
|
||||
CXXFLAGS += -std=c++11 -Wall -Wextra -Wfatal-errors -Wno-array-bounds
|
||||
CXXFLAGS += -fPIC -Wno-maybe-uninitialized
|
||||
CXXFLAGS += -I../../.. -I../../common -I../../../../sim/common
|
||||
CXXFLAGS += $(CONFIGS)
|
||||
|
||||
LDFLAGS +=
|
||||
|
||||
# control RTL debug tracing states
|
||||
DBG_TRACE_FLAGS += -DDBG_TRACE_CACHE_BANK
|
||||
DBG_TRACE_FLAGS += -DDBG_TRACE_CACHE_MSHR
|
||||
DBG_TRACE_FLAGS += -DDBG_TRACE_CACHE_TAG
|
||||
DBG_TRACE_FLAGS += -DDBG_TRACE_CACHE_DATA
|
||||
|
||||
DBG_FLAGS += -DDEBUG_LEVEL=$(DEBUG) -DVCD_OUTPUT $(DBG_TRACE_FLAGS)
|
||||
|
||||
RTL_PKGS = $(RTL_DIR)/VX_gpu_pkg.sv
|
||||
|
||||
RTL_INCLUDE = -I$(RTL_DIR) -I$(DPI_DIR) -I$(RTL_DIR)/libs -I$(RTL_DIR)/interfaces -I$(RTL_DIR)/mem -I$(RTL_DIR)/cache
|
||||
|
||||
SRCS = cachesim.cpp testbench.cpp
|
||||
SRCS += $(DPI_DIR)/util_dpi.cpp
|
||||
|
||||
TOP = VX_cache_top
|
||||
|
||||
VL_FLAGS = --exe
|
||||
VL_FLAGS += --language 1800-2009 --assert -Wall -Wpedantic
|
||||
VL_FLAGS += -Wno-DECLFILENAME -Wno-REDEFMACRO
|
||||
VL_FLAGS += --x-initial unique --x-assign unique
|
||||
VL_FLAGS += -DSIMULATION
|
||||
VL_FLAGS += $(CONFIGS)
|
||||
VL_FLAGS += $(PARAMS)
|
||||
VL_FLAGS += $(RTL_INCLUDE)
|
||||
VL_FLAGS += $(RTL_PKGS)
|
||||
VL_FLAGS += --cc $(TOP) --top-module $(TOP)
|
||||
|
||||
# Enable Verilator multithreaded simulation
|
||||
THREADS ?= $(shell python -c 'import multiprocessing as mp; print(mp.cpu_count())')
|
||||
VL_FLAGS += -j $(THREADS)
|
||||
#VL_FLAGS += --threads $(THREADS)
|
||||
|
||||
# Debugigng
|
||||
ifdef DEBUG
|
||||
VL_FLAGS += --trace --trace-structs $(DBG_FLAGS)
|
||||
CXXFLAGS += -g -O0 $(DBG_FLAGS)
|
||||
else
|
||||
VL_FLAGS += -DNDEBUG
|
||||
CXXFLAGS += -O2 -DNDEBUG
|
||||
endif
|
||||
|
||||
# Enable perf counters
|
||||
ifdef PERF
|
||||
VL_FLAGS += -DPERF_ENABLE
|
||||
CXXFLAGS += -DPERF_ENABLE
|
||||
endif
|
||||
|
||||
PROJECT = cache
|
||||
|
||||
all: $(DESTDIR)/$(PROJECT)
|
||||
|
||||
$(DESTDIR)/$(PROJECT): $(SRCS)
|
||||
verilator --build $(VL_FLAGS) $^ -CFLAGS '$(CXXFLAGS)' -o ../$@
|
||||
|
||||
run: $(DESTDIR)/$(PROJECT)
|
||||
$(DESTDIR)/$(PROJECT)
|
||||
|
||||
waves: trace.vcd
|
||||
gtkwave -o trace.vcd
|
||||
|
||||
clean:
|
||||
rm -rf obj_dir $(DESTDIR)/$(PROJECT)
|
||||
353
hw/unittest/cache/cachesim.cpp
vendored
Normal file
353
hw/unittest/cache/cachesim.cpp
vendored
Normal file
@@ -0,0 +1,353 @@
|
||||
// Copyright © 2019-2023
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "cachesim.h"
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <bitset>
|
||||
|
||||
#ifndef TRACE_START_TIME
|
||||
#define TRACE_START_TIME 0ull
|
||||
#endif
|
||||
|
||||
#ifndef TRACE_STOP_TIME
|
||||
#define TRACE_STOP_TIME -1ull
|
||||
#endif
|
||||
|
||||
static uint64_t timestamp = 0;
|
||||
static bool trace_enabled = false;
|
||||
static uint64_t trace_start_time = TRACE_START_TIME;
|
||||
static uint64_t trace_stop_time = TRACE_STOP_TIME;
|
||||
|
||||
double sc_time_stamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
bool sim_trace_enabled() {
|
||||
if (timestamp >= trace_start_time
|
||||
&& timestamp < trace_stop_time)
|
||||
return true;
|
||||
return trace_enabled;
|
||||
}
|
||||
|
||||
void sim_trace_enable(bool enable) {
|
||||
trace_enabled = enable;
|
||||
}
|
||||
|
||||
CacheSim::CacheSim() {
|
||||
// force random values for uninitialized signals
|
||||
Verilated::randReset(2);
|
||||
|
||||
ram_ = nullptr;
|
||||
cache_ = new VVX_cache_top();
|
||||
|
||||
mem_rsp_active_ = false;
|
||||
snp_req_active_ = false;
|
||||
|
||||
#ifdef VCD_OUTPUT
|
||||
Verilated::traceEverOn(true);
|
||||
trace_ = new VerilatedVcdC;
|
||||
cache_->trace(trace_, 99);
|
||||
trace_->open("trace.vcd");
|
||||
#endif
|
||||
}
|
||||
|
||||
CacheSim::~CacheSim() {
|
||||
#ifdef VCD_OUTPUT
|
||||
trace_->close();
|
||||
#endif
|
||||
delete cache_;
|
||||
//need to delete the req and rsp vectors
|
||||
}
|
||||
|
||||
void CacheSim::attach_ram(RAM* ram) {
|
||||
ram_ = ram;
|
||||
mem_rsp_vec_.clear();
|
||||
}
|
||||
|
||||
void CacheSim::reset() {
|
||||
#ifndef NDEBUG
|
||||
std::cout << timestamp << ": [sim] reset()" << std::endl;
|
||||
#endif
|
||||
|
||||
cache_->reset = 1;
|
||||
this->step();
|
||||
cache_->reset = 0;
|
||||
this->step();
|
||||
|
||||
mem_rsp_vec_.clear();
|
||||
//clear req and rsp vecs
|
||||
|
||||
}
|
||||
|
||||
void CacheSim::step() {
|
||||
//std::cout << timestamp << ": [sim] step()" << std::endl;
|
||||
//toggle clock
|
||||
cache_->clk = 0;
|
||||
this->eval();
|
||||
|
||||
cache_->clk = 1;
|
||||
this->eval();
|
||||
|
||||
//handle core and memory reqs and rsps
|
||||
this->eval_reqs();
|
||||
this->eval_rsps();
|
||||
this->eval_mem_bus();
|
||||
timestamp++;
|
||||
}
|
||||
|
||||
void CacheSim::eval() {
|
||||
cache_->eval();
|
||||
#ifdef VCD_OUTPUT
|
||||
trace_->dump(timestamp);
|
||||
#endif
|
||||
++timestamp;
|
||||
}
|
||||
|
||||
void CacheSim::run(){
|
||||
//#ifndef NDEBUG
|
||||
|
||||
//#endif
|
||||
this->step();
|
||||
|
||||
int valid = 300;
|
||||
int stalls = 20 + 10;
|
||||
|
||||
while (valid > -1) {
|
||||
|
||||
this->step();
|
||||
display_miss();
|
||||
if(cache_->core_rsp_valid){
|
||||
get_core_rsp();
|
||||
}
|
||||
|
||||
if(!cache_->core_req_valid && !cache_->core_rsp_valid){
|
||||
valid--;
|
||||
|
||||
}
|
||||
stalls--;
|
||||
if (stalls == 20){
|
||||
//stall_mem();
|
||||
//send_snoop_req();
|
||||
stalls--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CacheSim::clear_req(){
|
||||
cache_->core_req_valid = 0;
|
||||
}
|
||||
|
||||
void CacheSim::send_req(core_req_t *req){
|
||||
core_req_vec_.push(req);
|
||||
unsigned int *data = new unsigned int[4];
|
||||
core_rsp_vec_.insert(std::pair<unsigned int, unsigned int*>(req->tag, data));
|
||||
}
|
||||
|
||||
bool CacheSim::get_core_req_ready(){
|
||||
return cache_->core_req_ready;
|
||||
}
|
||||
|
||||
bool CacheSim::get_core_rsp_ready(){
|
||||
return cache_->core_rsp_ready;
|
||||
}
|
||||
|
||||
void CacheSim::eval_reqs(){
|
||||
//check to see if cache is accepting reqs
|
||||
if(!core_req_vec_.empty() && cache_->core_req_ready){
|
||||
core_req_t *req = core_req_vec_.front();
|
||||
|
||||
cache_->core_req_valid = req->valid;
|
||||
cache_->core_req_rw = req->rw;
|
||||
cache_->core_req_byteen = req->byteen;
|
||||
|
||||
cache_->core_req_addr[0] = req->addr[0];
|
||||
cache_->core_req_addr[1] = req->addr[1];
|
||||
cache_->core_req_addr[2] = req->addr[2];
|
||||
cache_->core_req_addr[3] = req->addr[3];
|
||||
|
||||
cache_->core_req_data[0] = req->data[0];
|
||||
cache_->core_req_data[1] = req->data[1];
|
||||
cache_->core_req_data[2] = req->data[2];
|
||||
cache_->core_req_data[3] = req->data[3];
|
||||
|
||||
cache_->core_req_tag = req->tag;
|
||||
|
||||
core_req_vec_.pop();
|
||||
|
||||
} else {
|
||||
clear_req();
|
||||
}
|
||||
}
|
||||
|
||||
void CacheSim::eval_rsps(){
|
||||
//check to see if a request has been responded to
|
||||
if (cache_->core_rsp_valid){
|
||||
core_rsp_vec_.at(cache_->core_rsp_tag)[0] = cache_->core_rsp_data[0];
|
||||
core_rsp_vec_.at(cache_->core_rsp_tag)[1] = cache_->core_rsp_data[1];
|
||||
core_rsp_vec_.at(cache_->core_rsp_tag)[2] = cache_->core_rsp_data[2];
|
||||
core_rsp_vec_.at(cache_->core_rsp_tag)[3] = cache_->core_rsp_data[3];
|
||||
}
|
||||
}
|
||||
|
||||
void CacheSim::stall_mem(){
|
||||
cache_->mem_req_ready = 0;
|
||||
}
|
||||
|
||||
void CacheSim::send_snoop_req(){
|
||||
/*cache_->snp_req_valid = 1;
|
||||
cache_->snp_req_addr = 0x12222222;
|
||||
cache_->snp_req_invalidate = 1;
|
||||
cache_->snp_req_tag = 0xff; */
|
||||
}
|
||||
|
||||
void CacheSim::eval_mem_bus() {
|
||||
if (ram_ == nullptr) {
|
||||
cache_->mem_req_ready = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// schedule memory responses
|
||||
int dequeue_index = -1;
|
||||
for (int i = 0; i < mem_rsp_vec_.size(); i++) {
|
||||
if (mem_rsp_vec_[i].cycles_left > 0) {
|
||||
mem_rsp_vec_[i].cycles_left -= 1;
|
||||
}
|
||||
if ((dequeue_index == -1)
|
||||
&& (mem_rsp_vec_[i].cycles_left == 0)) {
|
||||
dequeue_index = i;
|
||||
}
|
||||
}
|
||||
|
||||
// send memory response
|
||||
if (mem_rsp_active_
|
||||
&& cache_->mem_rsp_valid
|
||||
&& cache_->mem_rsp_ready) {
|
||||
mem_rsp_active_ = false;
|
||||
}
|
||||
if (!mem_rsp_active_) {
|
||||
if (dequeue_index != -1) { //time to respond to the request
|
||||
cache_->mem_rsp_valid = 1;
|
||||
|
||||
//copy data from the rsp queue to the cache module
|
||||
memcpy(cache_->mem_rsp_data.data(), mem_rsp_vec_[dequeue_index].data, MEM_BLOCK_SIZE);
|
||||
|
||||
cache_->mem_rsp_tag = mem_rsp_vec_[dequeue_index].tag;
|
||||
free(mem_rsp_vec_[dequeue_index].data); //take data out of the queue
|
||||
mem_rsp_vec_.erase(mem_rsp_vec_.begin() + dequeue_index);
|
||||
mem_rsp_active_ = true;
|
||||
} else {
|
||||
cache_->mem_rsp_valid = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// handle memory stalls
|
||||
bool mem_stalled = false;
|
||||
#ifdef ENABLE_MEM_STALLS
|
||||
if (0 == ((timestamp/2) % MEM_STALLS_MODULO)) {
|
||||
mem_stalled = true;
|
||||
} else
|
||||
if (mem_rsp_vec_.size() >= MEM_RQ_SIZE) {
|
||||
mem_stalled = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
// process memory requests
|
||||
if (!mem_stalled) {
|
||||
if (cache_->mem_req_valid) {
|
||||
if (cache_->mem_req_rw) { //write = 1
|
||||
uint64_t byteen = cache_->mem_req_byteen;
|
||||
uint64_t base_addr = (cache_->mem_req_addr * MEM_BLOCK_SIZE);
|
||||
uint8_t* data = reinterpret_cast<uint8_t*>(cache_->mem_req_data.data());
|
||||
for (int i = 0; i < MEM_BLOCK_SIZE; i++) {
|
||||
if ((byteen >> i) & 0x1) {
|
||||
(*ram_)[base_addr + i] = data[i];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
mem_req_t mem_req;
|
||||
mem_req.cycles_left = MEM_LATENCY;
|
||||
mem_req.data = (uint8_t*)malloc(MEM_BLOCK_SIZE);
|
||||
mem_req.tag = cache_->mem_req_tag;
|
||||
ram_->read(cache_->mem_req_addr * MEM_BLOCK_SIZE, MEM_BLOCK_SIZE, mem_req.data);
|
||||
mem_rsp_vec_.push_back(mem_req);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cache_->mem_req_ready = ~mem_stalled;
|
||||
}
|
||||
|
||||
bool CacheSim::assert_equal(unsigned int* data, unsigned int tag){
|
||||
int check = 0;
|
||||
unsigned int *rsp = core_rsp_vec_.at(tag);
|
||||
for (int i = 0; i < 4; ++i){
|
||||
for (int j = 0; j < 4; ++j){
|
||||
if (data[i] == rsp[j]){
|
||||
check++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return check;
|
||||
|
||||
}
|
||||
|
||||
//DEBUG
|
||||
|
||||
void CacheSim::display_miss(){
|
||||
//int i = (unsigned int)cache_->miss_vec;
|
||||
//std::bitset<8> x(i);
|
||||
//if (i) std::cout << "Miss Vec " << x << std::endl;
|
||||
//std::cout << "Miss Vec 0" << cache_->miss_vec[0] << std::endl;
|
||||
}
|
||||
|
||||
void CacheSim::get_core_req(unsigned int (&rsp)[4]){
|
||||
rsp[0] = cache_->core_rsp_data[0];
|
||||
rsp[1] = cache_->core_rsp_data[1];
|
||||
rsp[2] = cache_->core_rsp_data[2];
|
||||
rsp[3] = cache_->core_rsp_data[3];
|
||||
|
||||
//std::cout << std::hex << "core_rsp_valid: " << cache_->core_rsp_valid << std::endl;
|
||||
//std::cout << std::hex << "core_rsp_data: " << cache_->core_rsp_data << std::endl;
|
||||
//std::cout << std::hex << "core_rsp_tag: " << cache_->core_rsp_tag << std::endl;
|
||||
}
|
||||
|
||||
void CacheSim::get_core_rsp(){
|
||||
//std::cout << cache_->genblk5_BRA_0_KET_->bank->is_fill_in_pipe<< std::endl;
|
||||
char check = cache_->core_rsp_valid;
|
||||
std::cout << std::hex << "core_rsp_valid: " << (unsigned int) check << std::endl;
|
||||
std::cout << std::hex << "core_rsp_data[0]: " << cache_->core_rsp_data[0] << std::endl;
|
||||
std::cout << std::hex << "core_rsp_data[1]: " << cache_->core_rsp_data[1] << std::endl;
|
||||
std::cout << std::hex << "core_rsp_data[2]: " << cache_->core_rsp_data[2] << std::endl;
|
||||
std::cout << std::hex << "core_rsp_data[3]: " << cache_->core_rsp_data[3] << std::endl;
|
||||
std::cout << std::hex << "core_rsp_tag: " << cache_->core_rsp_tag << std::endl;
|
||||
}
|
||||
|
||||
void CacheSim::get_mem_req(){
|
||||
std::cout << std::hex << "mem_req_valid: " << cache_->mem_req_valid << std::endl;
|
||||
std::cout << std::hex << "mem_req_rw: " << cache_->mem_req_rw << std::endl;
|
||||
std::cout << std::hex << "mem_req_byteen: " << cache_->mem_req_byteen << std::endl;
|
||||
std::cout << std::hex << "mem_req_addr: " << cache_->mem_req_addr << std::endl;
|
||||
std::cout << std::hex << "mem_req_data: " << cache_->mem_req_data << std::endl;
|
||||
std::cout << std::hex << "mem_req_tag: " << cache_->mem_req_tag << std::endl;
|
||||
}
|
||||
|
||||
void CacheSim::get_mem_rsp(){
|
||||
std::cout << std::hex << "mem_rsp_valid: " << cache_->mem_rsp_valid << std::endl;
|
||||
std::cout << std::hex << "mem_rsp_data: " << cache_->mem_rsp_data << std::endl;
|
||||
std::cout << std::hex << "mem_rsp_tag: " << cache_->mem_rsp_tag << std::endl;
|
||||
std::cout << std::hex << "mem_rsp_ready: " << cache_->mem_rsp_ready << std::endl;
|
||||
}
|
||||
105
hw/unittest/cache/cachesim.h
vendored
Normal file
105
hw/unittest/cache/cachesim.h
vendored
Normal file
@@ -0,0 +1,105 @@
|
||||
// Copyright © 2019-2023
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "VVX_cache_top.h"
|
||||
#include "VVX_cache_top__Syms.h"
|
||||
#include "verilated.h"
|
||||
|
||||
#ifdef VCD_OUTPUT
|
||||
#include <verilated_vcd_c.h>
|
||||
#endif
|
||||
|
||||
#include <VX_config.h>
|
||||
#include "ram.h"
|
||||
#include <ostream>
|
||||
#include <vector>
|
||||
#include <queue>
|
||||
|
||||
#define ENABLE_MEM_STALLS
|
||||
#define MEM_LATENCY 100
|
||||
#define MEM_RQ_SIZE 16
|
||||
#define MEM_STALLS_MODULO 16
|
||||
#define MEM_BLOCK_SIZE 16
|
||||
|
||||
typedef struct {
|
||||
int cycles_left;
|
||||
uint8_t *data;
|
||||
unsigned tag;
|
||||
} mem_req_t;
|
||||
|
||||
typedef struct {
|
||||
char valid;
|
||||
char rw;
|
||||
unsigned byteen;
|
||||
unsigned *addr;
|
||||
unsigned *data;
|
||||
unsigned int tag;
|
||||
} core_req_t;
|
||||
|
||||
class CacheSim {
|
||||
public:
|
||||
|
||||
CacheSim();
|
||||
virtual ~CacheSim();
|
||||
|
||||
bool busy();
|
||||
|
||||
void reset();
|
||||
void step();
|
||||
void wait(uint32_t cycles);
|
||||
void attach_ram(RAM* ram);
|
||||
void run(); //run until all reqs are empty
|
||||
|
||||
//req/rsp
|
||||
void send_req(core_req_t *req);
|
||||
void clear_req();
|
||||
void stall_mem();
|
||||
void send_snoop_req();
|
||||
void send_snp_fwd_in();
|
||||
|
||||
//assert funcs
|
||||
bool assert_equal(unsigned int* data, unsigned int tag);
|
||||
|
||||
//debug funcs
|
||||
void get_mem_req();
|
||||
void get_core_req(unsigned int (&rsp)[4]);
|
||||
void get_core_rsp();
|
||||
bool get_core_req_ready();
|
||||
bool get_core_rsp_ready();
|
||||
void get_mem_rsp();
|
||||
void display_miss();
|
||||
|
||||
private:
|
||||
|
||||
void eval();
|
||||
void eval_reqs();
|
||||
void eval_rsps();
|
||||
void eval_mem_bus();
|
||||
|
||||
std::queue<core_req_t*> core_req_vec_;
|
||||
std::vector<mem_req_t> mem_rsp_vec_;
|
||||
std::map<unsigned int, unsigned int*> core_rsp_vec_;
|
||||
int mem_rsp_active_;
|
||||
|
||||
uint32_t snp_req_active_;
|
||||
uint32_t snp_req_size_;
|
||||
uint32_t pending_snp_reqs_;
|
||||
|
||||
VVX_cache_top *cache_;
|
||||
RAM *ram_;
|
||||
#ifdef VCD_OUTPUT
|
||||
VerilatedVcdC *trace_;
|
||||
#endif
|
||||
};
|
||||
77
hw/unittest/cache/ram.h
vendored
Normal file
77
hw/unittest/cache/ram.h
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
// Copyright © 2019-2023
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
class RAM {
|
||||
private:
|
||||
|
||||
mutable uint8_t *mem_[(1 << 12)];
|
||||
|
||||
uint8_t *get(uint32_t address) const {
|
||||
uint32_t block_addr = address >> 20;
|
||||
uint32_t block_offset = address & 0x000FFFFF;
|
||||
if (mem_[block_addr] == NULL) {
|
||||
mem_[block_addr] = new uint8_t[(1 << 20)];
|
||||
}
|
||||
return mem_[block_addr] + block_offset;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
RAM() {
|
||||
for (uint32_t i = 0; i < (1 << 12); i++) {
|
||||
mem_[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
~RAM() {
|
||||
this->clear();
|
||||
}
|
||||
|
||||
size_t size() const {
|
||||
return (1ull << 32);
|
||||
}
|
||||
|
||||
void clear() {
|
||||
for (uint32_t i = 0; i < (1 << 12); i++) {
|
||||
if (mem_[i]) {
|
||||
delete [] mem_[i];
|
||||
mem_[i] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void read(uint32_t address, uint32_t length, uint8_t *data) const {
|
||||
for (unsigned i = 0; i < length; i++) {
|
||||
data[i] = *this->get(address + i);
|
||||
}
|
||||
}
|
||||
|
||||
void write(uint32_t address, uint32_t length, const uint8_t *data) {
|
||||
for (unsigned i = 0; i < length; i++) {
|
||||
*this->get(address + i) = data[i];
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t& operator[](uint32_t address) {
|
||||
return *get(address);
|
||||
}
|
||||
|
||||
const uint8_t& operator[](uint32_t address) const {
|
||||
return *get(address);
|
||||
}
|
||||
};
|
||||
248
hw/unittest/cache/testbench.cpp
vendored
Normal file
248
hw/unittest/cache/testbench.cpp
vendored
Normal file
@@ -0,0 +1,248 @@
|
||||
// Copyright © 2019-2023
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "cachesim.h"
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
|
||||
#define VCD_OUTPUT 1
|
||||
|
||||
|
||||
int REQ_RSP(CacheSim *sim){ //verified
|
||||
unsigned int addr[4] = {0x12222222, 0xabbbbbbb, 0xcddddddd, 0xe4444444};
|
||||
unsigned int data[4] = {0xffffffff, 0x11111111, 0x22222222, 0x33333333};
|
||||
unsigned int rsp[4] = {0,0,0,0};
|
||||
char responded = 0;
|
||||
//write req
|
||||
core_req_t* write = new core_req_t;
|
||||
write->valid = 0xf;
|
||||
write->rw = 0xf;
|
||||
write->byteen = 0xffff;
|
||||
write->addr = addr;
|
||||
write->data = data;
|
||||
write->tag = 0xff;
|
||||
|
||||
//read req
|
||||
core_req_t* read = new core_req_t;
|
||||
read->valid = 0xf;
|
||||
read->rw = 0;
|
||||
read->byteen = 0xffff;
|
||||
read->addr = addr;
|
||||
read->data = addr;
|
||||
read->tag = 0xff;
|
||||
|
||||
// reset the device
|
||||
sim->reset();
|
||||
|
||||
//queue reqs
|
||||
sim->send_req(write);
|
||||
sim->send_req(read);
|
||||
|
||||
sim->run();
|
||||
|
||||
int check = sim->assert_equal(data, write->tag);
|
||||
|
||||
if (check == 4) return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int HIT_1(CacheSim *sim){
|
||||
unsigned int addr[4] = {0x12222222, 0xabbbbbbb, 0xcddddddd, 0xe4444444};
|
||||
unsigned int data[4] = {0xffffffff, 0x11111111, 0x22222222, 0x33333333};
|
||||
unsigned int rsp[4] = {0,0,0,0};
|
||||
char responded = 0;
|
||||
//write req
|
||||
core_req_t* write = new core_req_t;
|
||||
write->valid = 0xf;
|
||||
write->rw = 0xf;
|
||||
write->byteen = 0xffff;
|
||||
write->addr = addr;
|
||||
write->data = data;
|
||||
write->tag = 0x11;
|
||||
|
||||
//read req
|
||||
core_req_t* read = new core_req_t;
|
||||
read->valid = 0xf;
|
||||
read->rw = 0;
|
||||
read->byteen = 0xffff;
|
||||
read->addr = addr;
|
||||
read->data = addr;
|
||||
read->tag = 0x22;
|
||||
|
||||
// reset the device
|
||||
sim->reset();
|
||||
|
||||
//queue reqs
|
||||
sim->send_req(write);
|
||||
sim->send_req(read);
|
||||
|
||||
sim->run();
|
||||
|
||||
bool check = sim->assert_equal(data, write->tag);
|
||||
|
||||
return check;
|
||||
}
|
||||
|
||||
int MISS_1(CacheSim *sim){
|
||||
unsigned int addr1[4] = {0x12222222, 0xabbbbbbb, 0xcddddddd, 0xe4444444};
|
||||
unsigned int addr2[4] = {0x12229222, 0xabbbb4bb, 0xcddd47dd, 0xe4423544};
|
||||
unsigned int addr3[4] = {0x12223332, 0xabb454bb, 0xcdddeefd, 0xe4447744};
|
||||
unsigned int data[4] = {0xffffffff, 0x11111111, 0x22222222, 0x33333333};
|
||||
unsigned int rsp[4] = {0,0,0,0};
|
||||
char responded = 0;
|
||||
//write req
|
||||
core_req_t* write = new core_req_t;
|
||||
write->valid = 0xf;
|
||||
write->rw = 0xf;
|
||||
write->byteen = 0xffff;
|
||||
write->addr = addr1;
|
||||
write->data = data;
|
||||
write->tag = 0xff;
|
||||
|
||||
//read req
|
||||
core_req_t* read1 = new core_req_t;
|
||||
read1->valid = 0xf;
|
||||
read1->rw = 0;
|
||||
read1->byteen = 0xffff;
|
||||
read1->addr = addr1;
|
||||
read1->data = data;
|
||||
read1->tag = 0xff;
|
||||
|
||||
core_req_t* read2 = new core_req_t;
|
||||
read2->valid = 0xf;
|
||||
read2->rw = 0;
|
||||
read2->byteen = 0xffff;
|
||||
read2->addr = addr2;
|
||||
read2->data = data;
|
||||
read2->tag = 0xff;
|
||||
|
||||
core_req_t* read3 = new core_req_t;
|
||||
read3->valid = 0xf;
|
||||
read3->rw = 0;
|
||||
read3->byteen = 0xffff;
|
||||
read3->addr = addr3;
|
||||
read3->data = data;
|
||||
read3->tag = 0xff;
|
||||
|
||||
// reset the device
|
||||
sim->reset();
|
||||
|
||||
//queue reqs
|
||||
sim->send_req(write);
|
||||
sim->send_req(read1);
|
||||
sim->send_req(read2);
|
||||
sim->send_req(read3);
|
||||
|
||||
sim->run();
|
||||
|
||||
bool check = sim->assert_equal(data, write->tag);
|
||||
|
||||
return check;
|
||||
}
|
||||
int FLUSH(CacheSim *sim){
|
||||
unsigned int addr[4] = {0x12222222, 0xabbbbbbb, 0xcddddddd, 0xe4444444};
|
||||
unsigned int data[4] = {0xffffffff, 0x11111111, 0x22222222, 0x33333333};
|
||||
unsigned int rsp[4] = {0,0,0,0};
|
||||
char responded = 0;
|
||||
//write req
|
||||
core_req_t* write = new core_req_t;
|
||||
write->valid = 0xf;
|
||||
write->rw = 0xf;
|
||||
write->byteen = 0xffff;
|
||||
write->addr = addr;
|
||||
write->data = data;
|
||||
write->tag = 0xff;
|
||||
|
||||
//read req
|
||||
core_req_t* read = new core_req_t;
|
||||
read->valid = 0xf;
|
||||
read->rw = 0;
|
||||
read->byteen = 0xffff;
|
||||
read->addr = addr;
|
||||
read->data = addr;
|
||||
read->tag = 0xff;
|
||||
|
||||
// reset the device
|
||||
sim->reset();
|
||||
|
||||
//queue reqs
|
||||
sim->send_req(write);
|
||||
sim->send_req(read);
|
||||
|
||||
sim->run();
|
||||
|
||||
bool check = sim->assert_equal(data, write->tag);
|
||||
|
||||
return check;
|
||||
}
|
||||
|
||||
|
||||
int BACK_PRESSURE(CacheSim *sim){
|
||||
//happens whenever the core is stalled or memory is stalled
|
||||
unsigned int addr[4] = {0x12222222, 0xabbbbbbb, 0xcddddddd, 0xe4444444};
|
||||
unsigned int data[4] = {0xffffffff, 0x11111111, 0x22222222, 0x33333333};
|
||||
unsigned int rsp[4] = {0,0,0,0};
|
||||
char responded = 0;
|
||||
|
||||
//write req
|
||||
core_req_t* write = new core_req_t;
|
||||
write->valid = 0xf;
|
||||
write->rw = 0xf;
|
||||
write->byteen = 0xffff;
|
||||
write->addr = addr;
|
||||
write->data = data;
|
||||
write->tag = 0xff;
|
||||
|
||||
//read req
|
||||
core_req_t* read = new core_req_t;
|
||||
read->valid = 0xf;
|
||||
read->rw = 0;
|
||||
read->byteen = 0xffff;
|
||||
read->addr = addr;
|
||||
read->data = addr;
|
||||
read->tag = 0xff;
|
||||
|
||||
// reset the device
|
||||
sim->reset();
|
||||
|
||||
//queue reqs
|
||||
for (int i = 0; i < 10; i++){
|
||||
sim->send_req(write);
|
||||
}
|
||||
sim->send_req(read);
|
||||
|
||||
sim->run();
|
||||
|
||||
bool check = sim->assert_equal(data, write->tag);
|
||||
|
||||
return check;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
//init
|
||||
RAM ram;
|
||||
CacheSim cachesim;
|
||||
cachesim.attach_ram(&ram);
|
||||
int check = REQ_RSP(&cachesim);
|
||||
if(check){
|
||||
std::cout << "PASSED" << std::endl;
|
||||
} else {
|
||||
std::cout << "FAILED" << std::endl;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user