mirror of
https://github.com/openhwgroup/cvw
synced 2025-02-11 06:05:49 +00:00
Merge pull request #776 from davidharrishmc/dev
Added -H to pip3 installation to install in system home directory
This commit is contained in:
commit
b4fc47cd65
5
.gitignore
vendored
5
.gitignore
vendored
@ -229,4 +229,7 @@ examples/verilog/fulladder/profileReport/
|
||||
examples/verilog/fulladder/simprofile_dir/
|
||||
examples/verilog/fulladder/simv.daidir/
|
||||
examples/verilog/fulladder/ucli.key
|
||||
examples/verilog/fulladder/verdi_config_file
|
||||
examples/verilog/fulladder/verdi_config_file
|
||||
tests/functcov
|
||||
tests/functcov/*
|
||||
tests/functcov/*/*
|
||||
|
@ -48,7 +48,7 @@ sudo apt update -y
|
||||
sudo apt upgrade -y
|
||||
sudo apt install -y git gawk make texinfo bison flex build-essential python3 libz-dev libexpat-dev autoconf device-tree-compiler ninja-build libpixman-1-dev ncurses-base ncurses-bin libncurses5-dev dialog curl wget ftp libgmp-dev libglib2.0-dev python3-pip pkg-config opam z3 zlib1g-dev automake autotools-dev libmpc-dev libmpfr-dev gperf libtool patchutils bc mutt ssmtp
|
||||
# Other python libraries used through the book.
|
||||
sudo pip3 install sphinx sphinx_rtd_theme matplotlib scipy scikit-learn adjustText lief markdown
|
||||
sudo -H pip3 install sphinx sphinx_rtd_theme matplotlib scipy scikit-learn adjustText lief markdown
|
||||
|
||||
# needed for Ubuntu 22.04, gcc cross compiler expects python not python2 or python3.
|
||||
if ! command -v python &> /dev/null
|
||||
@ -183,8 +183,8 @@ sudo ln -sf $RISCV/sail-riscv/c_emulator/riscv_sim_RV64 /usr/bin/riscv_sim_RV64
|
||||
sudo ln -sf $RISCV/sail-riscv/c_emulator/riscv_sim_RV32 /usr/bin/riscv_sim_RV32
|
||||
|
||||
# riscof
|
||||
sudo pip3 install -U testresources riscv_config
|
||||
sudo pip3 install git+https://github.com/riscv/riscof.git
|
||||
sudo -H pip3 install -U testresources riscv_config
|
||||
sudo -H pip3 install git+https://github.com/riscv/riscof.git
|
||||
|
||||
# Download OSU Skywater 130 cell library
|
||||
sudo mkdir -p $RISCV/cad/lib
|
||||
|
@ -1,4 +1,39 @@
|
||||
all:
|
||||
#all:
|
||||
# ./covergen.py
|
||||
# cd ../riscof; make wally-riscv-arch-test
|
||||
# cd ../../sim; make memfiles
|
||||
|
||||
CEXT := c
|
||||
CPPEXT := cpp
|
||||
AEXT := s
|
||||
SEXT := S
|
||||
SRCEXT := \([$(CEXT)$(AEXT)$(SEXT)]\|$(CPPEXT)\)
|
||||
#SRCS = $(wildcard *.S)
|
||||
#PROGS = $(patsubst %.S,%,$(SRCS))
|
||||
SRCDIR = ${WALLY}/tests/functcov/rv64/I
|
||||
SRCEXT = S
|
||||
SOURCES ?= $(shell find $(SRCDIR) -type f -regex ".*\.$(SRCEXT)" | sort)
|
||||
OBJEXT = elf
|
||||
OBJECTS := $(SOURCES:.$(SEXT)=.$(OBJEXT))
|
||||
|
||||
all:
|
||||
./covergen.py
|
||||
cd ../riscof; make wally-riscv-arch-test
|
||||
cd ../../sim; make memfiles
|
||||
make build
|
||||
|
||||
build: $(OBJECTS)
|
||||
|
||||
%.elf.objdump: %.elf
|
||||
|
||||
# Change many things if bit width isn't 64
|
||||
$(SRCDIR)/%.elf: $(SRCDIR)/%.$(SEXT)
|
||||
riscv64-unknown-elf-gcc -g -o $@ -march=rv64gqc_zfa_zba_zbb_zbc_zbs_zfh_zicboz_zicbop_zicbom -mabi=lp64 -mcmodel=medany \
|
||||
-nostartfiles -T${WALLY}/examples/link/link.ld $<
|
||||
riscv64-unknown-elf-objdump -S -D $@ > $@.objdump
|
||||
riscv64-unknown-elf-elf2hex --bit-width 64 --input $@ --output $@.memfile
|
||||
extractFunctionRadix.sh $@.objdump
|
||||
|
||||
clean:
|
||||
rm -f ${SRCDIR}/*.elf ${SRCDIR}/*.objdump ${SRCDIR}/*.addr *${SRCDIR}/.lab ${SRCDIR}/*.memfile
|
||||
|
||||
|
||||
|
||||
|
@ -14,7 +14,7 @@ from datetime import datetime
|
||||
from random import randint
|
||||
from random import seed
|
||||
from random import getrandbits
|
||||
from os import getenv
|
||||
import os
|
||||
import re
|
||||
|
||||
##################################
|
||||
@ -33,16 +33,16 @@ def signedImm12(imm):
|
||||
|
||||
def writeCovVector(desc, rs1, rs2, rd, rs1val, rs2val, immval, rdval, test, storecmd, xlen):
|
||||
lines = "\n# Testcase " + str(desc) + "\n"
|
||||
lines = lines + "li x" + str(rd) + ", MASK_XLEN(" + formatstr.format(rdval) + ") # initialize rd to a random value that should get changed\n"
|
||||
lines = lines + "li x" + str(rd) + ", " + formatstr.format(rdval) + " # initialize rd to a random value that should get changed\n"
|
||||
if (test in rtype):
|
||||
lines = lines + "li x" + str(rs1) + ", MASK_XLEN(" + formatstr.format(rs1val) + ") # initialize rs1 to a random value \n"
|
||||
lines = lines + "li x" + str(rs2) + ", MASK_XLEN(" + formatstr.format(rs2val) + ") # initialize rs2 to a random value\n"
|
||||
lines = lines + "li x" + str(rs1) + ", " + formatstr.format(rs1val) + " # initialize rs1 to a random value \n"
|
||||
lines = lines + "li x" + str(rs2) + ", " + formatstr.format(rs2val) + " # initialize rs2 to a random value\n"
|
||||
lines = lines + test + " x" + str(rd) + ", x" + str(rs1) + ", x" + str(rs2) + " # perform operation\n"
|
||||
elif (test in shiftitype):
|
||||
lines = lines + "li x" + str(rs1) + ", MASK_XLEN(" + formatstr.format(rs1val) + ") # initialize rs1 to a random value \n"
|
||||
lines = lines + "li x" + str(rs1) + ", " + formatstr.format(rs1val) + " # initialize rs1 to a random value \n"
|
||||
lines = lines + test + " x" + str(rd) + ", x" + str(rs1) + ", " + shiftImm(immval, xlen) + " # perform operation\n"
|
||||
elif (test in itype):
|
||||
lines = lines + "li x" + str(rs1) + ", MASK_XLEN(" + formatstr.format(rs1val) + ") # initialize rs1 to a random value \n"
|
||||
lines = lines + "li x" + str(rs1) + ", " + formatstr.format(rs1val) + " # initialize rs1 to a random value \n"
|
||||
lines = lines + test + " x" + str(rd) + ", x" + str(rs1) + ", " + signedImm12(immval) + " # perform operation\n"
|
||||
else:
|
||||
pass
|
||||
@ -79,22 +79,28 @@ def make_rs2(test, storecmd, xlen):
|
||||
|
||||
def make_rd_rs1(test, storecmd, xlen):
|
||||
for r in range(32):
|
||||
[rs1, rs1, rd, rs1val, rs2val, immval, rdval] = randomize()
|
||||
[rs1, rs2, rd, rs1val, rs2val, immval, rdval] = randomize()
|
||||
desc = "cp_rd_rs1 (Test rd = rs1 = x" + str(r) + ")"
|
||||
writeCovVector(desc, r, rs2, r, rs1val, rs2val, immval, rdval, test, storecmd, xlen)
|
||||
|
||||
def make_rd_rs2(test, storecmd, xlen):
|
||||
for r in range(32):
|
||||
[rs1, rs1, rd, rs1val, rs2val, immval, rdval] = randomize()
|
||||
[rs1, rs2, rd, rs1val, rs2val, immval, rdval] = randomize()
|
||||
desc = "cp_rd_rs2 (Test rd = rs1 = x" + str(r) + ")"
|
||||
writeCovVector(desc, rs1, r, r, rs1val, rs2val, immval, rdval, test, storecmd, xlen)
|
||||
|
||||
def make_rd_rs1_rs2(test, storecmd, xlen):
|
||||
for r in range(32):
|
||||
[rs1, rs1, rd, rs1val, rs2val, immval, rdval] = randomize()
|
||||
[rs1, rs2, rd, rs1val, rs2val, immval, rdval] = randomize()
|
||||
desc = "cp_rd_rs1_rs2 (Test rd = rs1 = rs2 = x" + str(r) + ")"
|
||||
writeCovVector(desc, r, r, r, rs1val, rs2val, immval, rdval, test, storecmd, xlen)
|
||||
|
||||
def make_rs1_rs2(test, storecmd, xlen):
|
||||
for r in range(32):
|
||||
[rs1, rs2, rd, rs1val, rs2val, immval, rdval] = randomize()
|
||||
desc = "cp_rd_rs1_rs2 (Test rs1 = rs2 = x" + str(r) + ")"
|
||||
writeCovVector(desc, r, r, rd, rs1val, rs2val, immval, rdval, test, storecmd, xlen)
|
||||
|
||||
def make_rs1_maxvals(test, storecmd, xlen):
|
||||
for v in [0, 2**(xlen-1), 2**(xlen-1)-1, 2**xlen-1, 1, 2**(xlen-1)+1]:
|
||||
[rs1, rs2, rd, rs1val, rs2val, immval, rdval] = randomize()
|
||||
@ -131,6 +137,29 @@ def make_rs1_rs2_eqval(test, storecmd, xlen):
|
||||
#def make_cp_gpr_hazard(test, storecmd, xlen):
|
||||
# pass # *** to be implemented ***
|
||||
|
||||
def make_rs1_sign(test, storecmd, xlen):
|
||||
for v in [1, -1]:
|
||||
[rs1, rs2, rd, rs1val, rs2val, immval, rdval] = randomize()
|
||||
rs1val = abs(rs1val) * v;
|
||||
desc = "cp_rs1_sign (Test source rs1 value = " + hex(rs1val) + ")"
|
||||
writeCovVector(desc, rs1, rs2, rd, rs1val, rs2val, immval, rdval, test, storecmd, xlen)
|
||||
|
||||
def make_rs2_sign(test, storecmd, xlen):
|
||||
for v in [1, -1]:
|
||||
[rs1, rs2, rd, rs1val, rs2val, immval, rdval] = randomize()
|
||||
rs2val = abs(rs2val) * v;
|
||||
desc = "cp_rs2_sign (Test source rs2 value = " + hex(rs2val) + ")"
|
||||
writeCovVector(desc, rs1, rs2, rd, rs1val, rs2val, immval, rdval, test, storecmd, xlen)
|
||||
|
||||
def make_cr_rs1_rs2_sign(test, storecmd, xlen):
|
||||
for v1 in [1, -1]:
|
||||
for v2 in [1, -1]:
|
||||
[rs1, rs2, rd, rs1val, rs2val, immval, rdval] = randomize()
|
||||
rs1val = abs(rs1val) * v1;
|
||||
rs2val = abs(rs2val) * v2;
|
||||
desc = "cr_rs1_rs2 (Test source rs1 = " + hex(rs1val) + " rs2 = " + hex(rs2val) + ")"
|
||||
writeCovVector(desc, rs1, rs2, rd, rs1val, rs2val, immval, rdval, test, storecmd, xlen)
|
||||
|
||||
def write_tests(coverpoints, test, storecmd, xlen):
|
||||
for coverpoint in coverpoints:
|
||||
if (coverpoint == "cp_asm_count"):
|
||||
@ -141,12 +170,18 @@ def write_tests(coverpoints, test, storecmd, xlen):
|
||||
make_rs1(test, storecmd, xlen)
|
||||
elif (coverpoint == "cp_rs2"):
|
||||
make_rs2(test, storecmd, xlen)
|
||||
elif (coverpoint == "cp_rd_rs1"):
|
||||
elif (coverpoint == "cmp_rd_rs1"):
|
||||
make_rd_rs1(test, storecmd, xlen)
|
||||
elif (coverpoint == "cp_rd_rs2"):
|
||||
elif (coverpoint == "cmp_rd_rs2"):
|
||||
make_rd_rs2(test, storecmd, xlen)
|
||||
elif (coverpoint == "cp_rd_rs1_rs2"):
|
||||
elif (coverpoint == "cmp_rd_rs1_rs2"):
|
||||
make_rd_rs1_rs2(test, storecmd, xlen)
|
||||
elif (coverpoint == "cmp_rd_rs1_eq"):
|
||||
pass # duplicate of cmp_rd_rs1
|
||||
elif (coverpoint == "cmp_rd_rs2_eq"):
|
||||
pass # duplicate of cmp_rd_rs2
|
||||
elif (coverpoint == "cmp_rs1_rs2_eq"):
|
||||
make_rs1_rs2(test, storecmd, xlen)
|
||||
elif (coverpoint == "cp_rs1_maxvals"):
|
||||
make_rs1_maxvals(test, storecmd, xlen)
|
||||
elif (coverpoint == "cp_rs2_maxvals"):
|
||||
@ -159,8 +194,22 @@ def write_tests(coverpoints, test, storecmd, xlen):
|
||||
make_rd_rs2_eqval(test, storecmd, xlen)
|
||||
elif (coverpoint == "cmp_rs1_rs2_eqval"):
|
||||
make_rs1_rs2_eqval(test, storecmd, xlen)
|
||||
# elif (coverpoint == "cp_gpr_hazard"):
|
||||
# make_cp_gpr_hazard(test, storecmd, xlen)
|
||||
elif (coverpoint == "cp_rs1_sign"):
|
||||
make_rs1_sign(test, storecmd, xlen)
|
||||
elif (coverpoint == "cp_rs2_sign"):
|
||||
make_rs2_sign(test, storecmd, xlen)
|
||||
elif (coverpoint == "cp_rd_sign"):
|
||||
pass # hope already covered by rd_maxvals
|
||||
elif (coverpoint == "cr_rs1_rs2"):
|
||||
make_cr_rs1_rs2_sign(test, storecmd, xlen)
|
||||
elif (coverpoint == "cp_rs1_toggle"):
|
||||
pass # toggle not needed and seems to be covered by other things
|
||||
elif (coverpoint == "cp_rs2_toggle"):
|
||||
pass # toggle not needed and seems to be covered by other things
|
||||
elif (coverpoint == "cp_rd_toggle"):
|
||||
pass # toggle not needed and seems to be covered by other things
|
||||
elif (coverpoint == "cp_gpr_hazard"):
|
||||
pass # not yet implemented
|
||||
else:
|
||||
print("Error: " + coverpoint + " not implemented yet for " + test)
|
||||
|
||||
@ -188,7 +237,7 @@ def getcovergroups(coverdefdir, coverfiles):
|
||||
##################################
|
||||
|
||||
# change these to suite your tests
|
||||
riscv = getenv("RISCV")
|
||||
riscv = os.environ.get("RISCV")
|
||||
coverdefdir = riscv+"/ImperasDV-OpenHW/Imperas/ImpProprietary/source/host/riscvISACOV/source/coverage";
|
||||
#coverfiles = ["RV64I", "RV64M", "RV64A", "RV64C", "RV64F", "RV64D"] # add more later
|
||||
coverfiles = ["RV64I"] # add more later
|
||||
@ -222,13 +271,13 @@ for xlen in xlens:
|
||||
storecmd = "sd"
|
||||
wordsize = 8
|
||||
for test in coverpoints.keys():
|
||||
# for test in tests:
|
||||
# corners = [0, 1, 2, 0xFF, 0x624B3E976C52DD14 % 2**xlen, 2**(xlen-1)-2, 2**(xlen-1)-1,
|
||||
# 2**(xlen-1), 2**(xlen-1)+1, 0xC365DDEB9173AB42 % 2**xlen, 2**(xlen)-2, 2**(xlen)-1]
|
||||
corners = [0, 1, 2**(xlen)-1]
|
||||
pathname = "../wally-riscv-arch-test/riscv-test-suite/rv" + str(xlen) + "i_m/I/"
|
||||
# pathname = "../wally-riscv-arch-test/riscv-test-suite/rv" + str(xlen) + "i_m/I/"
|
||||
WALLY = os.environ.get('WALLY')
|
||||
pathname = WALLY+"/tests/functcov/rv" + str(xlen) + "/I/"
|
||||
cmd = "mkdir -p " + pathname
|
||||
os.system(cmd)
|
||||
basename = "WALLY-COV-" + test
|
||||
fname = pathname + "src/" + basename + ".S"
|
||||
fname = pathname + "/" + basename + ".S"
|
||||
|
||||
# print custom header part
|
||||
f = open(fname, "w")
|
||||
|
@ -1,30 +1,2 @@
|
||||
RVTEST_CODE_END
|
||||
RVMODEL_HALT
|
||||
|
||||
RVTEST_DATA_BEGIN
|
||||
.align 4
|
||||
rvtest_data:
|
||||
.word 0x98765432
|
||||
RVTEST_DATA_END
|
||||
|
||||
RVMODEL_DATA_BEGIN
|
||||
|
||||
|
||||
wally_signature:
|
||||
.fill NUMTESTS*(XLEN/32),4,0xdeadbeef
|
||||
|
||||
#ifdef rvtest_mtrap_routine
|
||||
|
||||
mtrap_sigptr:
|
||||
.fill 64*(XLEN/32),4,0xdeadbeef
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef rvtest_gpr_save
|
||||
|
||||
gpr_save:
|
||||
.fill 32*(XLEN/32),4,0xdeadbeef
|
||||
|
||||
#endif
|
||||
|
||||
RVMODEL_DATA_END
|
||||
.end
|
||||
|
@ -4,18 +4,9 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
|
||||
///////////////////////////////////////////
|
||||
|
||||
#include "model_test.h"
|
||||
#include "arch_test.h"
|
||||
RVTEST_ISA("RV64I")
|
||||
|
||||
.section .text.init
|
||||
.globl rvtest_entry_point
|
||||
|
||||
rvtest_entry_point:
|
||||
RVMODEL_BOOT
|
||||
RVTEST_CODE_BEGIN
|
||||
|
||||
RVTEST_CASE(0,"//check ISA:=regex(.*64.*);check ISA:=regex(.*I.*);def TEST_CASE_1=True;",temp)
|
||||
|
||||
la x6, wally_signature
|
||||
sd x0, 0(x6)
|
||||
|
@ -1,292 +0,0 @@
|
||||
#!/usr/bin/python3
|
||||
##################################
|
||||
# virtual_memory_util.py
|
||||
#
|
||||
# Jessica Torrey <jtorrey@hmc.edu> 01 March 2021
|
||||
# Thomas Fleming <tfleming@hmc.edu> 01 March 2021
|
||||
#
|
||||
# Modified kmacsaigoren@hmc.edu 2 June 2021
|
||||
# file now reflects actual use to generate assembly code pagetable.
|
||||
# file now also includes small guide on how it can be used.
|
||||
#
|
||||
# Utility for generating the pagetable for any test assembly code where virtual memory is needed.
|
||||
##################################
|
||||
|
||||
######################################################
|
||||
""" HOW TO USE THIS FILE
|
||||
|
||||
This is all assuming you are writing code very similar to the WALLY-VIRTUALMEMORY tests and would like your own virtual memory map.
|
||||
This guide is also stored in the WALLY-VIRTUALMEMORY.S file as well.
|
||||
|
||||
Begin by copying an existing page directory over to your test and running make (it'll be wrong, but we'll fix it in a second).
|
||||
Make may hang or give you an error because the reference outputs may be wrong, but all we're trying to do is get an elf file.
|
||||
Simulate the test code on your favorite riscv processor simulator with a debugger that will show you internal state/register values.
|
||||
I used OVPsimPlus with the command 'riscvOVPsimPlus.exe --variant <Variant name, ex: RV64I> --program <path to elf file> --gdbconsole'
|
||||
Run through the simulation until it has written to satp and read the bottom 60 bits of it.
|
||||
Assuming you're a test with the same setup code, this should be the value of the base ppn.
|
||||
|
||||
Near the top of the python file you're reading right now, edit the value of 'INITIAL_PPN' to be the base PPN you just found in hex.
|
||||
|
||||
Now find the mappings at the very bottom of the python file.
|
||||
Each of these loops is adding a mapping from each virtual page in the loop to a physical page somewhere in RAM.
|
||||
|
||||
add or remove mappings as you see fit. the first loop maps VPNs of 0x80000 to 0x80014 onto PPNs of 0x80000 to 0x80014
|
||||
you can map single pages or ranges of pages. you can also map multiple VPNs onto the same PPN.
|
||||
Make sure NOT to include the final VPN that causes the page fault in your test or your program will hang on the j loop instruction (unless you change the end condition).
|
||||
|
||||
double check that you're using the right architecture/svmode in the 'arch' variable
|
||||
|
||||
then run this python file and paste its output at the bottom of your assembly code. Be sure not to delete the signature fills.
|
||||
|
||||
email kmacsaigoren@hmc.edu if you have any questions and he might be able to remember the answers.
|
||||
|
||||
*** Currently doesn't work: mapping something with nonzeros in the VPN[3] feild onto any physical aderss.
|
||||
It'll produce a page table, but writing to those virtual adresses will not correspond to the correctly mapped physical adresses.
|
||||
|
||||
additionally, the expected behaviour doesn't really work when we try to map to a ram afress that starts with something larger than 000000008
|
||||
This could be ebcause of the 32 bit adress space for physical memory.
|
||||
|
||||
remember that these things are broken with this program that generates page tables for test code. it does not say whether the test or module
|
||||
itself works or not.
|
||||
*/
|
||||
|
||||
"""
|
||||
######################################################
|
||||
|
||||
##################################
|
||||
# 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
|
||||
|
||||
PTE_PTR_MASK = ~(PTE_W | PTE_R | PTE_X)
|
||||
|
||||
pgdir = []
|
||||
|
||||
pages = {}
|
||||
|
||||
|
||||
testcase_num = 0
|
||||
signature_len = 2000
|
||||
signature = [0xff for _ in range(signature_len)]
|
||||
|
||||
# Base PPN, comes after 2 pages of test code and 2 pages of filler signature output space.
|
||||
# depending on your test however, this value may be different. You can use OVPsimPlus or QEMU with your testcode to find it.
|
||||
INITIAL_PPN = 0x80005
|
||||
|
||||
|
||||
##################################
|
||||
# classes
|
||||
##################################
|
||||
class Architecture:
|
||||
def __init__(self, xlen, svMode):
|
||||
if (xlen == 32):
|
||||
self.PTESIZE = 4 # bytes
|
||||
self.PTE_BITS = 32
|
||||
|
||||
self.VPN_BITS = 20
|
||||
self.VPN_SEGMENT_BITS = 10
|
||||
|
||||
self.PPN_BITS = 22
|
||||
|
||||
self.LEVELS = 2
|
||||
elif (xlen == 64):
|
||||
if (svMode == 39):
|
||||
self.PTESIZE = 8
|
||||
self.PTE_BITS = 54
|
||||
|
||||
self.VPN_BITS = 27
|
||||
self.VPN_SEGMENT_BITS = 9
|
||||
|
||||
self.PPN_BITS = 44
|
||||
|
||||
self.LEVELS = 3
|
||||
elif (svMode == 48):
|
||||
self.PTESIZE = 8
|
||||
self.PTE_BITS = 54
|
||||
|
||||
self.VPN_BITS = 36
|
||||
self.VPN_SEGMENT_BITS = 9
|
||||
|
||||
self.PPN_BITS = 44
|
||||
|
||||
self.LEVELS = 4
|
||||
else:
|
||||
raise ValueError('Only Sv39 and Sv48 are implemented')
|
||||
else:
|
||||
raise ValueError('Only rv32 and rv64 are allowed.')
|
||||
|
||||
self.PGSIZE = 2**12
|
||||
self.NPTENTRIES = self.PGSIZE // self.PTESIZE
|
||||
self.OFFSET_BITS = 12
|
||||
self.FLAG_BITS = 8
|
||||
self.VA_BITS = self.VPN_BITS + self.OFFSET_BITS
|
||||
|
||||
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, located at some physical page
|
||||
number `ppn` with symbol `name`, using a specified architecture `arch`.
|
||||
"""
|
||||
def __init__(self, name, ppn, arch):
|
||||
self.table = {}
|
||||
self.name = name
|
||||
self.ppn = ppn
|
||||
self.arch = arch
|
||||
|
||||
self.children = 0
|
||||
|
||||
pages[ppn] = self
|
||||
|
||||
def add_entry(self, vpn_segment, ppn, flags):
|
||||
if not (0 <= vpn_segment < 2**self.arch.VPN_SEGMENT_BITS):
|
||||
raise ValueError("Invalid virtual page segment number")
|
||||
self.table[vpn_segment] = PageTableEntry(ppn, flags, self.arch)
|
||||
|
||||
def add_mapping(self, va, pa, flags):
|
||||
"""
|
||||
Maps a virtual address `va` to a physical address `pa` with given `flags`,
|
||||
creating missing page table levels as needed.
|
||||
"""
|
||||
if not (0 <= va < 2**self.arch.VA_BITS):
|
||||
raise ValueError("Invalid virtual page number")
|
||||
|
||||
vpn = virtual_to_vpn(va, self.arch)
|
||||
ppn = pa >> self.arch.OFFSET_BITS
|
||||
current_level = self
|
||||
|
||||
pathname = self.name
|
||||
|
||||
for level in range(self.arch.LEVELS - 1, -1, -1):
|
||||
if level == 0:
|
||||
current_level.add_entry(vpn[level], ppn, flags)
|
||||
elif vpn[level] in current_level.table:
|
||||
current_level = pages[current_level.table[vpn[level]].ppn]
|
||||
pathname += f"_{current_level.name}"
|
||||
else:
|
||||
next_level_ppn = next_ppn()
|
||||
current_level.add_entry(vpn[level], next_level_ppn, flags & PTE_PTR_MASK)
|
||||
pathname += f"_t{current_level.children}"
|
||||
current_level.children += 1
|
||||
pages[next_level_ppn] = PageTable(pathname, next_level_ppn, self.arch)
|
||||
current_level = pages[next_level_ppn]
|
||||
|
||||
def assembly(self):
|
||||
# Sort the page table
|
||||
entries = list(sorted(self.table.items(), key=lambda item: item[0]))
|
||||
current_index = 0
|
||||
|
||||
# Align the table
|
||||
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" .{self.arch.PTESIZE}byte {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
|
||||
|
||||
def __str__(self):
|
||||
return self.assembly()
|
||||
|
||||
def __repr__(self):
|
||||
return f"<table: {self.table}>"
|
||||
|
||||
|
||||
##################################
|
||||
# functions
|
||||
##################################
|
||||
|
||||
def virtual_to_vpn(vaddr, arch):
|
||||
if not (0 <= vaddr < 2**arch.VA_BITS):
|
||||
raise ValueError("Invalid physical address")
|
||||
|
||||
page_number = [0 for _ in range(arch.LEVELS)]
|
||||
|
||||
vaddr = vaddr >> arch.OFFSET_BITS
|
||||
mask = 2**arch.VPN_SEGMENT_BITS - 1
|
||||
for level in range(arch.LEVELS):
|
||||
page_number[level] = vaddr & mask
|
||||
vaddr = vaddr >> arch.VPN_SEGMENT_BITS
|
||||
|
||||
return page_number
|
||||
|
||||
next_free_ppn = INITIAL_PPN
|
||||
def next_ppn():
|
||||
global next_free_ppn
|
||||
ppn = next_free_ppn
|
||||
next_free_ppn += 1
|
||||
return ppn
|
||||
|
||||
def print_pages():
|
||||
for page in pages:
|
||||
print(pages[page])
|
||||
|
||||
##################################
|
||||
# helper variables
|
||||
##################################
|
||||
sv32 = Architecture(32, 32)
|
||||
sv39 = Architecture(64, 39)
|
||||
sv48 = Architecture(64, 48)
|
||||
|
||||
if __name__ == "__main__":
|
||||
arch = sv39
|
||||
pgdir = PageTable("page_directory", next_ppn(), arch)
|
||||
|
||||
# Directly map the first 20 pages of RAM
|
||||
for page in range(20):
|
||||
vaddr = 0x80000000 + (arch.PGSIZE * page)
|
||||
paddr = 0x80000000 + (arch.PGSIZE * page)
|
||||
pgdir.add_mapping(vaddr, paddr, PTE_D | PTE_A | PTE_R | PTE_W | PTE_U | PTE_X | PTE_V)
|
||||
|
||||
# Map Vpn of of the offset below and the 20 pages after it mapped onto the same 20 pages of ram.
|
||||
# the first two of these are also the location of the output for each test.
|
||||
for page in range(40):
|
||||
vaddr = 0x00000000 + (arch.PGSIZE * page)
|
||||
paddr = 0x80000000 + (arch.PGSIZE * page)
|
||||
if page >= 20:
|
||||
pgdir.add_mapping(vaddr, paddr, PTE_D | PTE_A | PTE_R | PTE_W | PTE_U | PTE_X | 0) # gives me an invalid mapping where I can try to store/read to force a page fault.
|
||||
else:
|
||||
pgdir.add_mapping(vaddr, paddr, PTE_D | PTE_A | PTE_R | PTE_W | PTE_U | PTE_X | PTE_V)
|
||||
|
||||
|
||||
"""
|
||||
supervisor_pgdir = PageTable("sdir", next_ppn(), rv64)
|
||||
supervisor_pgdir.add_mapping(0x80000000, 0x80000000, PTE_R | PTE_W | PTE_X)
|
||||
supervisor_pgdir.add_mapping(0x80000001, 0x80000001, PTE_R | PTE_W | PTE_X)
|
||||
supervisor_pgdir.add_mapping(0x80001000, 0x80000000, PTE_R | PTE_W | PTE_X)
|
||||
supervisor_pgdir.add_mapping(0xffff0000, 0x80000000, PTE_R | PTE_W | PTE_X)
|
||||
"""
|
||||
|
||||
print_pages()
|
Loading…
Reference in New Issue
Block a user