mirror of
https://github.com/openhwgroup/cvw
synced 2025-01-26 22:44:28 +00:00
5fd521d333
Test program is currently failing on ovpsim. There is no indication that ovpsim is properly implementing virtual memory translation when satp is set accordingly. Need to confirm whether this is a problem with ovpsim, how ovpsim is being called, or the test itself.
126 lines
3.3 KiB
Python
126 lines
3.3 KiB
Python
#!/usr/bin/python3
|
|
##################################
|
|
# virtual_memory_util.py
|
|
#
|
|
# Jessica Torrey <jtorrey@hmc.edu> 01 March 2021
|
|
# Thomas Fleming <tfleming@hmc.edu> 01 March 2021
|
|
#
|
|
# Utility functions for simulating and testing virtual memory on RISC-V.
|
|
##################################
|
|
|
|
##################################
|
|
# libraries
|
|
##################################
|
|
from datetime import datetime
|
|
from random import randint, seed, getrandbits
|
|
from textwrap import dedent
|
|
|
|
##################################
|
|
# global structures
|
|
##################################
|
|
PTE_D = 1 << 7
|
|
PTE_A = 1 << 6
|
|
PTE_G = 1 << 5
|
|
PTE_U = 1 << 4
|
|
PTE_X = 1 << 3
|
|
PTE_W = 1 << 2
|
|
PTE_R = 1 << 1
|
|
PTE_V = 1 << 0
|
|
|
|
|
|
pgdir = []
|
|
|
|
testcase_num = 0
|
|
signature_len = 2000
|
|
signature = [0xff for _ in range(signature_len)]
|
|
|
|
##################################
|
|
# classes
|
|
##################################
|
|
class Architecture:
|
|
def __init__(self, xlen):
|
|
if (xlen == 32):
|
|
self.PTESIZE = 4
|
|
|
|
self.VPN_BITS = 20
|
|
self.VPN_SEGMENT_BITS = 10
|
|
|
|
self.PPN_BITS = 22
|
|
|
|
self.LEVELS = 2
|
|
elif (xlen == 64):
|
|
self.PTESIZE = 8
|
|
|
|
self.VPN_BITS = 27
|
|
self.VPN_SEGMENT_BITS = 9
|
|
|
|
self.PPN_BITS = 44
|
|
|
|
self.LEVELS = 3
|
|
else:
|
|
raise ValueError('Only rv32 and rv64 are allowed.')
|
|
|
|
self.PGSIZE = 2**12
|
|
self.NPTENTRIES = self.PGSIZE // self.PTESIZE
|
|
self.PTE_BITS = 8 * self.PTESIZE
|
|
self.OFFSET_BITS = 12
|
|
self.FLAG_BITS = 8
|
|
|
|
class PageTableEntry:
|
|
def __init__(self, ppn, flags, arch):
|
|
assert 0 <= ppn and ppn < 2**arch.PPN_BITS, "Invalid physical page number for PTE"
|
|
assert 0 <= flags and flags < 2**arch.FLAG_BITS, "Invalid flags for PTE"
|
|
self.ppn = ppn
|
|
self.flags = flags
|
|
self.arch = arch
|
|
|
|
def entry(self):
|
|
return (self.ppn << (self.arch.PTE_BITS - self.arch.PPN_BITS)) | self.flags
|
|
|
|
def __str__(self):
|
|
return "0x{0:0{1}x}".format(self.entry(), self.arch.PTESIZE*2)
|
|
|
|
def __repr__(self):
|
|
return f"<ppn: {hex(self.ppn)}, flags: {self.flags:08b}>"
|
|
|
|
class PageTable:
|
|
"""
|
|
Represents a single level of the page table, with
|
|
"""
|
|
def __init__(self, name, arch):
|
|
self.table = {}
|
|
self.name = name
|
|
self.arch = arch
|
|
|
|
def add_entry(self, vpn_segment, ppn_segment, flags, linked_table = None):
|
|
if not (0 <= vpn_segment < 2**self.arch.VPN_SEGMENT_BITS):
|
|
raise ValueError("Invalid virtual page segment number")
|
|
self.table[vpn_segment] = (PageTableEntry(ppn_segment, flags, self.arch), linked_table)
|
|
|
|
def add_mapping(self, va, pa, flags):
|
|
if not (0 <= va < 2**self.arch.VPN_BITS):
|
|
raise ValueError("Invalid virtual page number")
|
|
for level in range(self.arch.LEVELS - 1, -1, -1):
|
|
|
|
|
|
|
|
|
|
def assembly(self):
|
|
entries = list(sorted(self.table.items(), key=lambda item: item[0]))
|
|
current_index = 0
|
|
asm = f".balign {self.arch.PGSIZE}\n{self.name}:\n"
|
|
for entry in entries:
|
|
vpn_index, (pte, _) = entry
|
|
if current_index < vpn_index:
|
|
asm += f" .fill {vpn_index - current_index}, {self.arch.PTESIZE}, 0\n"
|
|
asm += f" .4byte {str(pte)}\n"
|
|
current_index = vpn_index + 1
|
|
if current_index < self.arch.NPTENTRIES:
|
|
asm += f" .fill {self.arch.NPTENTRIES - current_index}, {self.arch.PTESIZE}, 0\n"
|
|
return asm
|
|
|
|
##################################
|
|
# functions
|
|
##################################
|
|
|