mirror of
https://github.com/vortexgpgpu/vortex.git
synced 2025-04-23 21:39:10 -04:00
Merge Austin's code (Preliminary)
This commit is contained in:
parent
2662b6bcab
commit
43a90071e1
15 changed files with 830 additions and 53 deletions
|
@ -14,21 +14,28 @@
|
|||
`ifndef VX_CONFIG_VH
|
||||
`define VX_CONFIG_VH
|
||||
|
||||
`ifndef VM_ADDR_MODE
|
||||
`define VM_ADDR_MODE SV32
|
||||
`ifndef VM_DISABLE
|
||||
`define VM_ENABLE
|
||||
`endif
|
||||
`ifdef VM_ENABLE
|
||||
`ifndef VM_ADDR_MODE
|
||||
`define VM_ADDR_MODE SV32
|
||||
`endif
|
||||
|
||||
`ifndef PTE_SIZE
|
||||
`define PTE_SIZE 8
|
||||
`endif
|
||||
|
||||
`ifndef TLB_SIZE
|
||||
`define TLB_SIZE 32
|
||||
`endif
|
||||
|
||||
`ifndef SUPER_PAGING
|
||||
`define SUPER_PAGING 0
|
||||
`endif
|
||||
|
||||
`endif
|
||||
|
||||
`ifndef PTE_SIZE
|
||||
`define PTE_SIZE 8
|
||||
`endif
|
||||
|
||||
`ifndef TLB_SIZE
|
||||
`define TLB_SIZE 32
|
||||
`endif
|
||||
|
||||
`ifndef SUPER_PAGING
|
||||
`define SUPER_PAGING false
|
||||
`endif
|
||||
|
||||
`ifndef MIN
|
||||
`define MIN(x, y) (((x) < (y)) ? (x) : (y))
|
||||
|
|
|
@ -29,6 +29,38 @@
|
|||
|
||||
using namespace vortex;
|
||||
|
||||
#ifdef VM_ENABLE
|
||||
|
||||
#ifndef NDEBUG
|
||||
#define DBGPRINT(format, ...) do { printf("[VXDRV] " format "", ##__VA_ARGS__); } while (0)
|
||||
#else
|
||||
#define DBGPRINT(format, ...) ((void)0)
|
||||
#endif
|
||||
|
||||
#define CHECK_ERR(_expr, _cleanup) \
|
||||
do { \
|
||||
auto err = _expr; \
|
||||
if (err == 0) \
|
||||
break; \
|
||||
printf("[VXDRV] Error: '%s' returned %d!\n", #_expr, (int)err); \
|
||||
_cleanup \
|
||||
} while (false)
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
#include <bitset>
|
||||
#include <unistd.h>
|
||||
|
||||
uint64_t bits(uint64_t addr, uint8_t s_idx, uint8_t e_idx)
|
||||
{
|
||||
return (addr >> s_idx) & ((1 << (e_idx - s_idx + 1)) - 1);
|
||||
}
|
||||
bool bit(uint64_t addr, uint8_t idx)
|
||||
{
|
||||
return (addr) & (1 << idx);
|
||||
}
|
||||
#endif
|
||||
|
||||
class vx_device {
|
||||
public:
|
||||
vx_device()
|
||||
|
@ -42,6 +74,10 @@ public:
|
|||
{
|
||||
// attach memory module
|
||||
processor_.attach_ram(&ram_);
|
||||
#ifdef VM_ENABLE
|
||||
//Set
|
||||
processor_.set_processor_satp(VM_ADDR_MODE);
|
||||
#endif
|
||||
}
|
||||
|
||||
~vx_device() {
|
||||
|
@ -90,18 +126,75 @@ public:
|
|||
return 0;
|
||||
}
|
||||
|
||||
int mem_alloc(uint64_t size, int flags, uint64_t* dev_addr) {
|
||||
uint64_t addr;
|
||||
CHECK_ERR(global_mem_.allocate(size, &addr), {
|
||||
return err;
|
||||
});
|
||||
CHECK_ERR(this->mem_access(addr, size, flags), {
|
||||
global_mem_.release(addr);
|
||||
return err;
|
||||
});
|
||||
*dev_addr = addr;
|
||||
return 0;
|
||||
}
|
||||
#ifdef VM_ENABLE
|
||||
// VM SUPPORT
|
||||
uint64_t map_local_mem(uint64_t size, uint64_t* dev_maddr)
|
||||
{
|
||||
bool is_pc = false;
|
||||
std::cout << "startup addr: " << std::hex << STARTUP_ADDR << std::endl;
|
||||
std::cout << "bit mode: " << std::dec << XLEN << std::endl;
|
||||
if (*dev_maddr == STARTUP_ADDR || *dev_maddr == 0x7FFFF000) {
|
||||
is_pc = true;
|
||||
}
|
||||
|
||||
if (get_mode() == VA_MODE::BARE)
|
||||
return 0;
|
||||
|
||||
uint64_t ppn = *dev_maddr >> 12;
|
||||
uint64_t init_pAddr = *dev_maddr;
|
||||
uint64_t init_vAddr = *dev_maddr + 0xf0000000; // vpn will change, but we want to return the vpn of the beginning of the virtual allocation
|
||||
init_vAddr = (init_vAddr >> 12) << 12;
|
||||
uint64_t vpn;
|
||||
|
||||
//dev_maddr can be of size greater than a page, but we have to map and update
|
||||
//page tables on a page table granularity. So divide the allocation into pages.
|
||||
for (ppn = (*dev_maddr) >> 12; ppn < ((*dev_maddr) >> 12) + (size/RAM_PAGE_SIZE) + 1; ppn++)
|
||||
{
|
||||
//Currently a 1-1 mapping is used, this can be changed here to support different
|
||||
//mapping schemes
|
||||
vpn = is_pc ? ppn : ppn + 0xf0000;
|
||||
//vpn = ppn;
|
||||
|
||||
//If ppn to vpn mapping doesnt exist.
|
||||
if (addr_mapping.find(vpn) == addr_mapping.end())
|
||||
{
|
||||
//Create mapping.
|
||||
update_page_table(ppn, vpn);
|
||||
addr_mapping[vpn] = ppn;
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "mapped virtual addr: " << init_vAddr << " to physical addr: " << init_pAddr << std::endl;
|
||||
uint64_t size_bits;
|
||||
if (is_pc) {
|
||||
std::cout << "not returning virtual address because it is PC or stack" << std::endl;
|
||||
std::pair<uint64_t, uint8_t> ptw_access = page_table_walk(init_vAddr - 0xf0000000, &size_bits);
|
||||
return 0;
|
||||
} else {
|
||||
std::pair<uint64_t, uint8_t> ptw_access = page_table_walk(init_vAddr, &size_bits);
|
||||
}
|
||||
*dev_maddr = init_vAddr; // commit vpn to be returned to host
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int mem_alloc(uint64_t size, int flags, uint64_t* dev_addr) {
|
||||
uint64_t addr;
|
||||
CHECK_ERR(global_mem_.allocate(size, &addr), {
|
||||
return err;
|
||||
});
|
||||
CHECK_ERR(this->mem_access(addr, size, flags), {
|
||||
global_mem_.release(addr);
|
||||
return err;
|
||||
});
|
||||
#ifdef VM_ENABLE
|
||||
// VM address translation
|
||||
std::cout << "physical addr: " << std::hex << *dev_addr << std::endl;
|
||||
map_local_mem(size, dev_addr);
|
||||
#endif
|
||||
*dev_addr = addr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mem_reserve(uint64_t dev_addr, uint64_t size, int flags) {
|
||||
CHECK_ERR(global_mem_.reserve(dev_addr, size), {
|
||||
|
@ -140,6 +233,18 @@ public:
|
|||
if (dest_addr + asize > GLOBAL_MEM_SIZE)
|
||||
return -1;
|
||||
|
||||
#ifdef VM_ENABLE
|
||||
uint64_t pAddr = dest_addr; // map_local_mem overwrites the provided dest_addr, so store away physical destination address
|
||||
if (dest_addr >= STARTUP_ADDR) {
|
||||
map_local_mem(asize,&dest_addr);
|
||||
} else if (dest_addr >= 0x7fff0000)
|
||||
{
|
||||
map_local_mem(asize,&dest_addr);
|
||||
}
|
||||
std::cout << "uploading to 0x" << pAddr << "(VA)" << std::endl;
|
||||
dest_addr = pAddr;
|
||||
#endif
|
||||
|
||||
ram_.enable_acl(false);
|
||||
ram_.write((const uint8_t*)src, dest_addr, size);
|
||||
ram_.enable_acl(true);
|
||||
|
@ -235,6 +340,244 @@ public:
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef VM_ENABLE
|
||||
/* VM Management */
|
||||
void set_processor_satp(VA_MODE mode)
|
||||
{
|
||||
uint32_t satp;
|
||||
if (mode == VA_MODE::BARE)
|
||||
satp = 0;
|
||||
else if (mode == VA_MODE::SV32)
|
||||
{
|
||||
satp = (alloc_page_table() >> 10) | 0x80000000;
|
||||
// satp = 0xFEBFE000 ;
|
||||
}
|
||||
processor_.set_satp(satp);
|
||||
}
|
||||
|
||||
uint32_t get_ptbr()
|
||||
{
|
||||
// return processor_.get_satp();
|
||||
return processor_.get_satp() & 0x003fffff;
|
||||
}
|
||||
|
||||
VA_MODE get_mode()
|
||||
{
|
||||
return processor_.get_satp() & 0x80000000 ? VA_MODE::SV32 : VA_MODE::BARE;
|
||||
// return VA_MODE::SV32;
|
||||
}
|
||||
|
||||
void update_page_table(uint64_t pAddr, uint64_t vAddr) {
|
||||
std::cout << "mapping vpn: " << vAddr << " to ppn:" << pAddr << std::endl;
|
||||
//Updating page table with the following mapping of (vAddr) to (pAddr).
|
||||
uint64_t ppn_1, pte_addr, pte_bytes;
|
||||
uint64_t vpn_1 = bits(vAddr, 10, 19);
|
||||
uint64_t vpn_0 = bits(vAddr, 0, 9);
|
||||
|
||||
//Read first level PTE.
|
||||
pte_addr = (get_ptbr() << 12) + (vpn_1 * PTE_SIZE);
|
||||
pte_bytes = read_pte(pte_addr);
|
||||
std::cout << "[PTE] addr 0x" << std::hex << pte_addr << ", PTE 0x" << std::hex << pte_bytes << std::endl;
|
||||
|
||||
|
||||
if ( bit(pte_bytes, 0) && ((pte_bytes & 0xFFFFFFFF) != 0xbaadf00d))
|
||||
{
|
||||
//If valid bit set, proceed to next level using new ppn form PTE.
|
||||
std::cout << "PTE valid, continuing the walk..." << std::endl;
|
||||
ppn_1 = (pte_bytes >> 10);
|
||||
}
|
||||
else
|
||||
{
|
||||
//If valid bit not set, allocate a second level page table
|
||||
// in device memory and store ppn in PTE. Set rwx = 000 in PTE
|
||||
//to indicate this is a pointer to the next level of the page table.
|
||||
ppn_1 = (alloc_page_table() >> 12);
|
||||
pte_bytes = ( (ppn_1 << 10) | 0b0000000001) ;
|
||||
write_pte(pte_addr, pte_bytes);
|
||||
}
|
||||
|
||||
//Read second level PTE.
|
||||
pte_addr = (ppn_1 << 12) + (vpn_0 * PTE_SIZE);
|
||||
pte_bytes = read_pte(pte_addr);
|
||||
std::cout << "got pte: " << std::hex << pte_bytes << std::endl;
|
||||
|
||||
if ( bit(pte_bytes, 0) && ((pte_bytes & 0xFFFFFFFF) != 0xbaadf00d))
|
||||
{
|
||||
std::cout << "ERROR, shouldn't be here" << std::endl;
|
||||
//If valid bit is set, then the page is already allocated.
|
||||
//Should not reach this point, a sanity check.
|
||||
}
|
||||
else
|
||||
{
|
||||
//If valid bit not set, write ppn of pAddr in PTE. Set rwx = 111 in PTE
|
||||
//to indicate this is a leaf PTE and has the stated permissions.
|
||||
pte_bytes = ( (pAddr << 10) | 0b0000001111) ;
|
||||
write_pte(pte_addr, pte_bytes);
|
||||
|
||||
//If super paging is enabled.
|
||||
if (SUPER_PAGING)
|
||||
{
|
||||
//Check if this second level Page Table can be promoted to a super page. Brute force
|
||||
//method is used to iterate over all PTE entries of the table and check if they have
|
||||
//their valid bit set.
|
||||
bool superpage = true;
|
||||
for(int i = 0; i < 1024; i++)
|
||||
{
|
||||
pte_addr = (ppn_1 << 12) + (i * PTE_SIZE);
|
||||
pte_bytes = read_pte(pte_addr);
|
||||
|
||||
if (!bit(pte_bytes, 0) && ((pte_bytes & 0xFFFFFFFF) != 0xbaadf00d))
|
||||
{
|
||||
superpage = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (superpage)
|
||||
{
|
||||
//This can be promoted to a super page. Set root PTE to the first PTE of the
|
||||
//second level. This is because the first PTE of the second level already has the
|
||||
//correct PPN1, PPN0 set to zero and correct access bits.
|
||||
pte_addr = (ppn_1 << 12);
|
||||
pte_bytes = read_pte(pte_addr);
|
||||
pte_addr = (get_ptbr() << 12) + (vpn_1 * PTE_SIZE);
|
||||
write_pte(pte_addr, pte_bytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<uint64_t, uint8_t> page_table_walk(uint64_t vAddr_bits, uint64_t* size_bits)
|
||||
{
|
||||
uint64_t LEVELS = 2;
|
||||
vAddr_SV32_t vAddr(vAddr_bits);
|
||||
uint64_t pte_bytes;
|
||||
|
||||
std::cout << "PTW on vAddr: 0x" << std::hex << vAddr_bits << std::endl;
|
||||
|
||||
//Get base page table.
|
||||
uint64_t a = this->processor_.get_satp() << 12;
|
||||
std::cout << "PTW SATP: 0x" << a << std::endl;
|
||||
int i = LEVELS - 1;
|
||||
|
||||
while(true)
|
||||
{
|
||||
|
||||
//Read PTE.
|
||||
std::cout << "reading PTE from RAM addr 0x" << std::hex << (a+vAddr.vpn[i]*PTE_SIZE) << std::endl;
|
||||
ram_.read(&pte_bytes, a+vAddr.vpn[i]*PTE_SIZE, sizeof(uint64_t));
|
||||
//pte_bytes &= 0x00000000FFFFFFFF;
|
||||
PTE_SV32_t pte(pte_bytes);
|
||||
std::cout << "got pte: " << std::hex << pte_bytes << std::endl;
|
||||
|
||||
//Check if it has invalid flag bits.
|
||||
if ( (pte.v == 0) | ( (pte.r == 0) & (pte.w == 1) ) )
|
||||
{
|
||||
std::cout << "Error on vAddr 0x" << std::hex << vAddr_bits << std::endl;
|
||||
throw Page_Fault_Exception("Page Fault : Attempted to access invalid entry. Entry: 0x");
|
||||
}
|
||||
|
||||
if ( (pte.r == 0) & (pte.w == 0) & (pte.x == 0))
|
||||
{
|
||||
//Not a leaf node as rwx == 000
|
||||
i--;
|
||||
if (i < 0)
|
||||
{
|
||||
throw Page_Fault_Exception("Page Fault : No leaf node found.");
|
||||
}
|
||||
else
|
||||
{
|
||||
//Continue on to next level.
|
||||
a = (pte_bytes >> 10 ) << 12;
|
||||
std::cout << "next a: " << a << std::endl;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//Leaf node found, finished walking.
|
||||
a = (pte_bytes >> 10 ) << 12;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
PTE_SV32_t pte(pte_bytes);
|
||||
|
||||
//Check RWX permissions according to access type.
|
||||
if (pte.r == 0)
|
||||
{
|
||||
throw Page_Fault_Exception("Page Fault : TYPE LOAD, Incorrect permissions.");
|
||||
}
|
||||
|
||||
uint64_t pfn;
|
||||
if (i > 0)
|
||||
{
|
||||
//It is a super page.
|
||||
if (pte.ppn[0] != 0)
|
||||
{
|
||||
//Misss aligned super page.
|
||||
throw Page_Fault_Exception("Page Fault : Miss Aligned Super Page.");
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
//Valid super page.
|
||||
pfn = pte.ppn[1];
|
||||
*size_bits = 22;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//Regular page.
|
||||
*size_bits = 12;
|
||||
pfn = a >> 12;
|
||||
}
|
||||
return std::make_pair(pfn, pte_bytes & 0xff);
|
||||
}
|
||||
|
||||
uint64_t alloc_page_table() {
|
||||
uint64_t addr;
|
||||
global_mem_.allocate(RAM_PAGE_SIZE, &addr);
|
||||
std::cout << "address of page table 0x" << std::hex << addr << std::endl;
|
||||
init_page_table(addr);
|
||||
return addr;
|
||||
}
|
||||
|
||||
|
||||
void init_page_table(uint64_t addr) {
|
||||
uint64_t asize = aligned_size(RAM_PAGE_SIZE, CACHE_BLOCK_SIZE);
|
||||
uint8_t *src = new uint8_t[RAM_PAGE_SIZE];
|
||||
for (uint64_t i = 0; i < RAM_PAGE_SIZE; ++i) {
|
||||
src[i] = (0x00000000 >> ((i & 0x3) * 8)) & 0xff;
|
||||
}
|
||||
ram_.write((const uint8_t*)src, addr, asize);
|
||||
}
|
||||
|
||||
void read_page_table(uint64_t addr) {
|
||||
uint8_t *dest = new uint8_t[RAM_PAGE_SIZE];
|
||||
download(dest, addr, RAM_PAGE_SIZE);
|
||||
printf("VXDRV: download %d bytes from 0x%x\n", RAM_PAGE_SIZE, addr);
|
||||
for (int i = 0; i < RAM_PAGE_SIZE; i += 4) {
|
||||
printf("mem-read: 0x%x -> 0x%x\n", addr + i, *(uint64_t*)((uint8_t*)dest + i));
|
||||
}
|
||||
}
|
||||
|
||||
void write_pte(uint64_t addr, uint64_t value = 0xbaadf00d) {
|
||||
std::cout << "writing pte " << std::hex << value << " to pAddr: " << std::hex << addr << std::endl;
|
||||
uint8_t *src = new uint8_t[PTE_SIZE];
|
||||
for (uint64_t i = 0; i < PTE_SIZE; ++i) {
|
||||
src[i] = (value >> ((i & 0x3) * 8)) & 0xff;
|
||||
}
|
||||
//std::cout << "writing PTE to RAM addr 0x" << std::hex << addr << std::endl;
|
||||
ram_.write((const uint8_t*)src, addr, PTE_SIZE);
|
||||
}
|
||||
|
||||
uint64_t read_pte(uint64_t addr) {
|
||||
uint8_t *dest = new uint8_t[PTE_SIZE];
|
||||
std::cout << "[read_pte] reading PTE from RAM addr 0x" << std::hex << addr << std::endl;
|
||||
ram_.read((uint8_t*)dest, addr, PTE_SIZE);
|
||||
return *(uint64_t*)((uint8_t*)dest);
|
||||
}
|
||||
#endif // JAEWON
|
||||
|
||||
private:
|
||||
Arch arch_;
|
||||
RAM ram_;
|
||||
|
@ -243,6 +586,9 @@ private:
|
|||
DeviceConfig dcrs_;
|
||||
std::future<void> future_;
|
||||
std::unordered_map<uint32_t, std::array<uint64_t, 32>> mpm_cache_;
|
||||
#ifdef VM_ENABLE
|
||||
std::unordered_map<uint64_t, uint64_t> addr_mapping;
|
||||
#endif
|
||||
};
|
||||
|
||||
#include <callbacks.inc>
|
||||
#include <callbacks.inc>
|
||||
|
|
|
@ -137,16 +137,90 @@ void MemoryUnit::ADecoder::write(const void* data, uint64_t addr, uint64_t size)
|
|||
MemoryUnit::MemoryUnit(uint64_t pageSize)
|
||||
: pageSize_(pageSize)
|
||||
, enableVM_(pageSize != 0)
|
||||
, amo_reservation_({0x0, false}) {
|
||||
if (pageSize != 0) {
|
||||
tlb_[0] = TLBEntry(0, 077);
|
||||
, amo_reservation_({0x0, false})
|
||||
#ifdef VM_ENABLE
|
||||
, TLB_HIT(0)
|
||||
, TLB_MISS(0)
|
||||
, TLB_EVICT(0)
|
||||
, PTW(0) {};
|
||||
#else
|
||||
{
|
||||
if (pageSize != 0)
|
||||
{
|
||||
tlb_[0] = TLBEntry(0, 077);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void MemoryUnit::attach(MemDevice &m, uint64_t start, uint64_t end) {
|
||||
decoder_.map(start, end, m);
|
||||
}
|
||||
|
||||
#ifdef VM_ENABLE
|
||||
std::pair<bool, uint64_t> MemoryUnit::tlbLookup(uint64_t vAddr, ACCESS_TYPE type, uint64_t* size_bits) {
|
||||
|
||||
//Find entry while accounting for different sizes.
|
||||
for (auto entry : tlb_)
|
||||
{
|
||||
if(entry.first == vAddr >> entry.second.size_bits)
|
||||
{
|
||||
*size_bits = entry.second.size_bits;
|
||||
vAddr = vAddr >> (*size_bits);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
auto iter = tlb_.find(vAddr);
|
||||
if (iter != tlb_.end()) {
|
||||
TLBEntry e = iter->second;
|
||||
|
||||
//Set mru bit if it is a hit.
|
||||
iter->second.mru_bit = true;
|
||||
|
||||
//If at full capacity and no other unset bits.
|
||||
// Clear all bits except the one we just looked up.
|
||||
if (tlb_.size() == TLB_SIZE)
|
||||
{
|
||||
// bool no_cleared = true;
|
||||
// for (auto& entry : tlb_)
|
||||
// {
|
||||
// no_cleared = no_cleared & entry.second.mru_bit;
|
||||
// }
|
||||
|
||||
// if(no_cleared)
|
||||
// {
|
||||
for (auto& entry : tlb_)
|
||||
{
|
||||
entry.second.mru_bit = false;
|
||||
}
|
||||
iter->second.mru_bit = true;
|
||||
//}
|
||||
|
||||
}
|
||||
//Check access permissions.
|
||||
if ( (type == ACCESS_TYPE::FETCH) & ((e.r == 0) | (e.x == 0)) )
|
||||
{
|
||||
throw Page_Fault_Exception("Page Fault : Incorrect permissions.");
|
||||
}
|
||||
else if ( (type == ACCESS_TYPE::LOAD) & (e.r == 0) )
|
||||
{
|
||||
throw Page_Fault_Exception("Page Fault : Incorrect permissions.");
|
||||
}
|
||||
else if ( (type == ACCESS_TYPE::STORE) & (e.w == 0) )
|
||||
{
|
||||
throw Page_Fault_Exception("Page Fault : Incorrect permissions.");
|
||||
}
|
||||
else
|
||||
{
|
||||
//TLB Hit
|
||||
return std::make_pair(true, iter->second.pfn);
|
||||
}
|
||||
} else {
|
||||
//TLB Miss
|
||||
return std::make_pair(false, 0);
|
||||
}
|
||||
}
|
||||
#endif //JAEWON
|
||||
MemoryUnit::TLBEntry MemoryUnit::tlbLookup(uint64_t vAddr, uint32_t flagMask) {
|
||||
auto iter = tlb_.find(vAddr / pageSize_);
|
||||
if (iter != tlb_.end()) {
|
||||
|
@ -171,16 +245,40 @@ uint64_t MemoryUnit::toPhyAddr(uint64_t addr, uint32_t flagMask) {
|
|||
return pAddr;
|
||||
}
|
||||
|
||||
void MemoryUnit::read(void* data, uint64_t addr, uint64_t size, bool sup, ACCESS_TYPE type) {
|
||||
#ifdef VM_ENABLE
|
||||
void MemoryUnit::read(void* data, uint64_t addr, uint64_t size, ACCESS_TYPE type) {
|
||||
uint64_t pAddr;
|
||||
if (this->mode == VA_MODE::BARE) {
|
||||
pAddr = addr;
|
||||
} else {
|
||||
pAddr = vAddr_to_pAddr(addr, type);
|
||||
}
|
||||
return decoder_.read(data, pAddr, size);
|
||||
}
|
||||
#else
|
||||
void MemoryUnit::read(void* data, uint64_t addr, uint64_t size, bool sup) {
|
||||
uint64_t pAddr = this->toPhyAddr(addr, sup ? 8 : 1);
|
||||
return decoder_.read(data, pAddr, size);
|
||||
}
|
||||
|
||||
void MemoryUnit::write(const void* data, uint64_t addr, uint64_t size, bool sup, ACCESS_TYPE type) {
|
||||
#endif
|
||||
#ifdef VM_ENABLE
|
||||
void MemoryUnit::write(const void* data, uint64_t addr, uint64_t size, ACCESS_TYPE type) {
|
||||
uint64_t pAddr;
|
||||
if ( (this->mode == VA_MODE::BARE) | (addr >= IO_BASE_ADDR) ) {
|
||||
pAddr = addr;
|
||||
} else {
|
||||
pAddr = vAddr_to_pAddr(addr, type);
|
||||
}
|
||||
decoder_.write(data, pAddr, size);
|
||||
amo_reservation_.valid = false;
|
||||
}
|
||||
#else
|
||||
void MemoryUnit::write(const void* data, uint64_t addr, uint64_t size, bool sup) {
|
||||
uint64_t pAddr = this->toPhyAddr(addr, sup ? 16 : 1);
|
||||
decoder_.write(data, pAddr, size);
|
||||
amo_reservation_.valid = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
void MemoryUnit::amo_reserve(uint64_t addr) {
|
||||
uint64_t pAddr = this->toPhyAddr(addr, 1);
|
||||
|
@ -193,9 +291,8 @@ bool MemoryUnit::amo_check(uint64_t addr) {
|
|||
return amo_reservation_.valid && (amo_reservation_.addr == pAddr);
|
||||
}
|
||||
|
||||
void MemoryUnit::tlbAdd(uint64_t virt, uint64_t phys, uint32_t flags) {
|
||||
tlb_[virt / pageSize_] = TLBEntry(phys / pageSize_, flags);
|
||||
}
|
||||
|
||||
#ifdef VM_ENABLE
|
||||
|
||||
void MemoryUnit::tlbAdd(uint64_t virt, uint64_t phys, uint32_t flags, uint64_t size_bits) {
|
||||
// HW: evict TLB by Most Recently Used
|
||||
|
@ -219,6 +316,12 @@ void MemoryUnit::tlbAdd(uint64_t virt, uint64_t phys, uint32_t flags, uint64_t s
|
|||
}
|
||||
tlb_[virt / pageSize_] = TLBEntry(phys / pageSize_, flags, size_bits);
|
||||
}
|
||||
#else
|
||||
|
||||
void MemoryUnit::tlbAdd(uint64_t virt, uint64_t phys, uint32_t flags) {
|
||||
tlb_[virt / pageSize_] = TLBEntry(phys / pageSize_, flags);
|
||||
}
|
||||
#endif
|
||||
|
||||
void MemoryUnit::tlbRm(uint64_t va) {
|
||||
if (tlb_.find(va / pageSize_) != tlb_.end())
|
||||
|
@ -472,3 +575,130 @@ void RAM::loadHexImage(const char* filename) {
|
|||
--size;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef VM_ENABLE
|
||||
uint64_t MemoryUnit::vAddr_to_pAddr(uint64_t vAddr, ACCESS_TYPE type)
|
||||
{
|
||||
uint64_t pfn;
|
||||
uint64_t size_bits;
|
||||
|
||||
//First lookup TLB.
|
||||
std::pair<bool, uint64_t> tlb_access = tlbLookup(vAddr, type, &size_bits);
|
||||
if (tlb_access.first)
|
||||
{
|
||||
pfn = tlb_access.second;
|
||||
TLB_HIT++;
|
||||
}
|
||||
else //Else walk the PT.
|
||||
{
|
||||
std::pair<uint64_t, uint8_t> ptw_access = page_table_walk(vAddr, type, &size_bits);
|
||||
tlbAdd(vAddr>>size_bits, ptw_access.first, ptw_access.second,size_bits);
|
||||
pfn = ptw_access.first; TLB_MISS++; PTW++;
|
||||
unique_translations.insert(vAddr>>size_bits);
|
||||
PERF_UNIQUE_PTW = unique_translations.size();
|
||||
}
|
||||
|
||||
//Construct final address using pfn and offset.
|
||||
std::cout << "[MemoryUnit] translated vAddr: 0x" << std::hex << vAddr << " to pAddr: 0x" << std::hex << ((pfn << size_bits) + (vAddr & ((1 << size_bits) - 1))) << std::endl;
|
||||
return (pfn << size_bits) + (vAddr & ((1 << size_bits) - 1));
|
||||
}
|
||||
|
||||
std::pair<uint64_t, uint8_t> MemoryUnit::page_table_walk(uint64_t vAddr_bits, ACCESS_TYPE type, uint64_t* size_bits)
|
||||
{
|
||||
uint64_t LEVELS = 2;
|
||||
vAddr_SV32_t vAddr(vAddr_bits);
|
||||
uint64_t pte_bytes;
|
||||
|
||||
//Get base page table.
|
||||
uint64_t a = this->ptbr << 12;
|
||||
int i = LEVELS - 1;
|
||||
|
||||
while(true)
|
||||
{
|
||||
|
||||
//Read PTE.
|
||||
decoder_.read(&pte_bytes, a+vAddr.vpn[i]*PTE_SIZE, sizeof(uint64_t));
|
||||
PTE_SV32_t pte(pte_bytes);
|
||||
|
||||
//Check if it has invalid flag bits.
|
||||
if ( (pte.v == 0) | ( (pte.r == 0) & (pte.w == 1) ) )
|
||||
{
|
||||
throw Page_Fault_Exception("Page Fault : Attempted to access invalid entry.");
|
||||
}
|
||||
|
||||
if ( (pte.r == 0) & (pte.w == 0) & (pte.x == 0))
|
||||
{
|
||||
//Not a leaf node as rwx == 000
|
||||
i--;
|
||||
if (i < 0)
|
||||
{
|
||||
throw Page_Fault_Exception("Page Fault : No leaf node found.");
|
||||
}
|
||||
else
|
||||
{
|
||||
//Continue on to next level.
|
||||
a = (pte_bytes >> 10 ) << 12;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//Leaf node found, finished walking.
|
||||
a = (pte_bytes >> 10 ) << 12;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
PTE_SV32_t pte(pte_bytes);
|
||||
|
||||
//Check RWX permissions according to access type.
|
||||
if ( (type == ACCESS_TYPE::FETCH) & ((pte.r == 0) | (pte.x == 0)) )
|
||||
{
|
||||
throw Page_Fault_Exception("Page Fault : TYPE FETCH, Incorrect permissions.");
|
||||
}
|
||||
else if ( (type == ACCESS_TYPE::LOAD) & (pte.r == 0) )
|
||||
{
|
||||
throw Page_Fault_Exception("Page Fault : TYPE LOAD, Incorrect permissions.");
|
||||
}
|
||||
else if ( (type == ACCESS_TYPE::STORE) & (pte.w == 0) )
|
||||
{
|
||||
throw Page_Fault_Exception("Page Fault : TYPE STORE, Incorrect permissions.");
|
||||
}
|
||||
|
||||
uint64_t pfn;
|
||||
if (i > 0)
|
||||
{
|
||||
//It is a super page.
|
||||
if (pte.ppn[0] != 0)
|
||||
{
|
||||
//Misss aligned super page.
|
||||
throw Page_Fault_Exception("Page Fault : Miss Aligned Super Page.");
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
//Valid super page.
|
||||
pfn = pte.ppn[1];
|
||||
*size_bits = 22;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//Regular page.
|
||||
*size_bits = 12;
|
||||
pfn = a >> 12;
|
||||
}
|
||||
return std::make_pair(pfn, pte_bytes & 0xff);
|
||||
}
|
||||
|
||||
|
||||
uint32_t MemoryUnit::get_satp()
|
||||
{
|
||||
return satp;
|
||||
}
|
||||
void MemoryUnit::set_satp(uint32_t satp)
|
||||
{
|
||||
this->satp = satp;
|
||||
this->ptbr = satp & 0x003fffff; //22 bits
|
||||
this->mode = satp & 0x80000000 ? VA_MODE::SV32 : VA_MODE::BARE;
|
||||
}
|
||||
#endif
|
|
@ -20,9 +20,18 @@
|
|||
#include <cstdint>
|
||||
#include <unordered_set>
|
||||
#include <stdexcept>
|
||||
#include "VX_config.h"
|
||||
#ifdef VM_ENABLE
|
||||
#include <unordered_set>
|
||||
#include <stdexcept>
|
||||
#include <cassert>
|
||||
#endif
|
||||
|
||||
|
||||
namespace vortex {
|
||||
|
||||
|
||||
#ifdef VM_ENABLE
|
||||
enum VA_MODE {
|
||||
BARE,
|
||||
SV32
|
||||
|
@ -34,6 +43,14 @@ enum ACCESS_TYPE {
|
|||
FETCH
|
||||
};
|
||||
|
||||
class Page_Fault_Exception : public std::runtime_error /* or logic_error */
|
||||
{
|
||||
public:
|
||||
Page_Fault_Exception(const std::string& what = "") : std::runtime_error(what) {}
|
||||
uint64_t addr;
|
||||
ACCESS_TYPE type;
|
||||
};
|
||||
#endif
|
||||
struct BadAddress {};
|
||||
struct OutOfRange {};
|
||||
|
||||
|
@ -92,34 +109,42 @@ public:
|
|||
PageFault(uint64_t a, bool nf)
|
||||
: faultAddr(a)
|
||||
, notFound(nf)
|
||||
, access_type(ACCESS_TYPE::LOAD)
|
||||
// , access_type(ACCESS_TYPE::LOAD)
|
||||
{}
|
||||
uint64_t faultAddr;
|
||||
bool notFound;
|
||||
ACCESS_TYPE access_type;
|
||||
// ACCESS_TYPE access_type;
|
||||
};
|
||||
|
||||
MemoryUnit(uint64_t pageSize = 0);
|
||||
|
||||
void attach(MemDevice &m, uint64_t start, uint64_t end);
|
||||
|
||||
void read(void* data, uint64_t addr, uint64_t size, bool sup, ACCESS_TYPE type = ACCESS_TYPE::LOAD);
|
||||
void write(const void* data, uint64_t addr, uint64_t size, bool sup, ACCESS_TYPE type = ACCESS_TYPE::LOAD);
|
||||
|
||||
#ifdef VM_ENABLE
|
||||
void read(void* data, uint64_t addr, uint64_t size, ACCESS_TYPE type = ACCESS_TYPE::LOAD);
|
||||
void write(const void* data, uint64_t addr, uint64_t size, ACCESS_TYPE type = ACCESS_TYPE::STORE);
|
||||
#else
|
||||
void read(void* data, uint64_t addr, uint64_t size, bool sup);
|
||||
void write(const void* data, uint64_t addr, uint64_t size, bool sup);
|
||||
#endif
|
||||
|
||||
void amo_reserve(uint64_t addr);
|
||||
bool amo_check(uint64_t addr);
|
||||
|
||||
void tlbAdd(uint64_t virt, uint64_t phys, uint32_t flags);
|
||||
#ifdef VM_ENABLE
|
||||
void tlbAdd(uint64_t virt, uint64_t phys, uint32_t flags, uint64_t size_bits);
|
||||
uint32_t get_satp();
|
||||
void set_satp(uint32_t satp);
|
||||
#else
|
||||
void tlbAdd(uint64_t virt, uint64_t phys, uint32_t flags);
|
||||
#endif
|
||||
|
||||
void tlbRm(uint64_t vaddr);
|
||||
void tlbFlush() {
|
||||
tlb_.clear();
|
||||
}
|
||||
|
||||
uint32_t get_satp();
|
||||
void set_satp(uint32_t satp);
|
||||
|
||||
private:
|
||||
|
||||
struct amo_reservation_t {
|
||||
|
@ -156,11 +181,7 @@ private:
|
|||
|
||||
struct TLBEntry {
|
||||
TLBEntry() {}
|
||||
TLBEntry(uint32_t pfn, uint32_t flags)
|
||||
: pfn(pfn)
|
||||
, flags(flags)
|
||||
, mru_bit(true)
|
||||
{};
|
||||
#ifdef VM_ENABLE
|
||||
TLBEntry(uint32_t pfn, uint32_t flags, uint64_t size_bits)
|
||||
: pfn(pfn)
|
||||
, flags(flags)
|
||||
|
@ -182,17 +203,27 @@ private:
|
|||
}
|
||||
|
||||
uint32_t pfn;
|
||||
bool d, a, g, u, x, w, r, v;
|
||||
uint32_t flags;
|
||||
bool mru_bit;
|
||||
uint64_t size_bits;
|
||||
bool d, a, g, u, x, w, r, v;
|
||||
#else
|
||||
TLBEntry(uint32_t pfn, uint32_t flags)
|
||||
: pfn(pfn)
|
||||
, flags(flags)
|
||||
{}
|
||||
uint32_t pfn;
|
||||
uint32_t flags;
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef VM_ENABLE
|
||||
std::pair<bool, uint64_t> tlbLookup(uint64_t vAddr, ACCESS_TYPE type, uint64_t* size_bits);
|
||||
|
||||
uint64_t vAddr_to_pAddr(uint64_t vAddr, ACCESS_TYPE type);
|
||||
|
||||
std::pair<uint64_t, uint8_t> page_table_walk(uint64_t vAddr_bits, ACCESS_TYPE type, uint64_t* size_bits);
|
||||
#endif
|
||||
|
||||
TLBEntry tlbLookup(uint64_t vAddr, uint32_t flagMask);
|
||||
|
||||
|
@ -203,14 +234,17 @@ private:
|
|||
ADecoder decoder_;
|
||||
bool enableVM_;
|
||||
|
||||
amo_reservation_t amo_reservation_;
|
||||
#ifdef VM_ENABLE
|
||||
|
||||
uint32_t satp;
|
||||
VA_MODE mode;
|
||||
uint32_t ptbr;
|
||||
|
||||
std::unordered_set<uint64_t> unique_translations;
|
||||
uint64_t TLB_HIT, TLB_MISS, TLB_EVICT, PTW, PERF_UNIQUE_PTW;
|
||||
#endif
|
||||
|
||||
amo_reservation_t amo_reservation_;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -278,6 +312,7 @@ private:
|
|||
bool check_acl_;
|
||||
};
|
||||
|
||||
#ifdef VM_ENABLE
|
||||
class PTE_SV32_t
|
||||
{
|
||||
|
||||
|
@ -299,6 +334,7 @@ class PTE_SV32_t
|
|||
bool d, a, g, u, x, w, r, v;
|
||||
PTE_SV32_t(uint64_t address) : address(address)
|
||||
{
|
||||
assert((address>> 32) == 0 && "Upper 32 bits are not zero!");
|
||||
flags = bits(address,0,7);
|
||||
rsw = bits(address,8,9);
|
||||
ppn[0] = bits(address,10,19);
|
||||
|
@ -334,10 +370,12 @@ class vAddr_SV32_t
|
|||
uint64_t pgoff;
|
||||
vAddr_SV32_t(uint64_t address) : address(address)
|
||||
{
|
||||
assert((address>> 32) == 0 && "Upper 32 bits are not zero!");
|
||||
vpn[0] = bits(address,12,21);
|
||||
vpn[1] = bits(address,22,31);
|
||||
pgoff = bits(address,0,11);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
} // namespace vortex
|
||||
|
|
|
@ -106,6 +106,14 @@ void Cluster::attach_ram(RAM* ram) {
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef VM_ENABLE
|
||||
void Cluster::set_satp(uint32_t satp) {
|
||||
for (auto& socket : sockets_) {
|
||||
socket->set_satp(satp);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
bool Cluster::running() const {
|
||||
for (auto& socket : sockets_) {
|
||||
if (socket->running())
|
||||
|
|
|
@ -57,6 +57,10 @@ public:
|
|||
|
||||
void attach_ram(RAM* ram);
|
||||
|
||||
#ifdef VM_ENABLE
|
||||
void set_satp(uint32_t satp);
|
||||
#endif
|
||||
|
||||
bool running() const;
|
||||
|
||||
int get_exitcode() const;
|
||||
|
|
|
@ -428,3 +428,10 @@ bool Core::wspawn(uint32_t num_warps, Word nextPC) {
|
|||
void Core::attach_ram(RAM* ram) {
|
||||
emulator_.attach_ram(ram);
|
||||
}
|
||||
|
||||
#ifdef VM_ENABLE
|
||||
void Core::set_satp(uint32_t satp) {
|
||||
emulator_.set_satp(satp); //JAEWON wit, tid???
|
||||
// emulator_.set_csr(VX_CSR_SATP,satp,0,0); //JAEWON wit, tid???
|
||||
}
|
||||
#endif
|
|
@ -26,6 +26,7 @@
|
|||
#include "dispatcher.h"
|
||||
#include "func_unit.h"
|
||||
#include "mem_coalescer.h"
|
||||
#include "VX_config.h"
|
||||
|
||||
namespace vortex {
|
||||
|
||||
|
@ -98,6 +99,9 @@ public:
|
|||
void tick();
|
||||
|
||||
void attach_ram(RAM* ram);
|
||||
#ifdef VM_ENABLE
|
||||
void set_satp(uint32_t satp);
|
||||
#endif
|
||||
|
||||
bool running() const;
|
||||
|
||||
|
|
|
@ -269,10 +269,51 @@ bool Emulator::barrier(uint32_t bar_id, uint32_t count, uint32_t wid) {
|
|||
return false;
|
||||
}
|
||||
|
||||
#ifdef VM_ENABLE
|
||||
void Emulator::icache_read(void *data, uint64_t addr, uint32_t size) {
|
||||
mmu_.read(data, addr, size, 0);
|
||||
try
|
||||
{
|
||||
mmu_.read(data, addr, size, ACCESS_TYPE::LOAD);
|
||||
}
|
||||
catch (Page_Fault_Exception& page_fault)
|
||||
{
|
||||
std::cout<<page_fault.what()<<std::endl;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
#else
|
||||
void Emulator::icache_read(void *data, uint64_t addr, uint32_t size) {
|
||||
mmu_.read(data, addr, size, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef VM_ENABLE
|
||||
void Emulator::set_satp(uint32_t satp) {
|
||||
set_csr(VX_CSR_SATP,satp,0,0);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef VM_ENABLE
|
||||
void Emulator::dcache_read(void *data, uint64_t addr, uint32_t size) {
|
||||
auto type = get_addr_type(addr);
|
||||
if (type == AddrType::Shared) {
|
||||
core_->local_mem()->read(data, addr, size);
|
||||
} else {
|
||||
try
|
||||
{
|
||||
// mmu_.read(data, addr, size, 0);
|
||||
mmu_.read(data, addr, size, ACCESS_TYPE::LOAD);
|
||||
}
|
||||
catch (Page_Fault_Exception& page_fault)
|
||||
{
|
||||
std::cout<<page_fault.what()<<std::endl;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
DPH(2, "Mem Read: addr=0x" << std::hex << addr << ", data=0x" << ByteStream(data, size) << " (size=" << size << ", type=" << type << ")" << std::endl);
|
||||
}
|
||||
#else
|
||||
void Emulator::dcache_read(void *data, uint64_t addr, uint32_t size) {
|
||||
auto type = get_addr_type(addr);
|
||||
if (type == AddrType::Shared) {
|
||||
|
@ -283,7 +324,33 @@ void Emulator::dcache_read(void *data, uint64_t addr, uint32_t size) {
|
|||
|
||||
DPH(2, "Mem Read: addr=0x" << std::hex << addr << ", data=0x" << ByteStream(data, size) << " (size=" << size << ", type=" << type << ")" << std::endl);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef VM_ENABLE
|
||||
void Emulator::dcache_write(const void* data, uint64_t addr, uint32_t size) {
|
||||
auto type = get_addr_type(addr);
|
||||
if (addr >= uint64_t(IO_COUT_ADDR)
|
||||
&& addr < (uint64_t(IO_COUT_ADDR) + IO_COUT_SIZE)) {
|
||||
this->writeToStdOut(data, addr, size);
|
||||
} else {
|
||||
if (type == AddrType::Shared) {
|
||||
core_->local_mem()->write(data, addr, size);
|
||||
} else {
|
||||
try
|
||||
{
|
||||
// mmu_.write(data, addr, size, 0);
|
||||
mmu_.write(data, addr, size, ACCESS_TYPE::STORE);
|
||||
}
|
||||
catch (Page_Fault_Exception& page_fault)
|
||||
{
|
||||
std::cout<<page_fault.what()<<std::endl;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
DPH(2, "Mem Write: addr=0x" << std::hex << addr << ", data=0x" << ByteStream(data, size) << " (size=" << size << ", type=" << type << ")" << std::endl);
|
||||
}
|
||||
#else
|
||||
void Emulator::dcache_write(const void* data, uint64_t addr, uint32_t size) {
|
||||
auto type = get_addr_type(addr);
|
||||
if (addr >= uint64_t(IO_COUT_ADDR)
|
||||
|
@ -298,6 +365,7 @@ void Emulator::dcache_write(const void* data, uint64_t addr, uint32_t size) {
|
|||
}
|
||||
DPH(2, "Mem Write: addr=0x" << std::hex << addr << ", data=0x" << ByteStream(data, size) << " (size=" << size << ", type=" << type << ")" << std::endl);
|
||||
}
|
||||
#endif
|
||||
|
||||
void Emulator::dcache_amo_reserve(uint64_t addr) {
|
||||
auto type = get_addr_type(addr);
|
||||
|
@ -349,6 +417,10 @@ Word Emulator::get_csr(uint32_t addr, uint32_t tid, uint32_t wid) {
|
|||
auto core_perf = core_->perf_stats();
|
||||
switch (addr) {
|
||||
case VX_CSR_SATP:
|
||||
#ifdef VM_ENABLE
|
||||
// return csrs_.at(wid).at(tid)[addr];
|
||||
return mmu_.get_satp();
|
||||
#endif
|
||||
case VX_CSR_PMPCFG0:
|
||||
case VX_CSR_PMPADDR0:
|
||||
case VX_CSR_MSTATUS:
|
||||
|
@ -475,6 +547,12 @@ void Emulator::set_csr(uint32_t addr, Word value, uint32_t tid, uint32_t wid) {
|
|||
csr_mscratch_ = value;
|
||||
break;
|
||||
case VX_CSR_SATP:
|
||||
#ifdef VM_ENABLE
|
||||
// warps_.at(wid).fcsr = (warps_.at(wid).fcsr & ~0x1F) | (value & 0x1F);
|
||||
// csrs_.at(wid).at(tid)[addr] = value; //what is wid and tid?
|
||||
mmu_.set_satp(value);
|
||||
break;
|
||||
#endif
|
||||
case VX_CSR_MSTATUS:
|
||||
case VX_CSR_MEDELEG:
|
||||
case VX_CSR_MIDELEG:
|
||||
|
@ -493,6 +571,8 @@ void Emulator::set_csr(uint32_t addr, Word value, uint32_t tid, uint32_t wid) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
uint32_t Emulator::get_fpu_rm(uint32_t func3, uint32_t tid, uint32_t wid) {
|
||||
return (func3 == 0x7) ? this->get_csr(VX_CSR_FRM, tid, wid) : func3;
|
||||
}
|
||||
|
|
|
@ -39,6 +39,9 @@ public:
|
|||
void clear();
|
||||
|
||||
void attach_ram(RAM* ram);
|
||||
#ifdef VM_ENABLE
|
||||
void set_satp(uint32_t satp) ;
|
||||
#endif
|
||||
|
||||
instr_trace_t* step();
|
||||
|
||||
|
@ -122,6 +125,9 @@ private:
|
|||
uint32_t ipdom_size_;
|
||||
Word csr_mscratch_;
|
||||
wspawn_t wspawn_;
|
||||
#ifdef VM_ENABLE
|
||||
Word ptbr_;
|
||||
#endif
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -95,6 +95,13 @@ void ProcessorImpl::attach_ram(RAM* ram) {
|
|||
cluster->attach_ram(ram);
|
||||
}
|
||||
}
|
||||
#ifdef VM_ENABLE
|
||||
void ProcessorImpl::set_satp(uint32_t satp) {
|
||||
for (auto cluster : clusters_) {
|
||||
cluster->set_satp(satp);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void ProcessorImpl::run() {
|
||||
SimPlatform::instance().reset();
|
||||
|
@ -154,4 +161,17 @@ void Processor::run() {
|
|||
|
||||
void Processor::dcr_write(uint32_t addr, uint32_t value) {
|
||||
return impl_->dcr_write(addr, value);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef VM_ENABLE
|
||||
uint32_t Processor::get_satp() {
|
||||
std::cout << "get SATP: 0x" << std::hex << this->satp << std::endl;
|
||||
return this->satp;
|
||||
}
|
||||
|
||||
void Processor::set_satp(uint32_t satp) {
|
||||
std::cout << "set SATP: 0x" << std::hex << this->satp << std::endl;
|
||||
impl_->set_satp(satp);
|
||||
this->satp = satp;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <VX_config.h>
|
||||
#include <mem.h>
|
||||
|
||||
namespace vortex {
|
||||
|
||||
|
@ -31,9 +33,17 @@ public:
|
|||
void run();
|
||||
|
||||
void dcr_write(uint32_t addr, uint32_t value);
|
||||
#ifdef VM_ENABLE
|
||||
void set_processor_satp(VA_MODE mode);
|
||||
uint32_t get_satp();
|
||||
void set_satp(uint32_t satp);
|
||||
#endif
|
||||
|
||||
private:
|
||||
ProcessorImpl* impl_;
|
||||
#ifdef VM_ENABLE
|
||||
uint32_t satp;
|
||||
#endif
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -39,6 +39,11 @@ public:
|
|||
|
||||
void dcr_write(uint32_t addr, uint32_t value);
|
||||
|
||||
#ifdef VM_ENABLE
|
||||
// 32bit satp
|
||||
void set_satp(uint32_t satp);
|
||||
#endif
|
||||
|
||||
PerfStats perf_stats() const;
|
||||
|
||||
private:
|
||||
|
|
|
@ -107,6 +107,14 @@ void Socket::attach_ram(RAM* ram) {
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef VM_ENABLE
|
||||
void Socket::set_satp(uint32_t satp) {
|
||||
for (auto core : cores_) {
|
||||
core->set_satp(satp);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
bool Socket::running() const {
|
||||
for (auto& core : cores_) {
|
||||
if (core->running())
|
||||
|
|
|
@ -60,6 +60,10 @@ public:
|
|||
|
||||
void attach_ram(RAM* ram);
|
||||
|
||||
#ifdef VM_ENABLE
|
||||
void set_satp(uint32_t satp);
|
||||
#endif
|
||||
|
||||
bool running() const;
|
||||
|
||||
int get_exitcode() const;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue