mirror of
https://github.com/openhwgroup/cva5.git
synced 2025-04-20 12:07:53 -04:00
New AXI software simulation
This commit is contained in:
parent
967652d6d2
commit
4b1caa754d
17 changed files with 713 additions and 11485 deletions
413
test_benches/verilator/AXIMem.cc
Normal file
413
test_benches/verilator/AXIMem.cc
Normal file
|
@ -0,0 +1,413 @@
|
|||
/*
|
||||
* Copyright © 2024 Chris Keilbart
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Initial code developed under the supervision of Dr. Lesley Shannon,
|
||||
* Reconfigurable Computing Lab, Simon Fraser University.
|
||||
*
|
||||
* Author(s):
|
||||
* Chris Keilbart <ckeilbar@sfu.ca>
|
||||
*/
|
||||
|
||||
#include <fstream>
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include "verilated.h"
|
||||
#include "Vcva5_sim.h"
|
||||
#include "AXIMem.h"
|
||||
|
||||
static_assert(MEM_WORDS >= 1 && MEM_WORDS <= 16, "Bus width must be 32-512");
|
||||
//No other assertions, this unit can handle any compliant master (but does not check for compliance)
|
||||
|
||||
//TODO: ~0 is used to mark invalid data, but 1 for invalid IDs because Verilator cannot handle set MSBs
|
||||
|
||||
unsigned AXIMem::log2(unsigned x) {
|
||||
unsigned y = 0;
|
||||
while (x) {
|
||||
x >>= 1;
|
||||
y++;
|
||||
}
|
||||
return y - 1;
|
||||
}
|
||||
|
||||
AXIMem::AXIMem(Vcva5_sim* tb){
|
||||
this->tb = tb;
|
||||
//Static casting for safety is an alternative
|
||||
rdata_pointer = (uint32_t*) &tb->ddr_axi_rdata;
|
||||
wdata_pointer = (uint32_t*) &tb->ddr_axi_wdata;
|
||||
|
||||
//Create the delay distributions
|
||||
generator = default_random_engine(seed);
|
||||
rvalid_geo = geometric_distribution<unsigned>(rvalid_distribution_p);
|
||||
bvalid_geo = geometric_distribution<unsigned>(bvalid_distribution_p);
|
||||
arready_bern = bernoulli_distribution(arready_p);
|
||||
awready_bern = bernoulli_distribution(awready_p);
|
||||
wready_bern = bernoulli_distribution(wready_p);
|
||||
rvalid_bern = bernoulli_distribution(rvalid_p);
|
||||
|
||||
rst();
|
||||
}
|
||||
|
||||
AXIMem::AXIMem(ifstream (&memFiles)[NUM_CORES], Vcva5_sim* tb) : AXIMem(tb) {
|
||||
|
||||
uint32_t line_bin;
|
||||
string line_hex;
|
||||
uint32_t addr;
|
||||
const uint32_t addr_mask = (MEM_WORDS-1) << 2;
|
||||
|
||||
//First iterate over cores
|
||||
for (int i = 0; i < NUM_CORES; i++) {
|
||||
addr = (STARTING_ADDR + i*PROGRAM_SPACING);
|
||||
|
||||
//Hex files have one 32 bit hexadecimal number per line, we check the first line to determine file type
|
||||
getline(memFiles[i], line_hex);
|
||||
bool fileIsHex = line_hex.size() == 8;
|
||||
try {
|
||||
stoul(line_hex, 0, 16);
|
||||
}
|
||||
catch (invalid_argument& ex) {
|
||||
fileIsHex = false;
|
||||
}
|
||||
memFiles[i].clear();
|
||||
memFiles[i].seekg(0, ios::beg);
|
||||
|
||||
//Then iterate over pages
|
||||
while (!memFiles[i].eof()) {
|
||||
if (fileIsHex) {
|
||||
getline(memFiles[i], line_hex);
|
||||
line_bin = stoul(line_hex, 0, 16);
|
||||
}
|
||||
else
|
||||
memFiles[i].read((char*) &line_bin, 4);
|
||||
|
||||
uint32_t masked_addr = addr & addr_mask;
|
||||
uint32_t* rdata;
|
||||
try {
|
||||
rdata = mem.at(addr >> ADDR_SHIFT_AMT);
|
||||
} catch (out_of_range ex) {
|
||||
rdata = new uint32_t[MEM_WORDS];
|
||||
memset(rdata, 0, 4*MEM_WORDS);
|
||||
mem[addr >> ADDR_SHIFT_AMT] = rdata;
|
||||
}
|
||||
rdata[masked_addr>>2] = line_bin;
|
||||
|
||||
addr += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void AXIMem::pre_ar() {
|
||||
tb->ddr_axi_arready = 0;
|
||||
|
||||
//Randomly deny a request
|
||||
if (arready_bern(generator))
|
||||
return;
|
||||
|
||||
for (unsigned i = 0; i < max_read_requests; i++)
|
||||
if (!inflight_r[i].valid) {
|
||||
tb->ddr_axi_arready = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
inline void AXIMem::post_ar() {
|
||||
if (!tb->ddr_axi_arvalid || !tb->ddr_axi_arready)
|
||||
return;
|
||||
|
||||
unsigned free_index;
|
||||
unsigned max_id_latency = 0;
|
||||
for (int i = max_read_requests-1; i >= 0; i--) {
|
||||
if (!inflight_r[i].valid) //Searching backwards means insertions are likely at the beginning
|
||||
free_index = i;
|
||||
else if (inflight_r[i].id == tb->ddr_axi_arid)
|
||||
max_id_latency = max(max_id_latency, inflight_r[i].remaining);
|
||||
}
|
||||
|
||||
inflight_r[free_index].address = tb->ddr_axi_araddr;
|
||||
inflight_r[free_index].id = tb->ddr_axi_arid;
|
||||
inflight_r[free_index].burst = tb->ddr_axi_arburst;
|
||||
inflight_r[free_index].size = tb->ddr_axi_arsize;
|
||||
inflight_r[free_index].length = tb->ddr_axi_arlen;
|
||||
//Need to set the latency above the latency of the maximum outstanding request with the same ID (for ordering)
|
||||
inflight_r[free_index].remaining = max(rvalid_min_latency + rvalid_geo(generator), max_id_latency+1);
|
||||
inflight_r[free_index].valid = true;
|
||||
}
|
||||
|
||||
inline void AXIMem::rst_ar() {
|
||||
tb->ddr_axi_arready = 0;
|
||||
|
||||
arready_bern.reset();
|
||||
rvalid_geo.reset();
|
||||
for (unsigned i = 0; i < max_read_requests; i++)
|
||||
inflight_r[i].valid = false;
|
||||
}
|
||||
|
||||
inline void AXIMem::pre_aw() {
|
||||
tb->ddr_axi_awready = 0;
|
||||
|
||||
//Randomly deny a request
|
||||
if (awready_bern(generator))
|
||||
return;
|
||||
|
||||
for (unsigned i = 0; i < max_write_requests; i++) {
|
||||
if (!inflight_w[i].valid) {
|
||||
tb->ddr_axi_awready = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void AXIMem::post_aw() {
|
||||
if (!tb->ddr_axi_awvalid || !tb->ddr_axi_awready)
|
||||
return;
|
||||
|
||||
unsigned free_index;
|
||||
unsigned max_id_latency;
|
||||
for (int i = max_write_requests-1; i >= 0; i--) {
|
||||
if (!inflight_w[i].valid) //Searching backwards means insertions are likely at the beginning
|
||||
free_index = i;
|
||||
else if (inflight_w[i].id == tb->ddr_axi_awid)
|
||||
max_id_latency = max(max_id_latency, inflight_w[i].remaining);
|
||||
}
|
||||
|
||||
w_queue.push(free_index);
|
||||
inflight_w[free_index].address = tb->ddr_axi_awaddr;
|
||||
inflight_w[free_index].id = tb->ddr_axi_awid;
|
||||
inflight_w[free_index].burst = tb->ddr_axi_awburst;
|
||||
inflight_w[free_index].size = tb->ddr_axi_awsize;
|
||||
inflight_w[free_index].length = tb->ddr_axi_awlen;
|
||||
inflight_w[free_index].remaining = 0;
|
||||
inflight_w[free_index].valid = true;
|
||||
}
|
||||
|
||||
inline void AXIMem::rst_aw() {
|
||||
tb->ddr_axi_awready = 0;
|
||||
|
||||
awready_bern.reset();
|
||||
for (unsigned i = 0; i < max_write_requests; i++)
|
||||
inflight_w[i].valid = false;
|
||||
}
|
||||
|
||||
inline void AXIMem::pre_w() {
|
||||
tb->ddr_axi_wready = !wready_bern(generator) && !w_queue.empty();
|
||||
}
|
||||
|
||||
inline void AXIMem::post_w() {
|
||||
//Place the wdata in a queue for future commitment
|
||||
if (tb->ddr_axi_wvalid && tb->ddr_axi_wready) {
|
||||
const unsigned current_id = w_queue.front();
|
||||
wdata_entry new_entry;
|
||||
memcpy(new_entry.data, wdata_pointer, 4*MEM_WORDS);
|
||||
new_entry.strb = tb->ddr_axi_wstrb;
|
||||
inflight_wdata[current_id].push(new_entry);
|
||||
|
||||
if (tb->ddr_axi_wlast) {
|
||||
unsigned max_id_latency = 0;
|
||||
for (unsigned i = 0; i < max_write_requests; i++) {
|
||||
if (inflight_w[i].valid && inflight_w[i].id == current_id)
|
||||
max_id_latency = max(max_id_latency, inflight_w[i].remaining);
|
||||
}
|
||||
|
||||
inflight_w[current_id].remaining = max(bvalid_min_latency + bvalid_geo(generator), max_id_latency+1);
|
||||
w_queue.pop();
|
||||
}
|
||||
}
|
||||
|
||||
//Decrement outstanding write latencies and commit finished outstanding writes
|
||||
for (int i = max_write_requests-1; i >= 0; i--) { //Go backwards because that makes it more likely to reorder requests
|
||||
//0 remaining indicates a request that is waiting for wdata
|
||||
if (!inflight_w[i].valid || inflight_w[i].remaining == 0)
|
||||
continue;
|
||||
|
||||
if (--inflight_w[i].remaining != 0)
|
||||
continue;
|
||||
|
||||
//Commit
|
||||
b_queue.push(i);
|
||||
uint32_t raw_addr = inflight_w[i].address;
|
||||
const unsigned burst = inflight_w[i].burst;
|
||||
const unsigned size_bytes = 1 << inflight_w[i].size;
|
||||
const uint32_t line_bytes = size_bytes*(inflight_w[i].length+1);
|
||||
const uint32_t mask = ~0 << log2(line_bytes);
|
||||
|
||||
while (!inflight_wdata[i].empty()) {
|
||||
//Do the write
|
||||
uint8_t* rdata;
|
||||
try {
|
||||
rdata = (uint8_t*) mem.at(raw_addr >> ADDR_SHIFT_AMT);
|
||||
} catch (out_of_range ex) {
|
||||
rdata = (uint8_t*) new uint32_t[MEM_WORDS];
|
||||
memset(rdata, 0, 4*MEM_WORDS);
|
||||
mem[raw_addr >> ADDR_SHIFT_AMT] = (uint32_t*) rdata;
|
||||
}
|
||||
uint8_t* wdata = (uint8_t*) inflight_wdata[i].front().data;
|
||||
uint64_t strb = inflight_wdata[i].front().strb;
|
||||
|
||||
for (unsigned j = 0; j < 4*MEM_WORDS; j++) {
|
||||
if (strb & 1)
|
||||
*rdata = *wdata;
|
||||
wdata++;
|
||||
rdata++;
|
||||
strb >>= 1;
|
||||
}
|
||||
|
||||
inflight_wdata[i].pop();
|
||||
|
||||
//Set up the address for the next go
|
||||
if (burst == 1) //INCR
|
||||
raw_addr += size_bytes;
|
||||
else if (burst == 2) //WRAP
|
||||
raw_addr = (mask & raw_addr) | (~mask & raw_addr+size_bytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AXIMem::rst_w() {
|
||||
tb->ddr_axi_wready = 0;
|
||||
|
||||
bvalid_geo.reset();
|
||||
wready_bern.reset();
|
||||
while (!w_queue.empty())
|
||||
w_queue.pop();
|
||||
|
||||
for (unsigned i = 0; i < max_write_requests; i++)
|
||||
while (!inflight_wdata[i].empty())
|
||||
inflight_wdata[i].pop();
|
||||
}
|
||||
|
||||
void AXIMem::pre_r() {
|
||||
if (rvalid_bern(generator) || r_queue.empty()) {
|
||||
tb->ddr_axi_rvalid = 0;
|
||||
tb->ddr_axi_rlast = 0;
|
||||
tb->ddr_axi_rid = 1; //Cannot use ~0
|
||||
memset(rdata_pointer, ~0, 4*MEM_WORDS);
|
||||
return;
|
||||
}
|
||||
|
||||
const unsigned current_id = r_queue.front();
|
||||
tb->ddr_axi_rvalid = 1;
|
||||
tb->ddr_axi_rid = inflight_r[current_id].id;
|
||||
tb->ddr_axi_rlast = read_burst_count == inflight_r[current_id].length;
|
||||
|
||||
uint32_t start_addr = inflight_r[current_id].address;
|
||||
const unsigned burst = inflight_r[current_id].burst;
|
||||
const unsigned size_bytes = 1 << inflight_r[current_id].size;
|
||||
|
||||
if (burst == 1) //INCR
|
||||
start_addr += read_burst_count*size_bytes;
|
||||
else if (burst == 2) { //WRAP
|
||||
const uint32_t line_bytes = size_bytes*(inflight_r[current_id].length+1);
|
||||
const uint32_t mask = ~0 << log2(line_bytes);
|
||||
start_addr = (mask & start_addr) | (~mask & start_addr+read_burst_count*size_bytes);
|
||||
}
|
||||
|
||||
uint32_t* rdata;
|
||||
try {
|
||||
rdata = mem.at(start_addr >> ADDR_SHIFT_AMT);
|
||||
} catch (out_of_range ex) {
|
||||
rdata = new uint32_t[MEM_WORDS];
|
||||
memset(rdata, 0, 4*MEM_WORDS);
|
||||
mem[start_addr >> ADDR_SHIFT_AMT] = rdata;
|
||||
}
|
||||
memcpy(rdata_pointer, rdata, 4*MEM_WORDS);
|
||||
}
|
||||
|
||||
void AXIMem::post_r() {
|
||||
//Handle the last read
|
||||
if (tb->ddr_axi_rready && tb->ddr_axi_rvalid) {
|
||||
if (tb->ddr_axi_rlast) {
|
||||
read_burst_count = 0;
|
||||
inflight_r[r_queue.front()].valid = false;
|
||||
r_queue.pop();
|
||||
}
|
||||
else
|
||||
read_burst_count++;
|
||||
}
|
||||
|
||||
//Commit a read
|
||||
for (int i = max_read_requests-1; i >= 0; i--) { //Go backwards because that makes it more likely to reorder requests
|
||||
if (!inflight_r[i].valid || !inflight_r[i].remaining)
|
||||
continue;
|
||||
if (!--inflight_r[i].remaining)
|
||||
r_queue.push(i);
|
||||
}
|
||||
}
|
||||
|
||||
void AXIMem::rst_r() {
|
||||
read_burst_count = 0;
|
||||
tb->ddr_axi_rvalid = 0;
|
||||
tb->ddr_axi_rresp = 0; //Always good
|
||||
tb->ddr_axi_rlast = 0;
|
||||
tb->ddr_axi_rid = 1; //Cannot use ~0
|
||||
memset(rdata_pointer, ~0, 4*MEM_WORDS);
|
||||
|
||||
while (!r_queue.empty())
|
||||
r_queue.pop();
|
||||
}
|
||||
|
||||
void AXIMem::pre_b() {
|
||||
bool valid = !b_queue.empty();
|
||||
tb->ddr_axi_bvalid = valid;
|
||||
tb->ddr_axi_bid = valid ? inflight_w[b_queue.front()].id : 1; //Cannot use ~0
|
||||
}
|
||||
|
||||
void AXIMem::post_b() {
|
||||
if (tb->ddr_axi_bvalid && tb->ddr_axi_bready) {
|
||||
inflight_w[b_queue.front()].valid = false;
|
||||
b_queue.pop();
|
||||
}
|
||||
}
|
||||
|
||||
void AXIMem::rst_b() {
|
||||
tb->ddr_axi_bid = 0;
|
||||
tb->ddr_axi_bresp = 0; //Always good
|
||||
tb->ddr_axi_bvalid = 0;
|
||||
while (!b_queue.empty())
|
||||
b_queue.pop();
|
||||
}
|
||||
|
||||
void AXIMem::rst() {
|
||||
//Order does not matter
|
||||
rst_ar();
|
||||
rst_aw();
|
||||
rst_r();
|
||||
rst_w();
|
||||
rst_b();
|
||||
|
||||
}
|
||||
|
||||
void AXIMem::pre() {
|
||||
if (tb->rst)
|
||||
rst();
|
||||
else {
|
||||
pre_ar();
|
||||
pre_aw();
|
||||
pre_w();
|
||||
pre_r();
|
||||
pre_b();
|
||||
}
|
||||
}
|
||||
|
||||
void AXIMem::post() {
|
||||
post_ar();
|
||||
post_r();
|
||||
post_aw();
|
||||
post_w();
|
||||
post_b();
|
||||
}
|
||||
|
||||
AXIMem::~AXIMem() {
|
||||
for (auto it = mem.begin(); it != mem.end(); it++)
|
||||
delete[] it->second;
|
||||
}
|
165
test_benches/verilator/AXIMem.h
Normal file
165
test_benches/verilator/AXIMem.h
Normal file
|
@ -0,0 +1,165 @@
|
|||
/*
|
||||
* Copyright © 2024 Chris Keilbart
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Initial code developed under the supervision of Dr. Lesley Shannon,
|
||||
* Reconfigurable Computing Lab, Simon Fraser University.
|
||||
*
|
||||
* Author(s):
|
||||
* Chris Keilbart <ckeilbar@sfu.ca>
|
||||
*/
|
||||
|
||||
#ifndef AXIDDR_H
|
||||
#define AXIDDR_H
|
||||
#include <queue>
|
||||
#include <unordered_map>
|
||||
#include <random>
|
||||
#include <cstdint>
|
||||
#include "Vcva5_sim.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
//Default defines; can be overridden by command line
|
||||
#ifndef NUM_CORES
|
||||
#define NUM_CORES 1
|
||||
#endif
|
||||
#ifndef STARTING_ADDR
|
||||
#define STARTING_ADDR 0x80000000
|
||||
#endif
|
||||
#ifndef PROGRAM_SPACING
|
||||
#define PROGRAM_SPACING 0x04000000
|
||||
#endif
|
||||
|
||||
//If DETERMINISTIC is set, randomness effecting memory performance is disabled
|
||||
#if defined(DETERMINISTIC) && DETERMINISTIC != 0
|
||||
#define RVALID_DISTRIBUTION_P 0.0
|
||||
#define BVALID_DISTRIBUTION_P 0.0
|
||||
#define ARREADY_P 0.0
|
||||
#define AWREADY_P 0.0
|
||||
#define WREADY_P 0.0
|
||||
#define RVALID_P 0.0
|
||||
#else
|
||||
#define RVALID_DISTRIBUTION_P 0.5
|
||||
#define BVALID_DISTRIBUTION_P 0.5
|
||||
#define ARREADY_P 0.25
|
||||
#define AWREADY_P 0.25
|
||||
#define WREADY_P 0.1
|
||||
#define RVALID_P 0.1
|
||||
#endif
|
||||
|
||||
//Shared RNG and simulation properties
|
||||
#define RNG_SEED 101099
|
||||
#define RVALID_MIN_LATENCY 20
|
||||
#define BVALID_MIN_LATENCY 25
|
||||
#define MAX_READS 8
|
||||
#define MAX_WRITES 8
|
||||
|
||||
//Certain logic depends on the width of the data bus
|
||||
#define MEM_TYPE decltype(*Vcva5_sim::ddr_axi_rdata)
|
||||
#define MEM_WORDS (8*sizeof(Vcva5_sim::ddr_axi_rdata)/32)
|
||||
#define ADDR_SHIFT_AMT (log2(MEM_WORDS)+2)
|
||||
|
||||
struct request {
|
||||
uint32_t address;
|
||||
unsigned id;
|
||||
unsigned burst;
|
||||
unsigned size;
|
||||
unsigned length;
|
||||
unsigned remaining;
|
||||
bool valid;
|
||||
};
|
||||
|
||||
struct wdata_entry {
|
||||
uint32_t data[MEM_WORDS];
|
||||
uint64_t strb; //This caps the bus size to 512
|
||||
};
|
||||
|
||||
class AXIMem {
|
||||
public:
|
||||
//Initialize DDR
|
||||
AXIMem(ifstream (&memFiles)[NUM_CORES], Vcva5_sim* tb);
|
||||
//Free the memory map
|
||||
~AXIMem();
|
||||
|
||||
//Set outputs
|
||||
void pre();
|
||||
//Respond to inputs
|
||||
void post();
|
||||
|
||||
private:
|
||||
//Basic initialization that doesn't construct the memory itself
|
||||
AXIMem(Vcva5_sim* tb);
|
||||
|
||||
inline void pre_ar();
|
||||
inline void pre_aw();
|
||||
inline void pre_r();
|
||||
inline void pre_w();
|
||||
inline void pre_b();
|
||||
inline void post_ar();
|
||||
inline void post_aw();
|
||||
inline void post_r();
|
||||
inline void post_w();
|
||||
inline void post_b();
|
||||
void rst();
|
||||
inline void rst_ar();
|
||||
inline void rst_aw();
|
||||
inline void rst_r();
|
||||
inline void rst_w();
|
||||
inline void rst_b();
|
||||
|
||||
unsigned log2(unsigned x);
|
||||
|
||||
//Simulation tuneables
|
||||
//Latencies follow a shifted geometric distribution
|
||||
const unsigned seed = RNG_SEED;
|
||||
const unsigned rvalid_min_latency = RVALID_MIN_LATENCY;
|
||||
const unsigned bvalid_min_latency = BVALID_MIN_LATENCY;
|
||||
const double rvalid_distribution_p = RVALID_DISTRIBUTION_P;
|
||||
const double bvalid_distribution_p = BVALID_DISTRIBUTION_P;
|
||||
|
||||
//Bus availability
|
||||
static const unsigned max_read_requests = MAX_READS;
|
||||
static const unsigned max_write_requests = MAX_WRITES;
|
||||
|
||||
//Odds that it won't be available on any given cycle
|
||||
const double arready_p = ARREADY_P;
|
||||
const double awready_p = AWREADY_P;
|
||||
const double wready_p = WREADY_P;
|
||||
const double rvalid_p = RVALID_P;
|
||||
|
||||
//Latency Randomizers
|
||||
default_random_engine generator;
|
||||
geometric_distribution<unsigned> rvalid_geo;
|
||||
geometric_distribution<unsigned> bvalid_geo;
|
||||
bernoulli_distribution arready_bern;
|
||||
bernoulli_distribution awready_bern;
|
||||
bernoulli_distribution wready_bern;
|
||||
bernoulli_distribution rvalid_bern;
|
||||
|
||||
//Pointers to Data
|
||||
Vcva5_sim *tb;
|
||||
uint32_t* wdata_pointer;
|
||||
uint32_t* rdata_pointer;
|
||||
unordered_map<uint32_t,uint32_t*> mem; //TODO: use the gross fixed array length syntax
|
||||
request inflight_r[max_read_requests];
|
||||
request inflight_w[max_write_requests];
|
||||
queue<wdata_entry> inflight_wdata[max_write_requests];
|
||||
queue<unsigned> w_queue;
|
||||
queue<unsigned> b_queue;
|
||||
queue<unsigned> r_queue;
|
||||
unsigned read_burst_count;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load diff
|
@ -1,371 +0,0 @@
|
|||
#include <stdint.h>
|
||||
#include <iostream>
|
||||
#include <cstdlib>
|
||||
#include <assert.h>
|
||||
#include "verilated.h"
|
||||
#include "verilated_vcd_c.h"
|
||||
#include "Vcva5_sim.h"
|
||||
#include "axi_ddr_sim.h"
|
||||
#include "ddr_page.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
axi_ddr_sim::axi_ddr_sim(Vcva5_sim * tb){
|
||||
this->tb = tb;
|
||||
}
|
||||
|
||||
void axi_ddr_sim::init_signals(){
|
||||
tb->ddr_axi_bresp = 0;
|
||||
tb->ddr_axi_bvalid = 0;
|
||||
tb->ddr_axi_rvalid = 0;
|
||||
tb->ddr_axi_rdata = 0;
|
||||
tb->ddr_axi_rid = 0;
|
||||
tb->ddr_axi_rlast = 0;
|
||||
tb->ddr_axi_rresp = 0;
|
||||
tb->ddr_axi_rvalid = 0;
|
||||
}
|
||||
|
||||
|
||||
axi_ddr_sim::axi_ddr_sim(string filepath, uint32_t starting_memory_location, int number_of_bytes, Vcva5_sim * tb){
|
||||
ifstream input_memory_file;
|
||||
input_memory_file.open(filepath);
|
||||
string line;
|
||||
|
||||
|
||||
uint32_t max_pages = starting_memory_location/PAGE_SIZE + number_of_bytes/PAGE_SIZE;
|
||||
//Parse the uniform pages
|
||||
uint32_t page_index = starting_memory_location/PAGE_SIZE;
|
||||
for (; page_index < max_pages; page_index++){
|
||||
ddr_page page {};
|
||||
for(int data_index = 0; data_index < PAGE_SIZE/4; data_index++){
|
||||
getline(input_memory_file, line);
|
||||
//Read 32-bit number represented through hexidecimals
|
||||
page.write_data(data_index, stoul(line, 0, 16));
|
||||
}
|
||||
ddr_pages.insert(pair<uint32_t,ddr_page>((uint32_t)(page_index*PAGE_SIZE), page));
|
||||
}
|
||||
generator = default_random_engine(DELAY_SEED);
|
||||
read_distribution = uniform_int_distribution<int>(MIN_DELAY_RD,MAX_DELAY_RD);
|
||||
write_distribution = uniform_int_distribution<int>(MIN_DELAY_WR,MAX_DELAY_WR);
|
||||
this->tb = tb;
|
||||
init_signals();
|
||||
//printf("Done AXI Initialization. %d Pages intialized\n", page_index);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
|
||||
|
||||
axi_ddr_sim::axi_ddr_sim(ifstream & input_memory_file, Vcva5_sim * tb){
|
||||
string line;
|
||||
|
||||
uint32_t max_pages = DDR_SIZE/PAGE_SIZE;
|
||||
//Parse the uniform pages
|
||||
bool not_finished = true;
|
||||
uint32_t page_index = starting_location/PAGE_SIZE;
|
||||
for (; page_index < max_pages; page_index++){
|
||||
ddr_page page {};
|
||||
|
||||
for(int data_index = 0; data_index < PAGE_SIZE/4; data_index++){
|
||||
not_finished = (bool)getline(input_memory_file, line);
|
||||
if(!not_finished)
|
||||
break;
|
||||
//Read 32-bit number represented through hexidecimals
|
||||
page.write_data(data_index, stoul(line, 0, 16));
|
||||
}
|
||||
if(!not_finished)
|
||||
break;
|
||||
ddr_pages.insert(pair<uint32_t,ddr_page>((uint32_t)(page_index*PAGE_SIZE), page));
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
generator = default_random_engine(DELAY_SEED);
|
||||
read_distribution = uniform_int_distribution<int>(MIN_DELAY_RD,MAX_DELAY_RD);
|
||||
write_distribution = uniform_int_distribution<int>(MIN_DELAY_WR,MAX_DELAY_WR);
|
||||
this->tb = tb;
|
||||
init_signals();
|
||||
//printf("Done AXI Initialization. Started from: %u\n", starting_location);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
|
||||
int axi_ddr_sim::get_data(uint32_t data_address){
|
||||
uint32_t starting_address = (data_address / PAGE_SIZE) * PAGE_SIZE;
|
||||
if(!ddr_pages.count(starting_address)){ //If page does not exist
|
||||
ddr_page page {};
|
||||
ddr_pages.insert(pair<uint32_t,ddr_page>(starting_address, page));
|
||||
assert(ddr_pages.count(starting_address));
|
||||
}
|
||||
return ddr_pages[starting_address].return_data(data_address%PAGE_SIZE/4);
|
||||
}
|
||||
|
||||
void axi_ddr_sim::set_data(uint32_t data_address, uint32_t set_data, uint32_t byte_enable){
|
||||
uint32_t data = get_data(data_address);
|
||||
uint32_t starting_address = (data_address / PAGE_SIZE) * PAGE_SIZE;
|
||||
if(!ddr_pages.count(starting_address)){ //If page does not exist
|
||||
ddr_page page {};
|
||||
ddr_pages.insert(pair<uint32_t,ddr_page>(starting_address, page));
|
||||
assert(ddr_pages.count(starting_address)); //Check if it was intialized
|
||||
}
|
||||
data = (data & ~byte_enable) | (set_data & byte_enable);
|
||||
ddr_pages[starting_address].write_data(data_address%PAGE_SIZE/4, data);
|
||||
};
|
||||
|
||||
|
||||
ddr_page axi_ddr_sim::get_page(uint32_t page_address){
|
||||
return ddr_pages[page_address];
|
||||
}
|
||||
|
||||
void axi_ddr_sim::parse_input_signals(){
|
||||
//If the master has a write requests
|
||||
if(tb->ddr_axi_awvalid && wr_ad_channel_queue.size() < MAX_INFLIGHT_WR_REQ){
|
||||
AXI_write_address_channel_signals elem{tb->ddr_axi_awaddr, tb->ddr_axi_awlen, tb->ddr_axi_awsize, tb->ddr_axi_awburst,tb->ddr_axi_awcache,tb->ddr_axi_awid};
|
||||
wr_ad_channel_queue.push(elem);
|
||||
order_queue.push(1);
|
||||
}
|
||||
//If the master has write data
|
||||
if(tb->ddr_axi_wvalid){
|
||||
AXI_write_data_channel_signals elem{tb->ddr_axi_wid, tb->ddr_axi_wdata, tb->ddr_axi_wstrb, tb->ddr_axi_wlast};
|
||||
w_data_channel_queue.push(elem);
|
||||
}
|
||||
//If the master has a read request
|
||||
if(tb->ddr_axi_arvalid && rd_ad_channel_queue.size() < MAX_INFLIGHT_RD_REQ){
|
||||
AXI_read_address_channel_signals elem{tb->ddr_axi_araddr, tb->ddr_axi_arlen, tb->ddr_axi_arsize, tb->ddr_axi_arburst, tb->ddr_axi_arcache, tb->ddr_axi_arid};
|
||||
rd_ad_channel_queue.push(elem);
|
||||
order_queue.push(0);
|
||||
}
|
||||
}
|
||||
|
||||
void axi_ddr_sim::parse_output_signals(){
|
||||
if(tb->rst ==1){
|
||||
tb->ddr_axi_wready = 0;
|
||||
tb->ddr_axi_arready = 0;
|
||||
|
||||
tb->ddr_axi_bid = 0;
|
||||
tb->ddr_axi_bresp = 0;
|
||||
tb->ddr_axi_bvalid = 0;
|
||||
tb->ddr_axi_rid = 0;
|
||||
tb->ddr_axi_rdata = 0;
|
||||
tb->ddr_axi_rresp = 0;
|
||||
tb->ddr_axi_rlast = 0;
|
||||
//tb->ddr_axi_ruser = 0;
|
||||
tb->ddr_axi_rvalid = 0;
|
||||
|
||||
}
|
||||
else {
|
||||
tb->ddr_axi_wready = 1;
|
||||
|
||||
//Write Req
|
||||
if((wr_ad_channel_queue.size() < MAX_INFLIGHT_WR_REQ))
|
||||
tb->ddr_axi_awready = 1;
|
||||
else
|
||||
tb->ddr_axi_awready = 0;
|
||||
|
||||
//Read Req
|
||||
if(rd_ad_channel_queue.size() < MAX_INFLIGHT_RD_REQ)
|
||||
tb->ddr_axi_arready = 1;
|
||||
else
|
||||
tb->ddr_axi_arready = 0;
|
||||
|
||||
//If we the write_response
|
||||
if(w_res_channel_queue.size() > 0){
|
||||
AXI_write_response_channel_signals elem = w_res_channel_queue.front();
|
||||
if(tb->ddr_axi_bready)
|
||||
w_res_channel_queue.pop();
|
||||
|
||||
tb->ddr_axi_bid = elem.bid;
|
||||
tb->ddr_axi_bresp = elem.bresp;
|
||||
tb->ddr_axi_bvalid = 1;
|
||||
}
|
||||
else{
|
||||
tb->ddr_axi_bid = rand();
|
||||
tb->ddr_axi_bresp = rand();
|
||||
//tb->ddr_axi_buser = rand();
|
||||
tb->ddr_axi_bvalid = 0;
|
||||
}
|
||||
|
||||
//If we have the read data
|
||||
if(r_data_channel_queue.size() > 0){
|
||||
AXI_read_data_channel_signals elem = r_data_channel_queue.front();
|
||||
if(tb->ddr_axi_rready){
|
||||
//cout << "Before: " << r_data_channel_queue.size() << endl;
|
||||
r_data_channel_queue.pop();
|
||||
//cout << "After: " << r_data_channel_queue.size() << endl;
|
||||
}
|
||||
tb->ddr_axi_rid = elem.rid;
|
||||
tb->ddr_axi_rdata = elem.rdata;
|
||||
tb->ddr_axi_rresp = elem.rresp;
|
||||
tb->ddr_axi_rlast = elem.rlast;
|
||||
//tb->ddr_axi_ruser = elem.ruser;
|
||||
tb->ddr_axi_rvalid = 1;
|
||||
}
|
||||
else{
|
||||
tb->ddr_axi_rid = rand();
|
||||
tb->ddr_axi_rdata = rand();
|
||||
tb->ddr_axi_rresp = rand();
|
||||
tb->ddr_axi_rlast = 0;
|
||||
//tb->ddr_axi_ruser = rand();
|
||||
tb->ddr_axi_rvalid = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void axi_ddr_sim::handle_read_req(){
|
||||
if(rd_ad_channel_queue.size() > 0 && (order_queue.front() == 0)){
|
||||
if(current_read_parameters.delay_cycles_left == 0){
|
||||
AXI_read_data_channel_signals elem;
|
||||
elem.rid = rd_ad_channel_queue.front().arid;
|
||||
elem.rdata = get_data(current_read_parameters.address);
|
||||
current_read_parameters.number_of_bursts_left--;
|
||||
|
||||
if(rd_ad_channel_queue.front().arburst == 0 ){//FIXED
|
||||
//do nothing
|
||||
}
|
||||
else if(rd_ad_channel_queue.front().arburst == 1){ //INCR
|
||||
//Increment Address by number of bytes in a burst(arsize)
|
||||
current_read_parameters.address += current_read_parameters.increment;
|
||||
|
||||
}
|
||||
else if(rd_ad_channel_queue.front().arburst == 2){ //WRAP
|
||||
current_read_parameters.address += current_read_parameters.increment;
|
||||
if(current_read_parameters.address == current_read_parameters.wrap_boundary + current_read_parameters.number_bytes * current_read_parameters.burst_length){
|
||||
current_read_parameters.address = current_read_parameters.wrap_boundary;
|
||||
}
|
||||
}
|
||||
elem.rresp = 0; //OKAY bx00
|
||||
//elem.ruser = rd_ad_channel_queue.front().aruser;
|
||||
if(current_read_parameters.number_of_bursts_left == 0){
|
||||
elem.rlast = 1;
|
||||
rd_ad_channel_queue.pop();
|
||||
order_queue.pop();
|
||||
}
|
||||
else
|
||||
elem.rlast = 0;
|
||||
|
||||
if ((current_read_parameters.address >> 24) == 0x88) {
|
||||
elem.rdata = 0xFFFFFF21;
|
||||
}
|
||||
|
||||
r_data_channel_queue.push(elem);
|
||||
}
|
||||
else{
|
||||
current_read_parameters.delay_cycles_left--;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void axi_ddr_sim::handle_write_req(){
|
||||
//cout << "w_data_channel_queue size: " << w_data_channel_queue.size() << endl;
|
||||
//cout << "current_write_parameters.number_of_bursts_left: " << current_write_parameters.number_of_bursts_left << endl;
|
||||
if(w_data_channel_queue.size() > 0 && current_write_parameters.number_of_bursts_left > 0 && (order_queue.front() == 1)){
|
||||
if(current_write_parameters.delay_cycles_left == 0){
|
||||
AXI_write_data_channel_signals elem = w_data_channel_queue.front();
|
||||
w_data_channel_queue.pop();
|
||||
//Calculate Byte Enable
|
||||
uint32_t byte_enable = 0;
|
||||
if(elem.wstrb >= 8){
|
||||
byte_enable = byte_enable | 0xFF000000;
|
||||
elem.wstrb -= 8;
|
||||
}
|
||||
if(elem.wstrb >= 4){
|
||||
byte_enable = byte_enable | 0x00FF0000;
|
||||
elem.wstrb -= 4;
|
||||
}
|
||||
if(elem.wstrb >= 2){
|
||||
byte_enable = byte_enable | 0x0000FF00;
|
||||
elem.wstrb -= 2;
|
||||
}
|
||||
if(elem.wstrb == 1){
|
||||
byte_enable = byte_enable | 0x000000FF;
|
||||
elem.wstrb -= 1;
|
||||
}
|
||||
set_data(current_write_parameters.address, elem.wdata, byte_enable);
|
||||
current_write_parameters.number_of_bursts_left--;
|
||||
|
||||
if(wr_ad_channel_queue.front().awburst == 0 ){//FIXED
|
||||
//do nothing
|
||||
}
|
||||
else if(wr_ad_channel_queue.front().awburst == 1){ //INCR
|
||||
//Increment Address by number of bytes in a burst(arsize)
|
||||
current_write_parameters.address += current_write_parameters.increment;
|
||||
|
||||
}
|
||||
else if(wr_ad_channel_queue.front().awburst == 2){ //WRAP
|
||||
current_write_parameters.address += current_write_parameters.increment;
|
||||
if(current_write_parameters.address == current_write_parameters.wrap_boundary + current_write_parameters.number_bytes * current_write_parameters.burst_length){
|
||||
current_write_parameters.address = current_write_parameters.wrap_boundary;
|
||||
}
|
||||
}
|
||||
//If the Write is done
|
||||
if(current_write_parameters.number_of_bursts_left == 0){
|
||||
AXI_write_response_channel_signals resp_elem;
|
||||
resp_elem.bid = elem.wid;
|
||||
resp_elem.bresp = 0;
|
||||
wr_ad_channel_queue.pop();
|
||||
order_queue.pop();
|
||||
w_res_channel_queue.push(resp_elem);
|
||||
}
|
||||
}
|
||||
else{
|
||||
current_write_parameters.delay_cycles_left--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void axi_ddr_sim::update_current_read_parameters(){
|
||||
//If I can serve a new read request
|
||||
if(rd_ad_channel_queue.size() > 0 && current_read_parameters.number_of_bursts_left == 0 && (order_queue.front() == 0)){
|
||||
current_read_parameters.address = rd_ad_channel_queue.front().araddr;
|
||||
current_read_parameters.number_of_bursts_left = rd_ad_channel_queue.front().arlen +1;
|
||||
current_read_parameters.delay_cycles_left = read_distribution(generator);
|
||||
if(rd_ad_channel_queue.front().arburst == 0 ){//FIXED
|
||||
current_read_parameters.increment = 0;
|
||||
}
|
||||
else if(rd_ad_channel_queue.front().arburst == 1){ //INCR
|
||||
//Increment Address by number of bytes in a burst(arsize)
|
||||
current_read_parameters.increment = pow(2,rd_ad_channel_queue.front().arsize);
|
||||
|
||||
}
|
||||
else if(rd_ad_channel_queue.front().arburst == 2){ //WRAP
|
||||
current_read_parameters.increment = pow(2,rd_ad_channel_queue.front().arsize);
|
||||
current_read_parameters.number_bytes = pow(2,rd_ad_channel_queue.front().arsize);
|
||||
current_read_parameters.burst_length = rd_ad_channel_queue.front().arlen +1;
|
||||
current_read_parameters.wrap_boundary = (int)(current_read_parameters.address/(current_read_parameters.number_bytes * current_read_parameters.burst_length)) * (current_read_parameters.number_bytes * current_read_parameters.burst_length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void axi_ddr_sim::update_current_write_parameters(){
|
||||
//If I can serve a new read request
|
||||
if(wr_ad_channel_queue.size() > 0 && current_write_parameters.number_of_bursts_left == 0 && (order_queue.front() == 1)){
|
||||
current_write_parameters.address = wr_ad_channel_queue.front().awaddr;
|
||||
current_write_parameters.number_of_bursts_left = wr_ad_channel_queue.front().awlen +1;
|
||||
current_write_parameters.delay_cycles_left = write_distribution(generator);
|
||||
if(wr_ad_channel_queue.front().awburst == 0 ){//FIXED
|
||||
current_write_parameters.increment = 0;
|
||||
}
|
||||
else if(wr_ad_channel_queue.front().awburst == 1){ //INCR
|
||||
//Increment Address by number of bytes in a burst(arsize)
|
||||
current_write_parameters.increment = pow(2,wr_ad_channel_queue.front().awsize);
|
||||
|
||||
}
|
||||
else if(wr_ad_channel_queue.front().awburst == 2){ //WRAP
|
||||
current_write_parameters.increment = pow(2,wr_ad_channel_queue.front().awsize);
|
||||
current_write_parameters.number_bytes = pow(2,wr_ad_channel_queue.front().awsize);
|
||||
current_write_parameters.burst_length = wr_ad_channel_queue.front().awlen +1;
|
||||
current_write_parameters.wrap_boundary = (int)(current_write_parameters.address/(current_write_parameters.number_bytes * current_write_parameters.burst_length)) * (current_write_parameters.number_bytes * current_write_parameters.burst_length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void axi_ddr_sim::step(){
|
||||
|
||||
parse_input_signals();
|
||||
update_current_read_parameters();
|
||||
update_current_write_parameters();
|
||||
handle_read_req();
|
||||
handle_write_req();
|
||||
parse_output_signals();
|
||||
}
|
|
@ -1,113 +0,0 @@
|
|||
/*
|
||||
* Copyright © 2019 Eric Matthews,Zavier Aguila Lesley Shannon
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Initial code developed under the supervision of Dr. Lesley Shannon,
|
||||
* Reconfigurable Computing Lab, Simon Fraser University.
|
||||
*
|
||||
* Author(s):
|
||||
* Eric Matthews <ematthew@sfu.ca>
|
||||
* Zavier Aguila <zaguila@sfu.ca>
|
||||
*/
|
||||
|
||||
#ifndef AXIDDR_H
|
||||
#define AXIDDR_H
|
||||
#include <stdlib.h>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <queue>
|
||||
#include <cmath>
|
||||
#include <map>
|
||||
#include <random>
|
||||
#include "verilated.h"
|
||||
#include "verilated_vcd_c.h"
|
||||
#include "Vcva5_sim.h"
|
||||
#include "axi_interface.h"
|
||||
#include "ddr_page.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
struct addr_calculation_parameters{
|
||||
uint32_t address;
|
||||
uint32_t increment;
|
||||
uint32_t wrap_boundary;
|
||||
int number_bytes;
|
||||
int burst_length;
|
||||
int number_of_bursts_left;
|
||||
int delay_cycles_left;
|
||||
};
|
||||
|
||||
class axi_ddr_sim{
|
||||
public:
|
||||
//Functions--------------------------------------------------------------
|
||||
//Init instructions-----------------
|
||||
axi_ddr_sim();
|
||||
//Initialize DDR
|
||||
axi_ddr_sim(Vcva5_sim * tb);
|
||||
|
||||
//Initialize DDR from file
|
||||
axi_ddr_sim(string filepath, uint32_t starting_memory_location, int number_of_bytes, Vcva5_sim * tb);
|
||||
axi_ddr_sim(ifstream & input_memory_file, Vcva5_sim * tb);
|
||||
void step();
|
||||
int get_data(uint32_t data_address);
|
||||
|
||||
ddr_page get_page(uint32_t page_address);
|
||||
|
||||
void set_data(uint32_t data_address, uint32_t set_data, uint32_t byte_enable);
|
||||
|
||||
//Queue Handling Functions-------------------------------------
|
||||
|
||||
|
||||
//AXI Functions-------------------------------------
|
||||
//Latency Randomizer
|
||||
//Byte Enable Handler
|
||||
//Burst Handler
|
||||
|
||||
//Base AXI Read Reply
|
||||
//BASE AXI Write Reply
|
||||
private:
|
||||
default_random_engine generator;
|
||||
uniform_int_distribution<int> read_distribution;
|
||||
uniform_int_distribution<int> write_distribution;
|
||||
//Pointers to Data
|
||||
map<uint32_t,ddr_page> ddr_pages;
|
||||
Vcva5_sim *tb;
|
||||
void parse_output_signals();
|
||||
|
||||
void parse_input_signals();
|
||||
void update_current_read_parameters();
|
||||
void update_current_write_parameters();
|
||||
void handle_write_req();
|
||||
void handle_read_req();
|
||||
void init_signals();
|
||||
|
||||
addr_calculation_parameters current_read_parameters{0,0,0,0};
|
||||
addr_calculation_parameters current_write_parameters{0,0,0,0};
|
||||
//Read Request Queue
|
||||
queue<AXI_read_address_channel_signals> rd_ad_channel_queue;
|
||||
//Write Request Queue
|
||||
queue<AXI_write_address_channel_signals> wr_ad_channel_queue;
|
||||
//Read Data Queue
|
||||
queue<AXI_read_data_channel_signals> r_data_channel_queue;
|
||||
//Write Data Queue
|
||||
queue<AXI_write_data_channel_signals> w_data_channel_queue;
|
||||
//Write Response Queue
|
||||
queue<AXI_write_response_channel_signals> w_res_channel_queue;
|
||||
//Order Queue
|
||||
queue<int> order_queue;
|
||||
unsigned starting_location = 0x80000000;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,59 +0,0 @@
|
|||
#ifndef AXIINTERFACE_H
|
||||
#define AXIINTERFACE_H
|
||||
#include <stdint.h>
|
||||
|
||||
using namespace std;
|
||||
struct AXI_write_address_channel_signals{
|
||||
uint32_t awaddr;
|
||||
uint32_t awlen;
|
||||
uint32_t awsize;
|
||||
uint32_t awburst;
|
||||
uint32_t awcache;
|
||||
uint32_t awid;
|
||||
//uint32_t awready;
|
||||
};
|
||||
struct AXI_read_address_channel_signals{
|
||||
|
||||
uint32_t araddr;
|
||||
uint32_t arlen;
|
||||
uint32_t arsize;
|
||||
uint32_t arburst;
|
||||
uint32_t arcache;
|
||||
uint32_t arid;
|
||||
|
||||
};
|
||||
struct AXI_write_data_channel_signals{
|
||||
uint32_t wid;
|
||||
uint32_t wdata;
|
||||
uint32_t wstrb;
|
||||
uint32_t wlast;
|
||||
//uint32_t wuser;
|
||||
//uint32_t wvalid;
|
||||
//uint32_t wready;
|
||||
};
|
||||
struct AXI_write_response_channel_signals{
|
||||
uint32_t bid;
|
||||
uint32_t bresp;
|
||||
//uint32_t buser;
|
||||
uint32_t bvalid;
|
||||
//uint32_t bready;
|
||||
};
|
||||
struct AXI_read_data_channel_signals{
|
||||
uint32_t rid;
|
||||
uint32_t rdata;
|
||||
uint32_t rresp;
|
||||
uint32_t rlast;
|
||||
//uint32_t ruser;
|
||||
//uint32_t rvalid;
|
||||
//uint32_t rready;
|
||||
};
|
||||
|
||||
|
||||
struct AXI_channels{
|
||||
AXI_read_address_channel_signals rd_ad_channel;
|
||||
AXI_write_address_channel_signals wd_ad_channel;
|
||||
AXI_read_data_channel_signals r_data_channel;
|
||||
AXI_write_data_channel_signals w_data_channel;
|
||||
AXI_write_response_channel_signals w_res_channel;
|
||||
};
|
||||
#endif
|
|
@ -1,218 +0,0 @@
|
|||
#include <stdlib.h>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <queue>
|
||||
#include "Vaxi_l2_test.h"
|
||||
#include "verilated.h"
|
||||
#include "verilated_vcd_c.h"
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
//Trace Interface Counters
|
||||
int num_entries = PAGE_SIZE * 5;
|
||||
uint32_t starting_location = PAGE_SIZE*0;
|
||||
struct l2_arb_inputs{
|
||||
uint32_t address;
|
||||
uint32_t rnw;
|
||||
uint32_t burst_length;
|
||||
uint32_t sub_id;
|
||||
uint32_t be;
|
||||
};
|
||||
struct l2_data_inputs{
|
||||
uint32_t data;
|
||||
uint32_t be;
|
||||
};
|
||||
struct l2_arb_expected_output{
|
||||
uint32_t rd_data;
|
||||
uint32_t rd_sub_id;
|
||||
};
|
||||
|
||||
queue<l2_arb_inputs> test_inputs;
|
||||
queue<l2_arb_expected_output> test_expected_output;
|
||||
queue<l2_data_inputs> test_data_inputs;
|
||||
|
||||
void assign_read_input(uint32_t address, uint32_t burst_length, uint32_t sub_id){
|
||||
l2_arb_inputs in_elem{address, 1, burst_length, sub_id};
|
||||
test_inputs.push(in_elem);
|
||||
};
|
||||
|
||||
void assign_write_input(uint32_t address, uint32_t burst_length, uint32_t sub_id, uint32_t be){
|
||||
l2_arb_inputs in_elem{address, 0, burst_length, sub_id};
|
||||
test_inputs.push(in_elem);
|
||||
for(int i = burst_length-1 ; i >= 0; i--){
|
||||
l2_data_inputs in_data_elem{i+71, be};
|
||||
test_data_inputs.push(in_data_elem);
|
||||
}
|
||||
};
|
||||
|
||||
void assign_single_write_input(uint32_t address, uint32_t sub_id, uint32_t data, uint32_t be){
|
||||
l2_arb_inputs in_elem{address, 0, 1, sub_id};
|
||||
test_inputs.push(in_elem);
|
||||
l2_data_inputs in_data_elem{data, be};
|
||||
test_data_inputs.push(in_data_elem);
|
||||
|
||||
};
|
||||
vluint64_t main_time = 0; // Current simulation time
|
||||
// This is a 64-bit integer to reduce wrap over issues and
|
||||
// allow modulus. You can also use a double, if you wish.
|
||||
double sc_time_stamp () { // Called by $time in Verilog
|
||||
return main_time; // converts to double, to match
|
||||
// what SystemC does
|
||||
}
|
||||
|
||||
using namespace std;
|
||||
int main(int argc, char **argv) {
|
||||
//assign_single_write_input(0,1, 1 ,0xF);
|
||||
//assign_single_write_input(0,0, 21 ,0xF);
|
||||
assign_single_write_input(4,0, 22 ,0xF);
|
||||
//assign_single_write_input(4,0, 23 ,0xF);
|
||||
//assign_single_write_input(4,0, 25 ,0xF);
|
||||
//assign_write_input(0, 4, 0, 0xF);
|
||||
assign_read_input(4, 4, 0);
|
||||
//assign_read_input(4, 8, 0);;
|
||||
ofstream logFile, sigFile;
|
||||
uint64_t cycle_cout = 0;
|
||||
|
||||
// Initialize Verilators variables
|
||||
Verilated::commandArgs(argc, argv);
|
||||
#ifdef TRACE_ON
|
||||
Verilated::traceEverOn(true);
|
||||
#endif
|
||||
|
||||
if (!argv[1]) {
|
||||
cout << "Missing log file name.\n";
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (!argv[2]) {
|
||||
cout << "Missing signature file name.\n";
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
logFile.open (argv[1]);
|
||||
sigFile.open (argv[2]);
|
||||
// Create an instance of our module under test
|
||||
Vaxi_l2_test *tb = new Vaxi_l2_test;
|
||||
axi_ddr_sim <Vaxi_l2_test> axi_ddr("DDR_init.txt", starting_location, num_entries, tb);
|
||||
#ifdef TRACE_ON
|
||||
VerilatedVcdC *verilatorWaveformTracer;
|
||||
verilatorWaveformTracer = new VerilatedVcdC;
|
||||
tb->trace(verilatorWaveformTracer, 99);
|
||||
verilatorWaveformTracer->open("/data/sim-logs/sim_results.vcd");
|
||||
#endif
|
||||
|
||||
cout << "--------------------------------------------------------------\n";
|
||||
cout << " Starting Simulation, logging to: " << argv[1] << "\n";
|
||||
cout << "--------------------------------------------------------------\n";
|
||||
|
||||
//Reset
|
||||
for(int i = 0; i < 50;i++){
|
||||
tb->rst = 1;
|
||||
|
||||
tb->clk = 1;
|
||||
tb->eval();
|
||||
tb->clk = 0;
|
||||
tb->eval();
|
||||
}
|
||||
tb->rst = 0;
|
||||
tb->clk = 1;
|
||||
tb->eval();
|
||||
tb->clk = 0;
|
||||
tb->eval();
|
||||
// Tick the clock until we are done
|
||||
int number_of_data_left = 0;
|
||||
while(!Verilated::gotFinish()) {
|
||||
tb->clk = 1;
|
||||
tb->eval();
|
||||
|
||||
//Specify Inputs
|
||||
//Note: Current doesn't give the arbiter the address and data separate
|
||||
//READ Input
|
||||
if(test_inputs.size() > 0 && !tb->request_full && test_inputs.front().rnw){
|
||||
l2_arb_inputs elem;
|
||||
elem = test_inputs.front();
|
||||
test_inputs.pop();
|
||||
tb->addr = elem.address;
|
||||
tb->rnw = elem.rnw;
|
||||
tb->is_amo = 0;
|
||||
tb->amo_type_or_burst_size = elem.burst_length;
|
||||
tb->sub_id = elem.sub_id;
|
||||
|
||||
tb->request_push = 1;
|
||||
tb->wr_data_push = 0;
|
||||
}
|
||||
else if(test_inputs.size() > 0 && !tb->request_full && !test_inputs.front().rnw && number_of_data_left == 0){
|
||||
l2_arb_inputs elem;
|
||||
elem = test_inputs.front();
|
||||
tb->addr = elem.address;
|
||||
tb->rnw = elem.rnw;
|
||||
tb->is_amo = 0;
|
||||
tb->amo_type_or_burst_size = elem.burst_length - 1;
|
||||
tb->sub_id = elem.sub_id;
|
||||
number_of_data_left = elem.burst_length;
|
||||
tb->request_push = 1;
|
||||
tb->wr_data_push = 0;
|
||||
}
|
||||
else if(number_of_data_left > 0){
|
||||
tb->request_push = 0;
|
||||
|
||||
if(!tb->data_full){
|
||||
l2_data_inputs data_elem = test_data_inputs.front();
|
||||
test_data_inputs.pop();
|
||||
tb->wr_data = data_elem.data;
|
||||
tb->wr_data_be = data_elem.be;
|
||||
tb->wr_data_push = 1;
|
||||
|
||||
number_of_data_left--;
|
||||
if(number_of_data_left == 0)
|
||||
test_inputs.pop();
|
||||
}
|
||||
else{
|
||||
tb->wr_data_push = 0;
|
||||
}
|
||||
|
||||
}
|
||||
else{
|
||||
tb->addr = rand();
|
||||
tb->rnw = rand() % 2;
|
||||
tb->is_amo = rand() % 2;
|
||||
tb->amo_type_or_burst_size = rand();
|
||||
tb->sub_id = rand();
|
||||
tb->wr_data = rand();
|
||||
|
||||
tb->request_push = 0;
|
||||
tb->wr_data_push = 0;
|
||||
}
|
||||
|
||||
if(tb->rd_data_valid){
|
||||
tb->rd_data_ack = 1;
|
||||
cout << "Data Recieved: " << tb->rd_data << endl;
|
||||
}
|
||||
else{
|
||||
tb->rd_data_ack = 0;
|
||||
}
|
||||
//Step
|
||||
axi_ddr.step();
|
||||
|
||||
tb->clk = 0;
|
||||
tb->eval();
|
||||
cycle_cout++;
|
||||
#ifdef TRACE_ON
|
||||
verilatorWaveformTracer->dump(vluint32_t(cycle_cout));
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#ifdef TRACE_ON
|
||||
verilatorWaveformTracer->flush();
|
||||
verilatorWaveformTracer->close();
|
||||
#endif
|
||||
|
||||
cout << "--------------------------------------------------------------\n";
|
||||
cout << " Simulation Completed\n";
|
||||
|
||||
logFile.close();
|
||||
sigFile.close();
|
||||
delete tb;
|
||||
exit(EXIT_SUCCESS);
|
||||
|
||||
}
|
|
@ -1,309 +0,0 @@
|
|||
/*
|
||||
* Copyright © 2017 Eric Matthews, Lesley Shannon
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Initial code developed under the supervision of Dr. Lesley Shannon,
|
||||
* Reconfigurable Computing Lab, Simon Fraser University.
|
||||
*
|
||||
* Author(s):
|
||||
* Eric Matthews <ematthew@sfu.ca>
|
||||
*/
|
||||
|
||||
import cva5_config::*;
|
||||
import cva5_types::*;
|
||||
import l2_config_and_types::*;
|
||||
|
||||
|
||||
module axi_l2_test # (
|
||||
parameter MEMORY_FILE = "/home/ematthew/Research/RISCV/software/riscv-tools/riscv-tests/benchmarks/dhrystone.riscv.hw_init" //change this to appropriate location "/home/ematthew/Downloads/dhrystone.riscv.sim_init"
|
||||
)
|
||||
(
|
||||
input logic clk,
|
||||
input logic rst,
|
||||
|
||||
//DDR AXI
|
||||
output logic [31:0]ddr_axi_araddr,
|
||||
output logic [1:0]ddr_axi_arburst,
|
||||
output logic [3:0]ddr_axi_arcache,
|
||||
output logic [5:0]ddr_axi_arid,
|
||||
output logic [7:0]ddr_axi_arlen,
|
||||
output logic [0:0]ddr_axi_arlock,
|
||||
output logic [2:0]ddr_axi_arprot,
|
||||
output logic [3:0]ddr_axi_arqos,
|
||||
input logic ddr_axi_arready,
|
||||
output logic [3:0]ddr_axi_arregion,
|
||||
output logic [2:0]ddr_axi_arsize,
|
||||
output logic ddr_axi_arvalid,
|
||||
output logic [31:0]ddr_axi_awaddr,
|
||||
output logic [1:0]ddr_axi_awburst,
|
||||
output logic [3:0]ddr_axi_awcache,
|
||||
output logic [5:0]ddr_axi_awid,
|
||||
output logic [7:0]ddr_axi_awlen,
|
||||
output logic [0:0]ddr_axi_awlock,
|
||||
output logic [2:0]ddr_axi_awprot,
|
||||
output logic [3:0]ddr_axi_awqos,
|
||||
input logic ddr_axi_awready,
|
||||
output logic [3:0]ddr_axi_awregion,
|
||||
output logic [2:0]ddr_axi_awsize,
|
||||
output logic ddr_axi_awvalid,
|
||||
output logic [5:0]ddr_axi_bid,
|
||||
output logic ddr_axi_bready,
|
||||
input logic [1:0]ddr_axi_bresp,
|
||||
input logic ddr_axi_bvalid,
|
||||
input logic [31:0]ddr_axi_rdata,
|
||||
input logic [5:0]ddr_axi_rid,
|
||||
input logic ddr_axi_rlast,
|
||||
output logic ddr_axi_rready,
|
||||
input logic [1:0]ddr_axi_rresp,
|
||||
input logic ddr_axi_rvalid,
|
||||
output logic [31:0]ddr_axi_wdata,
|
||||
output logic ddr_axi_wlast,
|
||||
input logic ddr_axi_wready,
|
||||
output logic [3:0]ddr_axi_wstrb,
|
||||
output logic ddr_axi_wvalid,
|
||||
output logic [5:0]ddr_axi_wid,
|
||||
|
||||
|
||||
//L2 interface
|
||||
input logic [29:0] addr,
|
||||
input logic rnw,
|
||||
input logic is_amo,
|
||||
input logic [4:0] amo_type_or_burst_size,
|
||||
input logic [L2_SUB_ID_W-1:0] sub_id,
|
||||
|
||||
input logic request_push,
|
||||
output logic request_full,
|
||||
|
||||
output logic [31:2] inv_addr,
|
||||
output logic inv_valid,
|
||||
input logic inv_ack,
|
||||
|
||||
output logic con_result,
|
||||
output logic con_valid,
|
||||
|
||||
input logic [31:0] wr_data,
|
||||
input logic [3:0] wr_data_be,
|
||||
input logic wr_data_push,
|
||||
output logic data_full,
|
||||
|
||||
output logic [31:0] rd_data,
|
||||
output logic [L2_SUB_ID_W-1:0] rd_sub_id,
|
||||
output logic rd_data_valid,
|
||||
input logic rd_data_ack,
|
||||
|
||||
//Local Memory
|
||||
output logic [29:0] instruction_bram_addr,
|
||||
output logic instruction_bram_en,
|
||||
output logic [3:0] instruction_bram_be,
|
||||
output logic [31:0] instruction_bram_data_in,
|
||||
input logic [31:0] instruction_bram_data_out,
|
||||
|
||||
output logic [29:0] data_bram_addr,
|
||||
output logic data_bram_en,
|
||||
output logic [3:0] data_bram_be,
|
||||
output logic [31:0] data_bram_data_in,
|
||||
input logic [31:0] data_bram_data_out,
|
||||
|
||||
//Used by verilator
|
||||
output logic write_uart,
|
||||
output logic [7:0] uart_byte,
|
||||
|
||||
//Trace Interface
|
||||
output logic instruction_issued,
|
||||
output logic cva5_events [0:$bits(cva5_trace_events_t)-1],
|
||||
output logic [31:0] instruction_pc_dec,
|
||||
output logic [31:0] instruction_data_dec
|
||||
);
|
||||
|
||||
logic [3:0] WRITE_COUNTER_MAX;
|
||||
logic [3:0] READ_COUNTER_MAX;
|
||||
assign READ_COUNTER_MAX = 4'b0101;
|
||||
assign WRITE_COUNTER_MAX = 4'b0101;
|
||||
|
||||
//AXI memory
|
||||
logic [31:0]axi_araddr;
|
||||
logic [1:0]axi_arburst;
|
||||
logic [3:0]axi_arcache;
|
||||
logic [5:0]axi_arid;
|
||||
logic [7:0]axi_arlen;
|
||||
logic [0:0]axi_arlock;
|
||||
logic [2:0]axi_arprot;
|
||||
logic [3:0]axi_arqos;
|
||||
logic axi_arready;
|
||||
logic [3:0]axi_arregion;
|
||||
logic [2:0]axi_arsize;
|
||||
logic axi_arvalid;
|
||||
logic [31:0]axi_awaddr;
|
||||
logic [1:0]axi_awburst;
|
||||
logic [3:0]axi_awcache;
|
||||
logic [5:0]axi_awid;
|
||||
logic [7:0]axi_awlen;
|
||||
logic [0:0]axi_awlock;
|
||||
logic [2:0]axi_awprot;
|
||||
logic [3:0]axi_awqos;
|
||||
logic axi_awready;
|
||||
logic [3:0]axi_awregion;
|
||||
logic [2:0]axi_awsize;
|
||||
logic axi_awvalid;
|
||||
logic [5:0]axi_bid;
|
||||
logic axi_bready;
|
||||
logic [1:0]axi_bresp;
|
||||
logic axi_bvalid;
|
||||
logic [31:0]axi_rdata;
|
||||
logic [5:0]axi_rid;
|
||||
logic axi_rlast;
|
||||
logic axi_rready;
|
||||
logic [1:0]axi_rresp;
|
||||
logic axi_rvalid;
|
||||
logic [31:0]axi_wdata;
|
||||
logic axi_wlast;
|
||||
logic axi_wready;
|
||||
logic [3:0]axi_wstrb;
|
||||
logic axi_wvalid;
|
||||
logic [5:0]axi_wid;
|
||||
|
||||
parameter SCRATCH_MEM_KB = 128;
|
||||
parameter MEM_LINES = (SCRATCH_MEM_KB*1024)/4;
|
||||
|
||||
logic interrupt;
|
||||
logic timer_interrupt;
|
||||
|
||||
assign interrupt = 0;
|
||||
|
||||
axi_interface m_axi();
|
||||
//axi_interface ddr_axi();
|
||||
avalon_interface m_avalon();
|
||||
wishbone_interface dwishbone();
|
||||
|
||||
l2_requester_interface l2[L2_NUM_PORTS-1:0]();
|
||||
l2_memory_interface mem();
|
||||
|
||||
local_memory_interface instruction_bram();
|
||||
local_memory_interface data_bram();
|
||||
|
||||
// assign m_axi.arready = bus_axi_arready;
|
||||
// assign bus_axi_arvalid = m_axi.arvalid;
|
||||
// assign bus_axi_araddr = m_axi.araddr;
|
||||
//
|
||||
//
|
||||
// //read data
|
||||
// assign bus_axi_rready = m_axi.rready;
|
||||
// assign m_axi.rvalid = bus_axi_rvalid;
|
||||
// assign m_axi.rdata = bus_axi_rdata;
|
||||
// assign m_axi.rresp = bus_axi_rresp;
|
||||
//
|
||||
// //Write channel
|
||||
// //write address
|
||||
// assign m_axi.awready = bus_axi_awready;
|
||||
// assign bus_axi_awaddr = m_axi.awaddr;
|
||||
// assign bus_axi_awvalid = m_axi.awvalid;
|
||||
//
|
||||
//
|
||||
// //write data
|
||||
// assign m_axi.wready = bus_axi_wready;
|
||||
// assign bus_axi_wvalid = m_axi. wvalid;
|
||||
// assign bus_axi_wdata = m_axi.wdata;
|
||||
// assign bus_axi_wstrb = m_axi.wstrb;
|
||||
//
|
||||
// //write response
|
||||
// assign bus_axi_bready = m_axi.bready;
|
||||
// assign m_axi.bvalid = bus_axi_bvalid;
|
||||
// assign m_axi.bresp = bus_axi_bresp;
|
||||
|
||||
assign l2[0].addr = addr;
|
||||
assign l2[0].rnw = rnw;
|
||||
assign l2[0].is_amo = is_amo;
|
||||
assign l2[0].amo_type_or_burst_size = amo_type_or_burst_size;
|
||||
assign l2[0].sub_id = sub_id;
|
||||
|
||||
assign l2[0].request_push = request_push;
|
||||
assign request_full = l2[0].request_full;
|
||||
|
||||
assign inv_addr = l2[0].inv_addr;
|
||||
assign inv_valid = l2[0].inv_valid;
|
||||
assign l2[0].inv_ack = inv_ack;
|
||||
|
||||
assign con_result = l2[0].con_result;
|
||||
assign con_valid = l2[0].con_valid;
|
||||
|
||||
assign l2[0].wr_data = wr_data;
|
||||
assign l2[0].wr_data_be = wr_data_be;
|
||||
assign l2[0].wr_data_push = wr_data_push;
|
||||
assign data_full = l2[0].data_full;
|
||||
|
||||
assign rd_data = l2[0].rd_data;
|
||||
assign rd_sub_id = l2[0].rd_sub_id;
|
||||
assign rd_data_valid = l2[0].rd_data_valid;
|
||||
assign l2[0].rd_data_ack = rd_data_ack;
|
||||
|
||||
|
||||
assign l2[1].request_push = 0;
|
||||
assign l2[1].wr_data_push = 0;
|
||||
assign l2[1].inv_ack = l2[1].inv_valid;
|
||||
assign l2[1].rd_data_ack = l2[1].rd_data_valid;
|
||||
|
||||
axi_to_arb l2_to_mem (.*, .l2(mem));
|
||||
l2_arbiter l2_arb (.*, .request(l2));
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
//DDR AXI interface
|
||||
assign ddr_axi_araddr = axi_araddr;
|
||||
assign ddr_axi_arburst = axi_arburst;
|
||||
assign ddr_axi_arcache = axi_arcache;
|
||||
assign ddr_axi_arid = axi_arid;
|
||||
assign ddr_axi_arlen = axi_arlen;
|
||||
assign axi_arready = ddr_axi_arready;
|
||||
assign ddr_axi_arsize = axi_arsize;
|
||||
assign ddr_axi_arvalid = axi_arvalid;
|
||||
|
||||
assign ddr_axi_awaddr = axi_awaddr;
|
||||
assign ddr_axi_awburst = axi_awburst;
|
||||
assign ddr_axi_awcache = axi_awcache;
|
||||
assign ddr_axi_awid = axi_awid;
|
||||
assign ddr_axi_awlen = axi_awlen;
|
||||
assign axi_awready = ddr_axi_awready;
|
||||
assign ddr_axi_awvalid = axi_awvalid;
|
||||
|
||||
assign axi_bid = ddr_axi_bid;
|
||||
assign ddr_axi_bready = axi_bready;
|
||||
assign axi_bresp = ddr_axi_bresp;
|
||||
assign axi_bvalid = ddr_axi_bvalid;
|
||||
|
||||
assign axi_rdata = ddr_axi_rdata;
|
||||
assign axi_rid = ddr_axi_rid;
|
||||
assign axi_rlast = ddr_axi_rlast;
|
||||
assign ddr_axi_rready = axi_rready;
|
||||
assign axi_rresp = ddr_axi_rresp;
|
||||
assign axi_rvalid = ddr_axi_rvalid;
|
||||
|
||||
assign ddr_axi_wdata = axi_wdata;
|
||||
assign ddr_axi_wlast = axi_wlast;
|
||||
assign axi_wready = ddr_axi_wready;
|
||||
assign ddr_axi_wstrb = axi_wstrb;
|
||||
assign ddr_axi_wvalid = axi_wvalid;
|
||||
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
//Trace Interface
|
||||
assign instruction_pc_dec = tr.instruction_pc_dec;
|
||||
assign instruction_data_dec = tr.instruction_data_dec;
|
||||
assign instruction_issued = tr.events.instruction_issued_dec;
|
||||
logic [$bits(cva5_trace_events_t)-1:0] cva5_events_packed;
|
||||
assign cva5_events_packed = tr.events;
|
||||
always_comb begin
|
||||
foreach(cva5_events_packed[i])
|
||||
cva5_events[$bits(cva5_trace_events_t)-1-i] = cva5_events_packed[i];
|
||||
end
|
||||
|
||||
endmodule
|
|
@ -1,10 +0,0 @@
|
|||
#include "ddr_page.h"
|
||||
|
||||
ddr_page::ddr_page(){
|
||||
}
|
||||
uint32_t ddr_page::return_data(int data_address){
|
||||
return data[data_address];
|
||||
}
|
||||
void ddr_page::write_data(int data_address, int data_input){
|
||||
data[data_address] = data_input;
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
#ifndef DDR_PAGEH
|
||||
#define DDR_PAGEH
|
||||
#include <stdint.h>
|
||||
|
||||
class ddr_page{
|
||||
public:
|
||||
ddr_page();
|
||||
uint32_t return_data(int data_address);
|
||||
void write_data(int data_address, int data);
|
||||
private:
|
||||
uint32_t data[PAGE_SIZE/4];
|
||||
};
|
||||
#endif
|
|
@ -1,36 +0,0 @@
|
|||
#include "axi_ddr_sim.h"
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <fstream>
|
||||
using namespace std;
|
||||
|
||||
|
||||
void DDR_file_init(string filename,int num_entries){
|
||||
ofstream init_file;
|
||||
init_file.open(filename);
|
||||
for (int i = 0; i < num_entries; i++ ){
|
||||
init_file << setfill('0') << setw(8) << hex << i << endl;
|
||||
}
|
||||
};
|
||||
int print_DDR_init(string filepath,uint32_t starting_memory_location, int number_of_bytes){
|
||||
axi_ddr_sim AXI_DDR(filepath, starting_memory_location, number_of_bytes);
|
||||
|
||||
ifstream input_memory_file;
|
||||
input_memory_file.open(filepath);
|
||||
string line;
|
||||
for(int data_index = starting_memory_location; data_index < int(starting_memory_location + number_of_bytes); data_index+=4){
|
||||
cout << "[" << data_index << "]: " << AXI_DDR.get_data(data_index) << endl;
|
||||
|
||||
}
|
||||
cout << "Starting Location: " << starting_memory_location << endl;
|
||||
cout << "Final value should be: " << number_of_bytes/4 - 1 << endl;
|
||||
return 0;
|
||||
};
|
||||
|
||||
int main(){
|
||||
int num_entries = PAGE_SIZE * 5;
|
||||
uint32_t starting_location = PAGE_SIZE*0;
|
||||
DDR_file_init("DDR_init.txt",num_entries);
|
||||
print_DDR_init("DDR_init.txt", starting_location, num_entries*4);
|
||||
return 0;
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright © 2019 Eric Matthews, Lesley Shannon
|
||||
* Copyright © 2019 Eric Matthews, Chris Keilbart, Lesley Shannon
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -18,6 +18,7 @@
|
|||
*
|
||||
* Author(s):
|
||||
* Eric Matthews <ematthew@sfu.ca>
|
||||
* Chris Keilbart <ckeilbar@sfu.ca>
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
|
@ -73,12 +74,10 @@ bool CVA5Tracer::store_queue_empty() {
|
|||
void CVA5Tracer::reset() {
|
||||
tb->clk = 0;
|
||||
tb->rst = 1;
|
||||
for (int i=0; i <reset_length; i++){
|
||||
for (int i=0; i < reset_length; i++)
|
||||
tick();
|
||||
}
|
||||
|
||||
tb->rst = 0;
|
||||
std::cout << "DONE System reset \n" << std::flush;
|
||||
}
|
||||
|
||||
void CVA5Tracer::set_log_file(std::ofstream* logFile) {
|
||||
|
@ -96,42 +95,41 @@ void CVA5Tracer::update_UART() {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
void CVA5Tracer::update_memory() {
|
||||
void CVA5Tracer::memory_pre() {
|
||||
tb->instruction_bram_data_out = instruction_r;
|
||||
tb->data_bram_data_out = data_out_r;
|
||||
}
|
||||
|
||||
void CVA5Tracer::memory_post() {
|
||||
if (tb->instruction_bram_en)
|
||||
instruction_r = mem->read(tb->instruction_bram_addr);
|
||||
|
||||
tb->data_bram_data_out = data_out_r;
|
||||
if (tb->data_bram_en) {
|
||||
data_out_r = mem->read(tb->data_bram_addr);
|
||||
mem->write(tb->data_bram_addr, tb->data_bram_data_in, tb->data_bram_be);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void CVA5Tracer::tick() {
|
||||
cycle_count++;
|
||||
//Rising edge
|
||||
cycle_count++;
|
||||
tb->clk = 1;
|
||||
tb->eval();
|
||||
|
||||
tb->clk = 1;
|
||||
tb->eval();
|
||||
#ifdef TRACE_ON
|
||||
verilatorWaveformTracer->dump(vluint32_t(cycle_count));
|
||||
#endif
|
||||
cycle_count++;
|
||||
//Set outputs
|
||||
axi_ddr->pre();
|
||||
memory_pre();
|
||||
tb->eval();
|
||||
|
||||
tb->clk = 0;
|
||||
tb->eval();
|
||||
#ifdef TRACE_ON
|
||||
verilatorWaveformTracer->dump(vluint32_t(cycle_count));
|
||||
#endif
|
||||
//Respond to inputs
|
||||
axi_ddr->post();
|
||||
memory_post();
|
||||
|
||||
tb->clk = 1;
|
||||
tb->eval();
|
||||
axi_ddr->step();
|
||||
update_UART();
|
||||
update_memory();
|
||||
#ifdef TRACE_ON
|
||||
verilatorWaveformTracer->dump(vluint32_t(cycle_count));
|
||||
#endif
|
||||
|
||||
update_UART();
|
||||
#ifdef PC_TRACE_ON
|
||||
for (int i =0; i < tb->NUM_RETIRE_PORTS; i++) {
|
||||
if (logPC && tb->retire_ports_valid[i]) {
|
||||
|
@ -140,9 +138,15 @@ void CVA5Tracer::tick() {
|
|||
}
|
||||
#endif
|
||||
|
||||
//Falling edge
|
||||
cycle_count++;
|
||||
tb->clk = 0;
|
||||
tb->eval();
|
||||
#ifdef TRACE_ON
|
||||
verilatorWaveformTracer->dump(vluint32_t(cycle_count));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void CVA5Tracer::start_tracer(const char *trace_file) {
|
||||
#ifdef TRACE_ON
|
||||
verilatorWaveformTracer = new VerilatedFstC;
|
||||
|
@ -151,32 +155,24 @@ void CVA5Tracer::start_tracer(const char *trace_file) {
|
|||
#endif
|
||||
}
|
||||
|
||||
|
||||
uint64_t CVA5Tracer::cycle_count = 0;
|
||||
uint64_t CVA5Tracer::get_cycle_count() {
|
||||
return cycle_count;
|
||||
}
|
||||
|
||||
|
||||
CVA5Tracer::CVA5Tracer(std::ifstream& programFile) {
|
||||
CVA5Tracer::CVA5Tracer(std::ifstream (&programFile)[1]) {
|
||||
cycle_count = 0;
|
||||
|
||||
#ifdef TRACE_ON
|
||||
Verilated::traceEverOn(true);
|
||||
#endif
|
||||
|
||||
|
||||
tb = new Vcva5_sim;
|
||||
|
||||
#ifdef DDR_LOAD_FILE
|
||||
axi_ddr = new axi_ddr_sim(DDR_INIT_FILE,DDR_FILE_STARTING_LOCATION,DDR_FILE_NUM_BYTES);
|
||||
#else
|
||||
axi_ddr = new axi_ddr_sim(programFile, tb);
|
||||
|
||||
#endif
|
||||
programFile.clear();
|
||||
programFile.seekg(0, ios::beg);
|
||||
mem = new SimMem(programFile, 128);
|
||||
|
||||
axi_ddr = new AXIMem(programFile, tb);
|
||||
programFile[0].clear();
|
||||
programFile[0].seekg(0, ios::beg);
|
||||
mem = new SimMem(programFile);
|
||||
|
||||
instruction_r = mem->read(tb->instruction_bram_addr);
|
||||
data_out_r = 0;
|
||||
|
@ -189,5 +185,6 @@ CVA5Tracer::~CVA5Tracer() {
|
|||
verilatorWaveformTracer->close();
|
||||
#endif
|
||||
delete mem;
|
||||
delete axi_ddr;
|
||||
delete tb;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright © 2019 Eric Matthews, Lesley Shannon
|
||||
* Copyright © 2019 Eric Matthews, Chris Keilbart, Lesley Shannon
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -18,6 +18,7 @@
|
|||
*
|
||||
* Author(s):
|
||||
* Eric Matthews <ematthew@sfu.ca>
|
||||
* Chris Keilbart <ckeilbar@sfu.ca>
|
||||
*/
|
||||
|
||||
#ifndef CVA5Tracer_H
|
||||
|
@ -29,7 +30,7 @@
|
|||
#include "verilated_fst_c.h"
|
||||
#include "Vcva5_sim.h"
|
||||
#include "SimMem.h"
|
||||
#include "AXI_DDR_simulation/axi_ddr_sim.h"
|
||||
#include "AXIMem.h"
|
||||
//#define TRACE_ON
|
||||
|
||||
#define COMPLIANCE_SIG_PHASE_NOP 0x00B00013U
|
||||
|
@ -42,7 +43,7 @@
|
|||
//Testbench with CVA5 trace outputs on toplevel
|
||||
class CVA5Tracer {
|
||||
public:
|
||||
CVA5Tracer(std::ifstream& programFile);
|
||||
CVA5Tracer(std::ifstream (&programFile)[1]);
|
||||
~CVA5Tracer();
|
||||
bool check_if_instruction_retired(uint32_t instruction);
|
||||
bool has_terminated();
|
||||
|
@ -59,7 +60,7 @@ public:
|
|||
//DDR Simulation
|
||||
Vcva5_sim *tb;
|
||||
private:
|
||||
axi_ddr_sim * axi_ddr;
|
||||
AXIMem *axi_ddr;
|
||||
SimMem *mem;
|
||||
#ifdef TRACE_ON
|
||||
VerilatedFstC *verilatorWaveformTracer;
|
||||
|
@ -76,7 +77,8 @@ private:
|
|||
bool program_complete = false;
|
||||
|
||||
void update_UART();
|
||||
void update_memory();
|
||||
void memory_pre();
|
||||
void memory_post();
|
||||
uint32_t instruction_r;
|
||||
uint32_t data_out_r;
|
||||
};
|
||||
|
|
76
test_benches/verilator/SimMem.cc
Normal file → Executable file
76
test_benches/verilator/SimMem.cc
Normal file → Executable file
|
@ -1,24 +1,70 @@
|
|||
#include <sstream>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
/*
|
||||
* Copyright © 2019 Eric Matthews, Chris Keilbart, Lesley Shannon
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Initial code developed under the supervision of Dr. Lesley Shannon,
|
||||
* Reconfigurable Computing Lab, Simon Fraser University.
|
||||
*
|
||||
* Author(s):
|
||||
* Eric Matthews <ematthew@sfu.ca>
|
||||
* Chris Keilbart <ckeilbar@sfu.ca>
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <cstring>
|
||||
#include "SimMem.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
//Support files in hex or raw binary form
|
||||
SimMem::SimMem(ifstream (&memFiles)[NUM_CORES]) {
|
||||
string line_hex;
|
||||
uint32_t addr;
|
||||
uint32_t line_bin;
|
||||
|
||||
SimMem::SimMem(std::ifstream& program, uint32_t mem_size) : mem_size(mem_size) {
|
||||
memory = new uint32_t[mem_size*256]();//mem_size in KB
|
||||
address_mask = (mem_size*256) - 1; //mask to prevent any out-of-bounds array access. Assumes power-of-two memory size
|
||||
for (int i = 0; i < NUM_CORES; i++) {
|
||||
addr = (STARTING_ADDR + i*PROGRAM_SPACING) >> 2; //Only handle 32b memory words
|
||||
|
||||
std::string line;
|
||||
for (int i =0; (i < mem_size*256) && (std::getline(program, line)); i++) {
|
||||
memory[i] = std::stoul(line, 0, 16);
|
||||
//Hex files have one 32 bit hexadecimal number per line, we check the first line to determine file type
|
||||
getline(memFiles[i], line_hex);
|
||||
bool fileIsHex = line_hex.size() == 8;
|
||||
try {
|
||||
stoul(line_hex, 0, 16);
|
||||
}
|
||||
catch (invalid_argument& ex) {
|
||||
fileIsHex = false;
|
||||
}
|
||||
memFiles[i].clear();
|
||||
memFiles[i].seekg(0, ios::beg);
|
||||
|
||||
//Then iterate over pages
|
||||
while (!memFiles[i].eof()) {
|
||||
if (fileIsHex) {
|
||||
getline(memFiles[i], line_hex);
|
||||
line_bin = stoul(line_hex, 0, 16);
|
||||
}
|
||||
else
|
||||
memFiles[i].read((char*) &line_bin, 4);
|
||||
|
||||
memory[addr++] = line_bin;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
uint32_t SimMem::read(uint32_t addr) {
|
||||
return memory[addr & address_mask];
|
||||
return memory[addr]; //Will insert 0 if not present
|
||||
}
|
||||
|
||||
void SimMem::write(uint32_t addr, uint32_t data, uint32_t be) {
|
||||
|
@ -35,10 +81,6 @@ void SimMem::write(uint32_t addr, uint32_t data, uint32_t be) {
|
|||
if (be & 0x8)
|
||||
write_mask |= 0xFF000000L;
|
||||
|
||||
old_word = memory[addr & address_mask];
|
||||
memory[addr & address_mask] = (old_word & ~write_mask) | (data & write_mask);
|
||||
}
|
||||
|
||||
SimMem::~SimMem() {
|
||||
delete[] memory;
|
||||
old_word = memory[addr]; //Will insert 0 if not present
|
||||
memory[addr] = (old_word & ~write_mask) | (data & write_mask);
|
||||
}
|
||||
|
|
34
test_benches/verilator/SimMem.h
Normal file → Executable file
34
test_benches/verilator/SimMem.h
Normal file → Executable file
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright © 2019 Eric Matthews, Lesley Shannon
|
||||
* Copyright © 2019 Eric Matthews, Chris Keilbart, Lesley Shannon
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -18,23 +18,37 @@
|
|||
*
|
||||
* Author(s):
|
||||
* Eric Matthews <ematthew@sfu.ca>
|
||||
* Chris Keilbart <ckeilbar@sfu.ca>
|
||||
*/
|
||||
|
||||
#ifndef SIMMEM_H
|
||||
#define SIMMEM_H
|
||||
#include <stdlib.h>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <unordered_map>
|
||||
#include <queue>
|
||||
#include <cstdint>
|
||||
|
||||
using namespace std;
|
||||
|
||||
//Default defines; can be overridden by command line
|
||||
#ifndef NUM_CORES
|
||||
#define NUM_CORES 1
|
||||
#endif
|
||||
#ifndef STARTING_ADDR
|
||||
#define STARTING_ADDR 0x80000000
|
||||
#endif
|
||||
#ifndef PROGRAM_SPACING
|
||||
#define PROGRAM_SPACING 0x04000000
|
||||
#endif
|
||||
|
||||
class SimMem {
|
||||
public:
|
||||
SimMem(std::ifstream& program, uint32_t mem_size);
|
||||
~SimMem();
|
||||
void write (uint32_t addr, uint32_t data, uint32_t be);
|
||||
uint32_t read (uint32_t addr);
|
||||
SimMem(ifstream (&memFiles)[NUM_CORES]);
|
||||
void write(uint32_t addr, uint32_t data, uint32_t be);
|
||||
uint32_t read(uint32_t addr);
|
||||
private:
|
||||
uint32_t mem_size;
|
||||
uint32_t *memory;
|
||||
uint32_t address_mask;
|
||||
queue<uint32_t> i_queue[NUM_CORES];
|
||||
queue<uint32_t> d_queue[NUM_CORES];
|
||||
unordered_map<uint32_t,uint32_t> memory;
|
||||
};
|
||||
#endif
|
||||
|
|
|
@ -23,7 +23,7 @@ const char* cva5_csv_log_file_name () {
|
|||
using namespace std;
|
||||
int main(int argc, char **argv) {
|
||||
ofstream logFile, sigFile, pcFile;
|
||||
ifstream programFile;
|
||||
ifstream programFile[1];
|
||||
|
||||
// Initialize Verilators variables
|
||||
Verilated::commandArgs(argc, argv);
|
||||
|
@ -50,7 +50,7 @@ int main(int argc, char **argv) {
|
|||
|
||||
logFile.open (argv[1]);
|
||||
sigFile.open (argv[2]);
|
||||
programFile.open (argv[3]);
|
||||
programFile[0].open (argv[3]);
|
||||
|
||||
if (!logFile.is_open()) {
|
||||
cout << "Failed to open logfile: " << argv[1] << endl;
|
||||
|
@ -107,7 +107,7 @@ int main(int argc, char **argv) {
|
|||
|
||||
logFile.close();
|
||||
sigFile.close();
|
||||
programFile.close();
|
||||
programFile[0].close();
|
||||
pcFile.close();
|
||||
|
||||
delete cva5Tracer;
|
||||
|
|
|
@ -3,53 +3,21 @@ VERILATOR_DIR=$(CVA5_DIR)/test_benches/verilator
|
|||
|
||||
# Sources for verilator
|
||||
CVA5_HW_SRCS = $(addprefix $(CVA5_DIR)/, $(shell cat $(CVA5_DIR)/tools/compile_order))
|
||||
CVA5_SIM_SRCS = $(addprefix $(VERILATOR_DIR)/, CVA5Tracer.cc SimMem.cc cva5_sim.cc AXI_DDR_simulation/axi_ddr_sim.cc AXI_DDR_simulation/ddr_page.cc)
|
||||
CVA5_INCLUDED_SIM_SRCS = $(addprefix $(VERILATOR_DIR)/, cva5_sim.cc AXI_DDR_simulation/ddr_page.cc SimMem.cc)
|
||||
CVA5_SIM_SRCS = $(addprefix $(VERILATOR_DIR)/, CVA5Tracer.cc SimMem.cc AXIMem.cc cva5_sim.cc)
|
||||
|
||||
|
||||
#Tracing: Set to True or False
|
||||
TRACE_ENABLE?=False
|
||||
|
||||
TRACE_ENABLE = True
|
||||
|
||||
#Simulation Binary Name
|
||||
CVA5_SIM_DIR?=$(VERILATOR_DIR)/build
|
||||
CVA5_SIM?=$(CVA5_SIM_DIR)/cva5-sim
|
||||
|
||||
#(to-do)DDR Pre-Initialization
|
||||
#LOAD_DDR_FROM_FILE = False
|
||||
#DDR_FILE = "\"path_to_DDR_init_file\""
|
||||
#DDR_FILE_STARTING_LOCATION = 0
|
||||
#DDR_FILE_NUM_BYTES = 0
|
||||
|
||||
#AXI DDR Parameters
|
||||
DDR_SIZE_GB = 4
|
||||
PAGE_SIZE_KB = 2
|
||||
MAX_READ_REQ = 8
|
||||
MAX_WRITE_REQ = $(MAX_READ_REQ)
|
||||
MIN_RD_DELAY = 15
|
||||
MAX_RD_DELAY = 30
|
||||
MIN_WR_DELAY = 1
|
||||
MAX_WR_DELAY = 1
|
||||
DELAY_SEED = 867583
|
||||
######################################################################
|
||||
ddr_size_def = DDR_SIZE=\(long\)$(DDR_SIZE_GB)*\(long\)1073741824
|
||||
page_size_def = PAGE_SIZE=\($(PAGE_SIZE_KB)*1024\)
|
||||
max_inflight_read_requests = MAX_INFLIGHT_RD_REQ=$(MAX_READ_REQ)
|
||||
max_inflight_write_requests = MAX_INFLIGHT_WR_REQ=$(MAX_WRITE_REQ)
|
||||
mix_delay_read = MIN_DELAY_RD=$(MIN_RD_DELAY)
|
||||
max_delay_read = MAX_DELAY_RD=$(MAX_RD_DELAY)
|
||||
min_delay_write = MIN_DELAY_WR=$(MIN_WR_DELAY)
|
||||
max_delay_write = MAX_DELAY_WR=$(MAX_WR_DELAY)
|
||||
delay_seed = DELAY_SEED=$(DELAY_SEED)
|
||||
#(to-do)
|
||||
#ddr_init_file = DDR_INIT_FILE=$(DDR_FILE)
|
||||
#ddr_start_loc = DDR_FILE_STARTING_LOCATION=$(DDR_FILE_STARTING_LOCATION)
|
||||
#ddr_num_bytes = DDR_FILE_NUM_BYTES=$(DDR_FILE_NUM_BYTES)
|
||||
DETERMINISTIC?=0
|
||||
|
||||
CFLAGS = -g0 -O3 -std=c++14 -march=native -D$(ddr_size_def) -D$(page_size_def) -D$(max_inflight_read_requests) -D$(max_inflight_write_requests)\
|
||||
-D$(mix_delay_read) -D$(max_delay_read) -D$(min_delay_write) -D$(max_delay_write) -D$(delay_seed)
|
||||
|
||||
#(to-do)-D$(ddr_init_file) -D$(ddr_start_loc) -D$(ddr_num_bytes)
|
||||
CFLAGS = -g0 -O3 -std=c++14 -march=native -DDETERMINISTIC=$(DETERMINISTIC)
|
||||
|
||||
#Verilator
|
||||
################################################################################
|
||||
|
@ -62,10 +30,6 @@ endif
|
|||
|
||||
VERILATOR_LINT_IGNORE= -Wno-LITENDIAN -Wno-SYMRSVDWORD
|
||||
|
||||
#(to-do)
|
||||
#ifeq ($(LOAD_DDR_FROM_FILE), True)
|
||||
# VERILATOR_CFLAGS := $(VERILATOR_CFLAGS) -D LOAD_DDR_FROM_FILE"
|
||||
#endif
|
||||
|
||||
##################################################################################
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue