Vortex 2.0 changes:
+ Microarchitecture optimizations + 64-bit support + Xilinx FPGA support + LLVM-16 support + Refactoring and quality control fixes minor update minor update minor update minor update minor update minor update cleanup cleanup cache bindings and memory perf refactory minor update minor update hw unit tests fixes minor update minor update minor update minor update minor update minor udpate minor update minor update minor update minor update minor update minor update minor update minor updates minor updates minor update minor update minor update minor update minor update minor update minor updates minor updates minor updates minor updates minor update minor update
This commit is contained in:
@@ -1,3 +1,16 @@
|
||||
// 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 "processor.h"
|
||||
|
||||
#include <verilated.h>
|
||||
@@ -56,6 +69,14 @@
|
||||
#define VERILATOR_RESET_VALUE 2
|
||||
#endif
|
||||
|
||||
#if (XLEN == 32)
|
||||
typedef uint32_t Word;
|
||||
#elif (XLEN == 64)
|
||||
typedef uint64_t Word;
|
||||
#else
|
||||
#error unsupported XLEN
|
||||
#endif
|
||||
|
||||
#define VL_WDATA_GETW(lwp, i, n, w) \
|
||||
VL_SEL_IWII(0, n * w, 0, 0, lwp, i * w, w)
|
||||
|
||||
@@ -71,7 +92,7 @@ double sc_time_stamp() {
|
||||
|
||||
static bool trace_enabled = false;
|
||||
static uint64_t trace_start_time = TRACE_START_TIME;
|
||||
static uint64_t trace_stop_time = TRACE_STOP_TIME;
|
||||
static uint64_t trace_stop_time = TRACE_STOP_TIME;
|
||||
|
||||
bool sim_trace_enabled() {
|
||||
if (timestamp >= trace_start_time
|
||||
@@ -126,6 +147,9 @@ public:
|
||||
|
||||
// reset the device
|
||||
this->reset();
|
||||
|
||||
// Turn on assertion after reset
|
||||
Verilated::assertOn(true);
|
||||
}
|
||||
|
||||
~Impl() {
|
||||
@@ -165,27 +189,46 @@ public:
|
||||
std::cout << std::dec << timestamp << ": [sim] run()" << std::endl;
|
||||
#endif
|
||||
|
||||
// reset device
|
||||
this->reset();
|
||||
// start execution
|
||||
running_ = true;
|
||||
device_->reset = 0;
|
||||
|
||||
// execute program
|
||||
// wait on device to go busy
|
||||
while (!device_->busy) {
|
||||
this->tick();
|
||||
}
|
||||
|
||||
// wait on device to go idle
|
||||
while (device_->busy) {
|
||||
if (get_ebreak()) {
|
||||
exitcode = get_last_wb_value(3);
|
||||
exitcode = (int)get_last_wb_value(3);
|
||||
break;
|
||||
}
|
||||
this->tick();
|
||||
}
|
||||
|
||||
// reset device
|
||||
this->reset();
|
||||
|
||||
// wait 5 cycles to flush the pipeline
|
||||
this->wait(5);
|
||||
this->cout_flush();
|
||||
|
||||
return exitcode;
|
||||
}
|
||||
|
||||
void write_dcr(uint32_t addr, uint32_t value) {
|
||||
device_->dcr_wr_valid = 1;
|
||||
device_->dcr_wr_addr = addr;
|
||||
device_->dcr_wr_data = value;
|
||||
while (device_->dcr_wr_valid) {
|
||||
this->tick();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void reset() {
|
||||
void reset() {
|
||||
running_ = false;
|
||||
|
||||
print_bufs_.clear();
|
||||
|
||||
pending_mem_reqs_.clear();
|
||||
@@ -199,6 +242,8 @@ private:
|
||||
this->reset_avs_bus();
|
||||
#endif
|
||||
|
||||
this->reset_dcr_bus();
|
||||
|
||||
device_->reset = 1;
|
||||
|
||||
for (int i = 0; i < RESET_DELAY; ++i) {
|
||||
@@ -206,14 +251,7 @@ private:
|
||||
this->eval();
|
||||
device_->clk = 1;
|
||||
this->eval();
|
||||
}
|
||||
|
||||
device_->reset = 0;
|
||||
|
||||
// Turn on assertion after reset
|
||||
Verilated::assertOn(true);
|
||||
|
||||
this->cout_flush();
|
||||
}
|
||||
}
|
||||
|
||||
void tick() {
|
||||
@@ -226,6 +264,7 @@ private:
|
||||
#else
|
||||
this->eval_avs_bus(0);
|
||||
#endif
|
||||
this->eval_dcr_bus(0);
|
||||
|
||||
device_->clk = 1;
|
||||
this->eval();
|
||||
@@ -235,6 +274,7 @@ private:
|
||||
#else
|
||||
this->eval_avs_bus(1);
|
||||
#endif
|
||||
this->eval_dcr_bus(1);
|
||||
|
||||
if (MEM_CYCLE_RATIO > 0) {
|
||||
auto cycle = timestamp / 2;
|
||||
@@ -260,6 +300,8 @@ private:
|
||||
#ifdef VCD_OUTPUT
|
||||
if (sim_trace_enabled()) {
|
||||
trace_->dump(timestamp);
|
||||
} else {
|
||||
exit(-1);
|
||||
}
|
||||
#endif
|
||||
++timestamp;
|
||||
@@ -268,30 +310,30 @@ private:
|
||||
#ifdef AXI_BUS
|
||||
|
||||
void reset_axi_bus() {
|
||||
device_->m_axi_wready = 0;
|
||||
device_->m_axi_awready = 0;
|
||||
device_->m_axi_arready = 0;
|
||||
device_->m_axi_rvalid = 0;
|
||||
device_->m_axi_bvalid = 0;
|
||||
device_->m_axi_wready[0] = 0;
|
||||
device_->m_axi_awready[0] = 0;
|
||||
device_->m_axi_arready[0] = 0;
|
||||
device_->m_axi_rvalid[0] = 0;
|
||||
device_->m_axi_bvalid[0] = 0;
|
||||
}
|
||||
|
||||
void eval_axi_bus(bool clk) {
|
||||
if (!clk) {
|
||||
mem_rd_rsp_ready_ = device_->m_axi_rready;
|
||||
mem_wr_rsp_ready_ = device_->m_axi_bready;
|
||||
mem_rd_rsp_ready_ = device_->m_axi_rready[0];
|
||||
mem_wr_rsp_ready_ = device_->m_axi_bready[0];
|
||||
return;
|
||||
}
|
||||
|
||||
if (ram_ == nullptr) {
|
||||
device_->m_axi_wready = 0;
|
||||
device_->m_axi_awready = 0;
|
||||
device_->m_axi_arready = 0;
|
||||
device_->m_axi_wready[0] = 0;
|
||||
device_->m_axi_awready[0] = 0;
|
||||
device_->m_axi_arready[0] = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// process memory responses
|
||||
if (mem_rd_rsp_active_
|
||||
&& device_->m_axi_rvalid && mem_rd_rsp_ready_) {
|
||||
&& device_->m_axi_rvalid[0] && mem_rd_rsp_ready_) {
|
||||
mem_rd_rsp_active_ = false;
|
||||
}
|
||||
if (!mem_rd_rsp_active_) {
|
||||
@@ -299,30 +341,30 @@ private:
|
||||
&& (*pending_mem_reqs_.begin())->ready
|
||||
&& !(*pending_mem_reqs_.begin())->write) {
|
||||
auto mem_rsp_it = pending_mem_reqs_.begin();
|
||||
auto mem_req = *mem_rsp_it;
|
||||
auto mem_rsp = *mem_rsp_it;
|
||||
/*
|
||||
printf("%0ld: [sim] MEM Rd Rsp: bank=%d, addr=%0lx, data=", timestamp, last_mem_rsp_bank_, mem_req->addr);
|
||||
printf("%0ld: [sim] MEM Rd Rsp: bank=%d, addr=%0lx, data=", timestamp, last_mem_rsp_bank_, mem_rsp->addr);
|
||||
for (int i = 0; i < MEM_BLOCK_SIZE; i++) {
|
||||
printf("%02x", mem_req->block[(MEM_BLOCK_SIZE-1)-i]);
|
||||
printf("%02x", mem_rsp->block[(MEM_BLOCK_SIZE-1)-i]);
|
||||
}
|
||||
printf("\n");
|
||||
*/
|
||||
device_->m_axi_rvalid = 1;
|
||||
device_->m_axi_rid = mem_req->tag;
|
||||
device_->m_axi_rresp = 0;
|
||||
device_->m_axi_rlast = 1;
|
||||
memcpy((uint8_t*)device_->m_axi_rdata, mem_req->block.data(), MEM_BLOCK_SIZE);
|
||||
device_->m_axi_rvalid[0] = 1;
|
||||
device_->m_axi_rid[0] = mem_rsp->tag;
|
||||
device_->m_axi_rresp[0] = 0;
|
||||
device_->m_axi_rlast[0] = 1;
|
||||
memcpy(device_->m_axi_rdata[0].data(), mem_rsp->block.data(), MEM_BLOCK_SIZE);
|
||||
pending_mem_reqs_.erase(mem_rsp_it);
|
||||
mem_rd_rsp_active_ = true;
|
||||
delete mem_req;
|
||||
delete mem_rsp;
|
||||
} else {
|
||||
device_->m_axi_rvalid = 0;
|
||||
device_->m_axi_rvalid[0] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// send memory write response
|
||||
if (mem_wr_rsp_active_
|
||||
&& device_->m_axi_bvalid && mem_wr_rsp_ready_) {
|
||||
&& device_->m_axi_bvalid[0] && mem_wr_rsp_ready_) {
|
||||
mem_wr_rsp_active_ = false;
|
||||
}
|
||||
if (!mem_wr_rsp_active_) {
|
||||
@@ -330,34 +372,34 @@ private:
|
||||
&& (*pending_mem_reqs_.begin())->ready
|
||||
&& (*pending_mem_reqs_.begin())->write) {
|
||||
auto mem_rsp_it = pending_mem_reqs_.begin();
|
||||
auto mem_req = *mem_rsp_it;
|
||||
auto mem_rsp = *mem_rsp_it;
|
||||
/*
|
||||
printf("%0ld: [sim] MEM Wr Rsp: bank=%d, addr=%0lx\n", timestamp, last_mem_rsp_bank_, mem_req->addr);
|
||||
printf("%0ld: [sim] MEM Wr Rsp: bank=%d, addr=%0lx\n", timestamp, last_mem_rsp_bank_, mem_rsp->addr);
|
||||
*/
|
||||
device_->m_axi_bvalid = 1;
|
||||
device_->m_axi_bid = mem_req->tag;
|
||||
device_->m_axi_bresp = 0;
|
||||
device_->m_axi_bvalid[0] = 1;
|
||||
device_->m_axi_bid[0] = mem_rsp->tag;
|
||||
device_->m_axi_bresp[0] = 0;
|
||||
pending_mem_reqs_.erase(mem_rsp_it);
|
||||
mem_wr_rsp_active_ = true;
|
||||
delete mem_req;
|
||||
delete mem_rsp;
|
||||
} else {
|
||||
device_->m_axi_bvalid = 0;
|
||||
device_->m_axi_bvalid[0] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// select the memory bank
|
||||
uint32_t req_addr = device_->m_axi_wvalid ? device_->m_axi_awaddr : device_->m_axi_araddr;
|
||||
uint32_t req_addr = device_->m_axi_wvalid[0] ? device_->m_axi_awaddr[0] : device_->m_axi_araddr[0];
|
||||
|
||||
// process memory requests
|
||||
if (device_->m_axi_wvalid || device_->m_axi_arvalid) {
|
||||
if (device_->m_axi_wvalid) {
|
||||
uint64_t byteen = device_->m_axi_wstrb;
|
||||
unsigned base_addr = device_->m_axi_awaddr;
|
||||
uint8_t* data = (uint8_t*)(device_->m_axi_wdata);
|
||||
if ((device_->m_axi_wvalid[0] || device_->m_axi_arvalid[0]) && running_) {
|
||||
if (device_->m_axi_wvalid[0]) {
|
||||
uint64_t byteen = device_->m_axi_wstrb[0];
|
||||
uint64_t base_addr = device_->m_axi_awaddr[0];
|
||||
uint8_t* data = (uint8_t*)device_->m_axi_wdata[0].data();
|
||||
|
||||
// check console output
|
||||
if (base_addr >= IO_COUT_ADDR
|
||||
&& base_addr < (IO_COUT_ADDR + IO_COUT_SIZE)) {
|
||||
if (base_addr >= uint64_t(IO_COUT_ADDR)
|
||||
&& base_addr < (uint64_t(IO_COUT_ADDR) + IO_COUT_SIZE)) {
|
||||
for (int i = 0; i < MEM_BLOCK_SIZE; i++) {
|
||||
if ((byteen >> i) & 0x1) {
|
||||
auto& ss_buf = print_bufs_[i];
|
||||
@@ -384,15 +426,15 @@ private:
|
||||
}
|
||||
|
||||
auto mem_req = new mem_req_t();
|
||||
mem_req->tag = device_->m_axi_awid;
|
||||
mem_req->addr = device_->m_axi_awaddr;
|
||||
mem_req->tag = device_->m_axi_awid[0];
|
||||
mem_req->addr = device_->m_axi_awaddr[0];
|
||||
mem_req->write = true;
|
||||
mem_req->ready = true;
|
||||
pending_mem_reqs_.emplace_back(mem_req);
|
||||
|
||||
// send dram request
|
||||
ramulator::Request dram_req(
|
||||
device_->m_axi_awaddr,
|
||||
device_->m_axi_awaddr[0],
|
||||
ramulator::Request::Type::WRITE,
|
||||
0
|
||||
);
|
||||
@@ -401,18 +443,18 @@ private:
|
||||
} else {
|
||||
// process reads
|
||||
auto mem_req = new mem_req_t();
|
||||
mem_req->tag = device_->m_axi_arid;
|
||||
mem_req->addr = device_->m_axi_araddr;
|
||||
ram_->read(mem_req->block.data(), device_->m_axi_araddr, MEM_BLOCK_SIZE);
|
||||
mem_req->tag = device_->m_axi_arid[0];
|
||||
mem_req->addr = device_->m_axi_araddr[0];
|
||||
ram_->read(mem_req->block.data(), device_->m_axi_araddr[0], MEM_BLOCK_SIZE);
|
||||
mem_req->write = false;
|
||||
mem_req->ready = false;
|
||||
pending_mem_reqs_.emplace_back(mem_req);
|
||||
|
||||
// send dram request
|
||||
ramulator::Request dram_req(
|
||||
device_->m_axi_araddr,
|
||||
device_->m_axi_araddr[0],
|
||||
ramulator::Request::Type::READ,
|
||||
std::bind([](ramulator::Request& dram_req, mem_req_t* mem_req) {
|
||||
std::bind([&](ramulator::Request& dram_req, mem_req_t* mem_req) {
|
||||
mem_req->ready = true;
|
||||
}, placeholders::_1, mem_req),
|
||||
0
|
||||
@@ -421,9 +463,9 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
device_->m_axi_wready = 1;
|
||||
device_->m_axi_awready = 1;
|
||||
device_->m_axi_arready = 1;
|
||||
device_->m_axi_wready[0] = running_;
|
||||
device_->m_axi_awready[0] = running_;
|
||||
device_->m_axi_arready[0] = running_;
|
||||
}
|
||||
|
||||
#else
|
||||
@@ -454,35 +496,35 @@ private:
|
||||
&& (*pending_mem_reqs_.begin())->ready) {
|
||||
device_->mem_rsp_valid = 1;
|
||||
auto mem_rsp_it = pending_mem_reqs_.begin();
|
||||
auto mem_req = *mem_rsp_it;
|
||||
auto mem_rsp = *mem_rsp_it;
|
||||
/*
|
||||
printf("%0ld: [sim] MEM Rd: bank=%d, addr=%0lx, data=", timestamp, last_mem_rsp_bank_, mem_req->addr);
|
||||
printf("%0ld: [sim] MEM Rd: bank=%d, tag=%0lx, addr=%0lx, data=", timestamp, last_mem_rsp_bank_, mem_rsp->tag, mem_rsp->addr);
|
||||
for (int i = 0; i < MEM_BLOCK_SIZE; i++) {
|
||||
printf("%02x", mem_req->block[(MEM_BLOCK_SIZE-1)-i]);
|
||||
printf("%02x", mem_rsp->block[(MEM_BLOCK_SIZE-1)-i]);
|
||||
}
|
||||
printf("\n");
|
||||
*/
|
||||
memcpy(device_->mem_rsp_data.data(), mem_req->block.data(), MEM_BLOCK_SIZE);
|
||||
device_->mem_rsp_tag = mem_req->tag;
|
||||
memcpy(device_->mem_rsp_data.data(), mem_rsp->block.data(), MEM_BLOCK_SIZE);
|
||||
device_->mem_rsp_tag = mem_rsp->tag;
|
||||
pending_mem_reqs_.erase(mem_rsp_it);
|
||||
mem_rd_rsp_active_ = true;
|
||||
delete mem_req;
|
||||
delete mem_rsp;
|
||||
} else {
|
||||
device_->mem_rsp_valid = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// process memory requests
|
||||
if (device_->mem_req_valid) {
|
||||
uint32_t byte_addr = (device_->mem_req_addr * MEM_BLOCK_SIZE);
|
||||
if (device_->mem_req_valid && running_) {
|
||||
uint64_t byte_addr = (device_->mem_req_addr * MEM_BLOCK_SIZE);
|
||||
if (device_->mem_req_rw) {
|
||||
// process writes
|
||||
uint64_t byteen = device_->mem_req_byteen;
|
||||
uint8_t* data = (uint8_t*)device_->mem_req_data.data();
|
||||
uint8_t* data = (uint8_t*)(device_->mem_req_data.data());
|
||||
|
||||
// check console output
|
||||
if (byte_addr >= IO_COUT_ADDR
|
||||
&& byte_addr < (IO_COUT_ADDR + IO_COUT_SIZE)) {
|
||||
if (byte_addr >= uint64_t(IO_COUT_ADDR)
|
||||
&& byte_addr < (uint64_t(IO_COUT_ADDR) + IO_COUT_SIZE)) {
|
||||
for (int i = 0; i < IO_COUT_SIZE; i++) {
|
||||
if ((byteen >> i) & 0x1) {
|
||||
auto& ss_buf = print_bufs_[i];
|
||||
@@ -496,7 +538,7 @@ private:
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
printf("%0ld: [sim] MEM Wr: addr=%0x, byteen=%0lx, data=", timestamp, byte_addr, byteen);
|
||||
printf("%0ld: [sim] MEM Wr: tag=%0lx, addr=%0x, byteen=%0lx, data=", timestamp, device_->mem_req_tag, byte_addr, byteen);
|
||||
for (int i = 0; i < MEM_BLOCK_SIZE; i++) {
|
||||
printf("%02x", data[(MEM_BLOCK_SIZE-1)-i]);
|
||||
}
|
||||
@@ -515,7 +557,7 @@ private:
|
||||
0
|
||||
);
|
||||
dram_queue_.push(dram_req);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// process reads
|
||||
auto mem_req = new mem_req_t();
|
||||
@@ -526,11 +568,13 @@ private:
|
||||
ram_->read(mem_req->block.data(), byte_addr, MEM_BLOCK_SIZE);
|
||||
pending_mem_reqs_.emplace_back(mem_req);
|
||||
|
||||
//printf("%0ld: [sim] MEM Rd Req: addr=%0x, tag=%0lx\n", timestamp, byte_addr, device_->mem_req_tag);
|
||||
|
||||
// send dram request
|
||||
ramulator::Request dram_req(
|
||||
byte_addr,
|
||||
ramulator::Request::Type::READ,
|
||||
std::bind([](ramulator::Request& dram_req, mem_req_t* mem_req) {
|
||||
std::bind([&](ramulator::Request& dram_req, mem_req_t* mem_req) {
|
||||
mem_req->ready = true;
|
||||
}, placeholders::_1, mem_req),
|
||||
0
|
||||
@@ -539,11 +583,24 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
device_->mem_req_ready = 1;
|
||||
device_->mem_req_ready = running_;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void reset_dcr_bus() {
|
||||
device_->dcr_wr_valid = 0;
|
||||
}
|
||||
|
||||
void eval_dcr_bus(bool clk) {
|
||||
if (!clk) {
|
||||
return;
|
||||
}
|
||||
if (device_->dcr_wr_valid) {
|
||||
device_->dcr_wr_valid = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void wait(uint32_t cycles) {
|
||||
for (int i = 0; i < cycles; ++i) {
|
||||
this->tick();
|
||||
@@ -552,17 +609,17 @@ private:
|
||||
|
||||
bool get_ebreak() const {
|
||||
#ifdef AXI_BUS
|
||||
return (bool)device_->Vortex_axi->vortex->genblk2__BRA__0__KET____DOT__cluster->genblk2__BRA__0__KET____DOT__core->pipeline->execute->ebreak;
|
||||
return (bool)device_->Vortex_axi->vortex->sim_ebreak;
|
||||
#else
|
||||
return (bool)device_->Vortex->genblk2__BRA__0__KET____DOT__cluster->genblk2__BRA__0__KET____DOT__core->pipeline->execute->ebreak;
|
||||
return (bool)device_->Vortex->sim_ebreak;
|
||||
#endif
|
||||
}
|
||||
|
||||
int get_last_wb_value(int reg) const {
|
||||
uint64_t get_last_wb_value(int reg) const {
|
||||
#ifdef AXI_BUS
|
||||
return (int)device_->Vortex_axi->vortex->genblk2__BRA__0__KET____DOT__cluster->genblk2__BRA__0__KET____DOT__core->pipeline->commit->writeback->last_wb_value[reg];
|
||||
return ((Word*)device_->Vortex_axi->vortex->sim_wb_value.data())[reg];
|
||||
#else
|
||||
return (int)device_->Vortex->genblk2__BRA__0__KET____DOT__cluster->genblk2__BRA__0__KET____DOT__core->pipeline->commit->writeback->last_wb_value[reg];
|
||||
return ((Word*)device_->Vortex->sim_wb_value.data())[reg];
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -600,6 +657,8 @@ private:
|
||||
ramulator::Gem5Wrapper* dram_;
|
||||
|
||||
std::queue<ramulator::Request> dram_queue_;
|
||||
|
||||
bool running_;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
@@ -618,4 +677,8 @@ void Processor::attach_ram(RAM* mem) {
|
||||
|
||||
int Processor::run() {
|
||||
return impl_->run();
|
||||
}
|
||||
|
||||
void Processor::write_dcr(uint32_t addr, uint32_t value) {
|
||||
return impl_->write_dcr(addr, value);
|
||||
}
|
||||
Reference in New Issue
Block a user