Update google_riscv-dv to google/riscv-dv@0b62525

Update code from upstream repository https://github.com/google/riscv-
dv to revision 0b625258549e733082c12e5dc749f05aefb07d5a

* Add a knob to use rounding mode from the instruction (google/riscv-
  dv#767) (taoliug)
* Add rounding mode support for floating point arithmetic instructions
  (google/riscv-dv#766) (taoliug)
* Fix syntax issue (google/riscv-dv#765) (taoliug)
* Add riscv_amo_instr (aneels3)
* convert string to enum type (ishita71)
* Remove unintended errors in the coverage flow (google/riscv-dv#757)
  (taoliug)
* Fix c_test handling in the YAML testlist (google/riscv-dv#756)
  (taoliug)
* Add support for new Spike trace format (google/riscv-dv#755) (Daniel
  Bates)
* Fix google/riscv-dv#751 for floating point coverage (Weicai Yang)
* Fix issues with implemented TODO's (aneels3)
* fix randomize_gpr (aneels3)
* Add file riscv_b_instr.py (ishita71)
* add std_randomize todo (pvipsyash)
* Add todo for floating_point test (ShraddhaDevaiya)
* Add scripts to integrate with Metrics regression platform (Aimee
  Sutton)

Includes a fix to dv/uvm/core_ibex/sim.py to use `asm_test` rather than
`asm_tests` due to changes in RISCV-DV

Signed-off-by: Greg Chadwick <gac@lowrisc.org>
This commit is contained in:
Greg Chadwick 2021-02-01 18:40:28 +00:00
parent 860b085e25
commit 0cb2afffa9
41 changed files with 1800 additions and 442 deletions

View file

@ -363,7 +363,7 @@ def compare_test_run(test, idx, iss, output_dir, report):
'''
test_name = test['test']
elf = os.path.join(output_dir,
'instr_gen/asm_tests/{}.{}.o'.format(test_name, idx))
'instr_gen/asm_test/{}.{}.o'.format(test_name, idx))
logging.info("Comparing %s/DUT sim result : %s" % (iss, elf))
@ -586,7 +586,7 @@ def main():
# Create the output directory
output_dir = ("%s/rtl_sim" % args.o)
bin_dir = ("%s/instr_gen/asm_tests" % args.o)
bin_dir = ("%s/instr_gen/asm_test" % args.o)
subprocess.run(["mkdir", "-p", output_dir])
steps = {

View file

@ -9,6 +9,6 @@
upstream:
{
url: https://github.com/google/riscv-dv
rev: 3da32bbf6080d3bf252a7f71c5e3a32ea4924e49
rev: 0b625258549e733082c12e5dc749f05aefb07d5a
}
}

View file

@ -0,0 +1,26 @@
# This is a basic workflow to help you get started with Actions
name: metrics-regress
# Controls when the action will run. Triggers the workflow on push or pull request
# events but only for the master branch
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
# If you fork this repository, you must create a new Metrics project for your fork
# and set the environment variable $METRICS_PROJECT_ID accordingly
jobs:
metrics-regression:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: ./scripts/metrics-regress.py $METRICS_REGRESSION_NAME $METRICS_PROJECT_ID
env:
METRICS_CI_TOKEN: ${{ secrets.METRICS_CI_TOKEN }}
METRICS_REGRESSION_NAME: riscv-dv_regression
METRICS_PROJECT_ID: ${{ secrets.METRICS_PROJECT_ID }}
shell: bash

52
vendor/google_riscv-dv/.metrics.json vendored Normal file
View file

@ -0,0 +1,52 @@
{
"variables": {
"DSIM" : "${DSIM_HOME}/bin/dsim",
"DSIM_LIB_PATH" : "${DSIM_HOME}/uvm-1.2/src/dpi",
"RISCV_GCC" : "${RISCV_TOOLCHAIN}/bin/riscv-none-embed-gcc",
"RISCV_OBJCOPY" : "${RISCV_TOOLCHAIN}/bin/riscv-none-embed-objcopy",
"OVPSIM_PATH" : "/customer-tools/riscv-ovpsim/bin/Linux64"
},
"builds": {
"list": [{
"name": "rv32imc",
"image": "ibex-dsim-toolchain:latest",
"memory" : "1",
"cmd": "python3 run.py --test riscv_arithmetic_basic_test --simulator dsim --output out --verbose --co",
"wavesCmd": "python3 run.py --test riscv_arithmetic_basic_test --simulator dsim --output out --verbose --co"
}]
},
"regressions": [{
"name": "riscv-dv_sanity",
"description": "Basic test generated by Google riscv-dv instruction generator",
"tests": {
"builds": ["rv32imc"],
"resultsDir" : "/mux-flow/build/repo/out",
"memory" : "1",
"list": [
{
"name": "riscv_arithmetic_basic_test",
"build": "rv32imc",
"iterations": 2,
"cmd": "cd /mux-flow/results; python3 <rootDir>/run.py --test riscv_arithmetic_basic_test --seed <seed> --simulator dsim --iss ovpsim --so --out <rootDir>/out --verbose; <rootDir>/scripts/check-status $?; rm -fr <rootDir>/out/dsim",
"wavesCmd": "python3 <rootDir>/run.py --test riscv_arithmetic_basic_test --seed <seed> --simulator dsim --iss ovpsim --so --out <rootDir>/out --verbose; <rootDir>/scripts/check-status $?; rm -rf out/dsim",
"logFile": "simulation.log",
"metricsFile": "metrics.db",
"isPass": "Test passed",
"seed": "random"
}
]
}
},
{
"name" : "riscv-dv_regression",
"description": "Tests generated by Google riscv-dv instruction generator",
"tests": {
"resultsDir": "/mux-flow/build/repo/out",
"builds": ["rv32imc"],
"memory": "1",
"listCmd": "<rootDir>/scripts/genMetricsList.py",
"listFile": "<rootDir>/regression_list.json"
}
}
]
}

View file

@ -187,16 +187,16 @@ corner cases::
# Run a single/multiple assembly/C test
run --asm_tests asm_test_path1/asm_test1.S,asm_test_path2/asm_test2.S
run --c_tests c_test_path1/c_test1.c,c_test_path2/c_test2.c
run --asm_test asm_test_path1/asm_test1.S,asm_test_path2/asm_test2.S
run --c_test c_test_path1/c_test1.c,c_test_path2/c_test2.c
# Run regression with all assembly tests(*.S)/ C tests(*.c) under a given directory
run --asm_tests asm_test_path1,asm_test_path2
run --c_tests c_test_path1,c_test_path2
# Run regression with all assembly test(*.S)/ C test(*.c) under a given directory
run --asm_test asm_test_path1,asm_test_path2
run --c_test c_test_path1,c_test_path2
# Run mix between the assembly/C test and assembly/C tests under a directory
run --asm_tests asm_test_path1/asm_test1.S,asm_test_path2
run --c_tests c_test_path1/c_test1.c,c_test_path2
# Run mix between the assembly/C test and assembly/C test under a directory
run --asm_test asm_test_path1/asm_test1.S,asm_test_path2
run --c_test c_test_path1/c_test1.c,c_test_path2
You could also use this approach to integrate the assembly/C tests
from other sources to riscv-dv flow.

View file

@ -0,0 +1,71 @@
"""
Copyright 2020 Google LLC
Copyright 2020 PerfectVIPs Inc.
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.
"""
import sys
import logging
import vsc
from pygen_src.isa.riscv_instr import riscv_instr
from pygen_src.riscv_instr_pkg import pkg_ins, riscv_instr_name_t, riscv_instr_group_t
@vsc.randobj
class riscv_amo_instr(riscv_instr):
def __init__(self):
super().__init__()
self.aq = vsc.rand_bit_t(1)
self.rl = vsc.rand_bit_t(1)
@vsc.constraint
def aq_rl_c(self):
self.aq & self.rl == 0
def get_instr_name(self):
get_instr_name = self.instr_name.name
if self.group == riscv_instr_group_t.RV32A:
get_instr_name = "{}.w".format(get_instr_name[:-2])
if self.aq:
get_instr_name = "{}.aq".format(get_instr_name)
else:
if self.rl:
get_instr_name = "{}.rl".format(get_instr_name)
else:
get_instr_name = get_instr_name
elif self.group == riscv_instr_group_t.RV64A:
get_instr_name = "{}.d".format(get_instr_name[:-2])
if self.aq:
get_instr_name = "{}.aq".format(get_instr_name)
else:
if self.rl:
get_instr_name = "{}.rl".format(get_instr_name)
else:
logging.critical("Unexpected amo instr group: {} / {}"
.format(self.group.name, self.instr_name.name))
sys.exit(1)
return get_instr_name
# Convert the instruction to assembly code
def convert2asm(self, prefix = ""):
asm_str = pkg_ins.format_string(self.get_instr_name(), pkg_ins.MAX_INSTR_STR_LEN)
if self.group in [riscv_instr_group_t.RV32A, riscv_instr_group_t.RV64A]:
if self.instr_name in [riscv_instr_name_t.LR_W, riscv_instr_name_t.LR_D]:
asm_str = "{} {}, ({})".format(asm_str, self.rd.name, self.rs1.name)
else:
asm_str = "{} {}, {}, ({})".format(asm_str, self.rd.name, self.rs2.name,
self.rs1.name)
else:
logging.critical("Unexpected amo instr group: {} / {}"
.format(self.group.name, self.instr_name.name))
sys.exit(1)
if self.comment != "":
asm_str = "{} #{}".format(asm_str, self.comment)
return asm_str.lower()

View file

@ -0,0 +1,178 @@
"""
Copyright 2020 Google LLC
Copyright 2020 PerfectVIPs Inc.
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.
"""
import math
import logging
import vsc
from importlib import import_module
from pygen_src.isa.riscv_instr import riscv_instr
from pygen_src.riscv_instr_pkg import (pkg_ins, riscv_instr_category_t, riscv_reg_t,
riscv_instr_name_t, riscv_instr_group_t,
riscv_instr_format_t)
from pygen_src.riscv_instr_gen_config import cfg
rcs = import_module("pygen_src.target." + cfg.argv.target + ".riscv_core_setting")
@vsc.randobj
class riscv_b_instr(riscv_instr):
def __init__(self):
super().__init__()
self.rs3 = vsc.rand_enum_t(riscv_reg_t)
self.has_rs3 = vsc.bit_t(1)
def set_rand_mode(self):
super().set_rand_mode()
self.has_rs3 = 0
if self.format == riscv_instr_format_t.R_FORMAT:
if self.instr_name in [riscv_instr_name_t.CLZW,
riscv_instr_name_t.CTZW, riscv_instr_name_t.PCNTW,
riscv_instr_name_t.SEXT_B, riscv_instr_name_t.SEXT_H,
riscv_instr_name_t.CLZ, riscv_instr_name_t.CTZ,
riscv_instr_name_t.PCNT, riscv_instr_name_t.BMATFLIP,
riscv_instr_name_t.CRC32_B, riscv_instr_name_t.CRC32_H,
riscv_instr_name_t.CRC32_W, riscv_instr_name_t.CRC32C_B,
riscv_instr_name_t.CRC32C_H, riscv_instr_name_t.CRC32C_W,
riscv_instr_name_t.CRC32_D, riscv_instr_name_t.CRC32C_D]:
self.has_rs2 = 0
elif self.format == riscv_instr_format_t.R4_FORMAT:
self.has_imm = 0
self.has_rs3 = 1
elif self.format == riscv_instr_format_t.I_FORMAT:
self.has_rs2 = 0
if self.instr_name in [riscv_instr_name_t.FSRI, riscv_instr_name_t.FSRIW]:
self.has_rs3 = 1
def pre_randomize(self):
super().pre_randomize()
with vsc.raw_mode():
self.rs3.rand_mode = bool(self.has_rs3)
def set_imm_len(self):
if self.format == riscv_instr_format_t.I_FORMAT:
if self.category in [riscv_instr_category_t.SHIFT, riscv_instr_category_t.LOGICAL]:
if (self.group.name == riscv_instr_group_t.RV64B and
self.instr_name != riscv_instr_name_t.SLLIU_W):
self.imm_len = math.ceil(math.log2(rcs.XLEN)) - 1
else:
self.imm_len = math.ceil(math.log2(rcs.XLEN))
# ARITHMETIC RV32B
if self.instr_name in [riscv_instr_name_t.SHFLI, riscv_instr_name_t.UNSHFLI]:
self.imm_len = math.ceil(math.log2(rcs.XLEN)) - 1
# ARITHMETIC RV64B
if self.instr_name == riscv_instr_name_t.ADDIWU:
self.imm_len = 12
self.imm_mask = self.imm_mask << self.imm_len
# Convert the instruction to assembly code
def convert2asm(self, prefix = " "):
asm_str_final = ""
asm_str = ""
asm_str = pkg_ins.format_string(self.get_instr_name(), pkg_ins.MAX_INSTR_STR_LEN)
if self.format == riscv_instr_format_t.I_FORMAT:
if self.instr_name in [riscv_instr_name_t.FSRI,
riscv_instr_name_t.FSRIW]: # instr rd, rs1, rs3, imm
asm_str_final = "{}{}, {}, {}, {}".format(asm_str, self.rd.name, self.rs1.name,
self.rs3.name, self.get_imm())
elif self.format == riscv_instr_format_t.R_FORMAT: # instr rd, rs1
if not self.has_rs2:
asm_str_final = "{}{}, {}".format(asm_str, self.rd.name, self.rs1.name)
elif self.format == riscv_instr_format_t.R4_FORMAT: # instr rd, rs1, rs2, rs3
asm_str_final = "{}{}, {}, {}, {}".format(asm_str, self.rd.name, self.rs1.name,
self.rs2.name, self.rs3.name)
else:
logging.info("Unsupported format {}".format(self.format))
if asm_str_final == "":
return super().convert2asm(prefix)
if self.comment != "":
asm_str_final = asm_str_final + " #" + self.comment
return asm_str_final.lower()
def get_opcode(self):
# TODO
pass
def get_func3(self):
# TODO
pass
def get_func5(self):
# TODO
pass
def get_func2(self):
# TODO
pass
# Convert the instruction to assembly code
def convert2bin(self, prefix):
pass
def is_supported(self, cfg):
return (cfg.enable_b_extension and
("ZBB" in cfg.enable_bitmanip_groups and self.instr_name.name in
["CLZ", "CTZ", "CLZW", "CTZW", "PCNT", "PCNTW",
"SLO", "SLOI", "SLOW", "SLOIW",
"SRO", "SROI", "SROW", "SROIW",
"MIN", "MINU", "MAX", "MAXU",
"ADDWU", "ADDIWU", "SUBWU",
"ADDU_W", "SUBU_W",
"SLLIU_W",
"ANDN", "ORN",
"XNOR", "PACK", "PACKW", "PACKU", "PACKUW", "PACKH",
"ROL", "ROLW", "ROR", "RORW", "RORI", "RORIW"
]) or
("ZBS" in cfg.enable_bitmanip_groups and self.instr_name.name in
["SBSET", "SBSETW", "SBSETI", "SBSETIW",
"SBCLR", "SBCLRW", "SBCLRI", "SBCLRIW",
"SBINV", "SBINVW", "SBINVI", "SBINVIW",
"SBEXT", "SBEXTW", "SBEXTI"
]) or
("ZBP" in cfg.enable_bitmanip_groups and self.instr_name.name in
["GREV", "GREVW", "GREVI", "GREVIW",
"GORC", "GORCW", "GORCI", "GORCIW",
"SHFL", "SHFLW", "UNSHFL", "UNSHFLW", "SHFLI", "UNSHFLI"
]) or
("ZBE" in cfg.enable_bitmanip_groups and self.instr_name in
["BEXT", "BEXTW",
"BDEP", "BDEPW"
]) or
("ZBF" in cfg.enable_bitmanip_groups and self.instr_name.name in
["BFP", "BFPW"
]) or
("ZBC" in cfg.enable_bitmanip_groups and self.instr_name.name in
["CLMUL", "CLMULW", "CLMULH", "CLMULHW", "CLMULR", "CLMULRW"
]) or
("ZBR" in cfg.enable_bitmanip_groups and self.instr_name.name in
["CRC32_B", "CRC32_H", "CRC32_W", "CRC32_D",
"CRC32C_B", "CRC32C_H", "CRC32C_W", "CRC32C_D"
]) or
("ZBM" in cfg.enable_bitmanip_groups and self.instr_name.name in
["BMATOR", "BMATXOR", "BMATFLIP"
]) or
("ZBT" in cfg.enable_bitmanip_groups and self.instr_name.name in
["CMOV", "CMIX",
"FSL", "FSLW", "FSR", "FSRW", "FSRI", "FSRIW"
]) or
# TODO, spec 0.92 doesn't categorize these 2 instr, put them in ZB_TMP #572
("ZB_TMP" in cfg.enable_bitmanip_groups and self.instr_name.name in
["SEXT_B", "SEXT_H"
])
)
# Coverage related functions
def update_src_regs(self, operands):
# TODO
pass

View file

@ -139,9 +139,10 @@ class riscv_instr:
if instr_name in [riscv_instr_name_t.FENCE, riscv_instr_name_t.FENCE_I,
riscv_instr_name_t.SFENCE_VMA]:
continue
if (instr_inst.group.name in rcs.supported_isa and
if (instr_inst.group in rcs.supported_isa and
not(cfg.disable_compressed_instr and
instr_inst.group.name in ["RV32C", "RV64C", "RV32DC", "RV32FC", "RV128C"]) and
instr_inst.group.name in ["RV32C", "RV64C", "RV32DC",
"RV32FC", "RV128C"]) and
not(not(cfg.enable_floating_point) and instr_inst.group.name in
["RV32F", "RV64F", "RV32D", "RV64D"])):
cls.instr_category[instr_inst.category.name].append(instr_name)
@ -169,8 +170,9 @@ class riscv_instr:
cls.instr_category["LOGICAL"] + cls.instr_category["COMPARE"])
if cfg.no_ebreak == 0:
cls.basic_instr.append("EBREAK")
for items in rcs.supported_isa:
if("RV32C" in rcs.supported_isa and not(cfg.disable_compressed_instr)):
for _ in rcs.supported_isa:
if(riscv_instr_group_t.RV32C in rcs.supported_isa and
not(cfg.disable_compressed_instr)):
cls.basic_instr.append("C_EBREAK")
break
if cfg.no_dret == 0:

View file

@ -0,0 +1,40 @@
"""
Copyright 2020 Google LLC
Copyright 2020 PerfectVIPs Inc.
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.
"""
from pygen_src.riscv_defines import DEFINE_AMO_INSTR
from pygen_src.riscv_instr_pkg import (riscv_instr_name_t, riscv_instr_format_t,
riscv_instr_category_t, riscv_instr_group_t)
DEFINE_AMO_INSTR(riscv_instr_name_t.LR_W, riscv_instr_format_t.R_FORMAT,
riscv_instr_category_t.LOAD, riscv_instr_group_t.RV32A, g=globals())
DEFINE_AMO_INSTR(riscv_instr_name_t.SC_W, riscv_instr_format_t.R_FORMAT,
riscv_instr_category_t.STORE, riscv_instr_group_t.RV32A, g=globals())
DEFINE_AMO_INSTR(riscv_instr_name_t.AMOSWAP_W, riscv_instr_format_t.R_FORMAT,
riscv_instr_category_t.AMO, riscv_instr_group_t.RV32A, g=globals())
DEFINE_AMO_INSTR(riscv_instr_name_t.AMOADD_W, riscv_instr_format_t.R_FORMAT,
riscv_instr_category_t.AMO, riscv_instr_group_t.RV32A, g=globals())
DEFINE_AMO_INSTR(riscv_instr_name_t.AMOAND_W, riscv_instr_format_t.R_FORMAT,
riscv_instr_category_t.AMO, riscv_instr_group_t.RV32A, g=globals())
DEFINE_AMO_INSTR(riscv_instr_name_t.AMOOR_W, riscv_instr_format_t.R_FORMAT,
riscv_instr_category_t.AMO, riscv_instr_group_t.RV32A, g=globals())
DEFINE_AMO_INSTR(riscv_instr_name_t.AMOXOR_W, riscv_instr_format_t.R_FORMAT,
riscv_instr_category_t.AMO, riscv_instr_group_t.RV32A, g=globals())
DEFINE_AMO_INSTR(riscv_instr_name_t.AMOMIN_W, riscv_instr_format_t.R_FORMAT,
riscv_instr_category_t.AMO, riscv_instr_group_t.RV32A, g=globals())
DEFINE_AMO_INSTR(riscv_instr_name_t.AMOMAX_W, riscv_instr_format_t.R_FORMAT,
riscv_instr_category_t.AMO, riscv_instr_group_t.RV32A, g=globals())
DEFINE_AMO_INSTR(riscv_instr_name_t.AMOMINU_W, riscv_instr_format_t.R_FORMAT,
riscv_instr_category_t.AMO, riscv_instr_group_t.RV32A, g=globals())
DEFINE_AMO_INSTR(riscv_instr_name_t.AMOMAXU_W, riscv_instr_format_t.R_FORMAT,
riscv_instr_category_t.AMO, riscv_instr_group_t.RV32A, g=globals())

View file

@ -0,0 +1,135 @@
"""
Copyright 2020 Google LLC
Copyright 2020 PerfectVIPs Inc.
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.
"""
from pygen_src.riscv_defines import DEFINE_B_INSTR
from pygen_src.riscv_instr_pkg import (riscv_instr_name_t, riscv_instr_format_t,
riscv_instr_category_t, riscv_instr_group_t, imm_t)
DEFINE_B_INSTR(riscv_instr_name_t.SEXT_B, riscv_instr_format_t.R_FORMAT,
riscv_instr_category_t.LOGICAL, riscv_instr_group_t.RV32B, g=globals())
DEFINE_B_INSTR(riscv_instr_name_t.SEXT_H, riscv_instr_format_t.R_FORMAT,
riscv_instr_category_t.LOGICAL, riscv_instr_group_t.RV32B, g=globals())
DEFINE_B_INSTR(riscv_instr_name_t.ANDN, riscv_instr_format_t.R_FORMAT,
riscv_instr_category_t.LOGICAL, riscv_instr_group_t.RV32B, g=globals())
DEFINE_B_INSTR(riscv_instr_name_t.ORN, riscv_instr_format_t.R_FORMAT,
riscv_instr_category_t.LOGICAL, riscv_instr_group_t.RV32B, g=globals())
DEFINE_B_INSTR(riscv_instr_name_t.XNOR, riscv_instr_format_t.R_FORMAT,
riscv_instr_category_t.LOGICAL, riscv_instr_group_t.RV32B, g=globals())
DEFINE_B_INSTR(riscv_instr_name_t.GORC, riscv_instr_format_t.R_FORMAT,
riscv_instr_category_t.LOGICAL, riscv_instr_group_t.RV32B, g=globals())
DEFINE_B_INSTR(riscv_instr_name_t.GORCI, riscv_instr_format_t.I_FORMAT,
riscv_instr_category_t.LOGICAL, riscv_instr_group_t.RV32B, imm_t.UIMM, g=globals())
DEFINE_B_INSTR(riscv_instr_name_t.CMIX, riscv_instr_format_t.R4_FORMAT,
riscv_instr_category_t.LOGICAL, riscv_instr_group_t.RV32B, g=globals())
DEFINE_B_INSTR(riscv_instr_name_t.CMOV, riscv_instr_format_t.R4_FORMAT,
riscv_instr_category_t.LOGICAL, riscv_instr_group_t.RV32B, g=globals())
DEFINE_B_INSTR(riscv_instr_name_t.PACK, riscv_instr_format_t.R_FORMAT,
riscv_instr_category_t.LOGICAL, riscv_instr_group_t.RV32B, g=globals())
DEFINE_B_INSTR(riscv_instr_name_t.PACKU, riscv_instr_format_t.R_FORMAT,
riscv_instr_category_t.LOGICAL, riscv_instr_group_t.RV32B, g=globals())
DEFINE_B_INSTR(riscv_instr_name_t.PACKH, riscv_instr_format_t.R_FORMAT,
riscv_instr_category_t.LOGICAL, riscv_instr_group_t.RV32B, g=globals())
# SHIFH instructions
DEFINE_B_INSTR(riscv_instr_name_t.SLO, riscv_instr_format_t.R_FORMAT,
riscv_instr_category_t.SHIFT, riscv_instr_group_t.RV32B, g=globals())
DEFINE_B_INSTR(riscv_instr_name_t.SRO, riscv_instr_format_t.R_FORMAT,
riscv_instr_category_t.SHIFT, riscv_instr_group_t.RV32B, g=globals())
DEFINE_B_INSTR(riscv_instr_name_t.ROL, riscv_instr_format_t.R_FORMAT,
riscv_instr_category_t.SHIFT, riscv_instr_group_t.RV32B, g=globals())
DEFINE_B_INSTR(riscv_instr_name_t.ROR, riscv_instr_format_t.R_FORMAT,
riscv_instr_category_t.SHIFT, riscv_instr_group_t.RV32B, g=globals())
DEFINE_B_INSTR(riscv_instr_name_t.SBCLR, riscv_instr_format_t.R_FORMAT,
riscv_instr_category_t.SHIFT, riscv_instr_group_t.RV32B, g=globals())
DEFINE_B_INSTR(riscv_instr_name_t.SBSET, riscv_instr_format_t.R_FORMAT,
riscv_instr_category_t.SHIFT, riscv_instr_group_t.RV32B, g=globals())
DEFINE_B_INSTR(riscv_instr_name_t.SBINV, riscv_instr_format_t.R_FORMAT,
riscv_instr_category_t.SHIFT, riscv_instr_group_t.RV32B, g=globals())
DEFINE_B_INSTR(riscv_instr_name_t.SBEXT, riscv_instr_format_t.R_FORMAT,
riscv_instr_category_t.SHIFT, riscv_instr_group_t.RV32B, g=globals())
DEFINE_B_INSTR(riscv_instr_name_t.GREV, riscv_instr_format_t.R_FORMAT,
riscv_instr_category_t.SHIFT, riscv_instr_group_t.RV32B, g=globals())
DEFINE_B_INSTR(riscv_instr_name_t.GREVI, riscv_instr_format_t.I_FORMAT,
riscv_instr_category_t.SHIFT, riscv_instr_group_t.RV32B, imm_t.UIMM, g=globals())
DEFINE_B_INSTR(riscv_instr_name_t.SLOI, riscv_instr_format_t.I_FORMAT,
riscv_instr_category_t.SHIFT, riscv_instr_group_t.RV32B, imm_t.UIMM, g=globals())
DEFINE_B_INSTR(riscv_instr_name_t.SROI, riscv_instr_format_t.I_FORMAT,
riscv_instr_category_t.SHIFT, riscv_instr_group_t.RV32B, imm_t.UIMM, g=globals())
DEFINE_B_INSTR(riscv_instr_name_t.RORI, riscv_instr_format_t.I_FORMAT,
riscv_instr_category_t.SHIFT, riscv_instr_group_t.RV32B, imm_t.UIMM, g=globals())
DEFINE_B_INSTR(riscv_instr_name_t.SBCLRI, riscv_instr_format_t.I_FORMAT,
riscv_instr_category_t.SHIFT, riscv_instr_group_t.RV32B, imm_t.UIMM, g=globals())
DEFINE_B_INSTR(riscv_instr_name_t.SBSETI, riscv_instr_format_t.I_FORMAT,
riscv_instr_category_t.SHIFT, riscv_instr_group_t.RV32B, imm_t.UIMM, g=globals())
DEFINE_B_INSTR(riscv_instr_name_t.SBINVI, riscv_instr_format_t.I_FORMAT,
riscv_instr_category_t.SHIFT, riscv_instr_group_t.RV32B, imm_t.UIMM, g=globals())
DEFINE_B_INSTR(riscv_instr_name_t.SBEXTI, riscv_instr_format_t.I_FORMAT,
riscv_instr_category_t.SHIFT, riscv_instr_group_t.RV32B, imm_t.UIMM, g=globals())
DEFINE_B_INSTR(riscv_instr_name_t.FSL, riscv_instr_format_t.R4_FORMAT,
riscv_instr_category_t.SHIFT, riscv_instr_group_t.RV32B, g=globals())
DEFINE_B_INSTR(riscv_instr_name_t.FSR, riscv_instr_format_t.R4_FORMAT,
riscv_instr_category_t.SHIFT, riscv_instr_group_t.RV32B, g=globals())
DEFINE_B_INSTR(riscv_instr_name_t.FSRI, riscv_instr_format_t.I_FORMAT,
riscv_instr_category_t.SHIFT, riscv_instr_group_t.RV32B, imm_t.UIMM, g=globals())
# ARITMETIC instructions
DEFINE_B_INSTR(riscv_instr_name_t.CLZ, riscv_instr_format_t.R_FORMAT,
riscv_instr_category_t.ARITHMETIC, riscv_instr_group_t.RV32B, g=globals())
DEFINE_B_INSTR(riscv_instr_name_t.CTZ, riscv_instr_format_t.R_FORMAT,
riscv_instr_category_t.ARITHMETIC, riscv_instr_group_t.RV32B, g=globals())
DEFINE_B_INSTR(riscv_instr_name_t.PCNT, riscv_instr_format_t.R_FORMAT,
riscv_instr_category_t.ARITHMETIC, riscv_instr_group_t.RV32B, g=globals())
DEFINE_B_INSTR(riscv_instr_name_t.CRC32_B, riscv_instr_format_t.R_FORMAT,
riscv_instr_category_t.ARITHMETIC, riscv_instr_group_t.RV32B, g=globals())
DEFINE_B_INSTR(riscv_instr_name_t.CRC32_H, riscv_instr_format_t.R_FORMAT,
riscv_instr_category_t.ARITHMETIC, riscv_instr_group_t.RV32B, g=globals())
DEFINE_B_INSTR(riscv_instr_name_t.CRC32_W, riscv_instr_format_t.R_FORMAT,
riscv_instr_category_t.ARITHMETIC, riscv_instr_group_t.RV32B, g=globals())
DEFINE_B_INSTR(riscv_instr_name_t.CRC32C_B, riscv_instr_format_t.R_FORMAT,
riscv_instr_category_t.ARITHMETIC, riscv_instr_group_t.RV32B, g=globals())
DEFINE_B_INSTR(riscv_instr_name_t.CRC32C_H, riscv_instr_format_t.R_FORMAT,
riscv_instr_category_t.ARITHMETIC, riscv_instr_group_t.RV32B, g=globals())
DEFINE_B_INSTR(riscv_instr_name_t.CRC32C_W, riscv_instr_format_t.R_FORMAT,
riscv_instr_category_t.ARITHMETIC, riscv_instr_group_t.RV32B, g=globals())
DEFINE_B_INSTR(riscv_instr_name_t.CLMUL, riscv_instr_format_t.R_FORMAT,
riscv_instr_category_t.ARITHMETIC, riscv_instr_group_t.RV32B, g=globals())
DEFINE_B_INSTR(riscv_instr_name_t.CLMULR, riscv_instr_format_t.R_FORMAT,
riscv_instr_category_t.ARITHMETIC, riscv_instr_group_t.RV32B, g=globals())
DEFINE_B_INSTR(riscv_instr_name_t.CLMULH, riscv_instr_format_t.R_FORMAT,
riscv_instr_category_t.ARITHMETIC, riscv_instr_group_t.RV32B, g=globals())
DEFINE_B_INSTR(riscv_instr_name_t.MIN, riscv_instr_format_t.R_FORMAT,
riscv_instr_category_t.ARITHMETIC, riscv_instr_group_t.RV32B, g=globals())
DEFINE_B_INSTR(riscv_instr_name_t.MAX, riscv_instr_format_t.R_FORMAT,
riscv_instr_category_t.ARITHMETIC, riscv_instr_group_t.RV32B, g=globals())
DEFINE_B_INSTR(riscv_instr_name_t.MINU, riscv_instr_format_t.R_FORMAT,
riscv_instr_category_t.ARITHMETIC, riscv_instr_group_t.RV32B, g=globals())
DEFINE_B_INSTR(riscv_instr_name_t.MAXU, riscv_instr_format_t.R_FORMAT,
riscv_instr_category_t.ARITHMETIC, riscv_instr_group_t.RV32B, g=globals())
DEFINE_B_INSTR(riscv_instr_name_t.SHFL, riscv_instr_format_t.R_FORMAT,
riscv_instr_category_t.ARITHMETIC, riscv_instr_group_t.RV32B, g=globals())
DEFINE_B_INSTR(riscv_instr_name_t.UNSHFL, riscv_instr_format_t.R_FORMAT,
riscv_instr_category_t.ARITHMETIC, riscv_instr_group_t.RV32B, g=globals())
DEFINE_B_INSTR(riscv_instr_name_t.BDEP, riscv_instr_format_t.R_FORMAT,
riscv_instr_category_t.ARITHMETIC, riscv_instr_group_t.RV32B, g=globals())
DEFINE_B_INSTR(riscv_instr_name_t.BEXT, riscv_instr_format_t.R_FORMAT,
riscv_instr_category_t.ARITHMETIC, riscv_instr_group_t.RV32B, g=globals())
DEFINE_B_INSTR(riscv_instr_name_t.BFP, riscv_instr_format_t.R_FORMAT,
riscv_instr_category_t.ARITHMETIC, riscv_instr_group_t.RV32B, g=globals())
DEFINE_B_INSTR(riscv_instr_name_t.SHFLI, riscv_instr_format_t.I_FORMAT,
riscv_instr_category_t.ARITHMETIC, riscv_instr_group_t.RV32B, imm_t.UIMM,
g=globals())
DEFINE_B_INSTR(riscv_instr_name_t.UNSHFLI, riscv_instr_format_t.I_FORMAT,
riscv_instr_category_t.ARITHMETIC, riscv_instr_group_t.RV32B, imm_t.UIMM,
g=globals())

View file

@ -0,0 +1,193 @@
"""
Copyright 2020 Google LLC
Copyright 2020 PerfectVIPs Inc.
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.
"""
import vsc
import random
from importlib import import_module
from pygen_src.riscv_directed_instr_lib import riscv_mem_access_stream
from pygen_src.riscv_instr_pkg import (riscv_reg_t, riscv_pseudo_instr_name_t,
riscv_instr_name_t, riscv_instr_category_t,
riscv_instr_group_t)
from pygen_src.riscv_instr_gen_config import cfg
from pygen_src.riscv_pseudo_instr import riscv_pseudo_instr
from pygen_src.isa.riscv_instr import riscv_instr
rcs = import_module("pygen_src.target." + cfg.argv.target + ".riscv_core_setting")
# Base class for AMO instruction stream
@vsc.randobj
class riscv_amo_base_instr_stream(riscv_mem_access_stream):
def __init__(self):
super().__init__()
self.num_amo = vsc.rand_uint32_t()
self.num_mixed_instr = vsc.rand_uint32_t()
self.offset = vsc.randsz_list_t(vsc.int32_t())
self.rs1_reg = vsc.randsz_list_t(vsc.enum_t(riscv_reg_t))
self.num_of_rs1_reg = vsc.rand_int32_t()
self.data_page_id = vsc.uint32_t()
self.max_offset = vsc.uint32_t()
self.XLEN = vsc.uint32_t(rcs.XLEN)
# User can specify a small group of available registers to generate various hazard condition
self.avail_regs = vsc.randsz_list_t(vsc.enum_t(riscv_reg_t))
@vsc.constraint
def num_of_rs1_reg_c(self):
self.num_of_rs1_reg == 1
@vsc.constraint
def rs1_c(self):
# TODO constraint size with num_of_rs1_reg
vsc.solve_order(self.num_of_rs1_reg, self.rs1_reg)
self.rs1_reg.size == 1 # self.num_of_rs1_reg
self.offset.size == 1 # self.num_of_rs1_reg
with vsc.foreach(self.rs1_reg, idx = True) as i:
self.rs1_reg[i].not_inside(vsc.rangelist(cfg.reserved_regs,
self.reserved_rd, riscv_reg_t.ZERO))
vsc.unique(self.rs1_reg)
@vsc.constraint
def addr_range_c(self):
with vsc.foreach(self.offset, idx = True) as i:
self.offset[i] in vsc.rangelist(vsc.rng(0, self.max_offset - 1))
@vsc.constraint
def aligned_amo_c(self):
with vsc.foreach(self.offset, idx = True) as i:
with vsc.if_then(self.XLEN == 32):
self.offset[i] % 4 == 0
with vsc.else_then():
self.offset[i] % 8 == 0
def pre_randomize(self):
self.data_page = cfg.amo_region
max_data_page_id = len(self.data_page)
self.data_page_id = random.randrange(0, max_data_page_id - 1)
self.max_offset = self.data_page[self.data_page_id]['size_in_bytes']
# Use "la" instruction to initialize the offset regiseter
def init_offset_reg(self):
for i in range(len(self.rs1_reg)):
la_instr = riscv_pseudo_instr()
la_instr.pseudo_instr_name = riscv_pseudo_instr_name_t.LA
la_instr.rd = self.rs1_reg[i]
la_instr.imm_str = "{}+{}".format(cfg.amo_region[self.data_page_id]['name'],
self.offset[i])
self.instr_list.insert(0, la_instr)
def post_randomize(self):
self.gen_amo_instr()
self.reserved_rd.append(self.rs1_reg)
self.add_mixed_instr(self.num_mixed_instr)
self.init_offset_reg()
super().post_randomize()
# AMO instruction generation
def gen_amo_instr(self):
pass
# A pair of LR/SC instruction
@vsc.randobj
class riscv_lr_sc_instr_stream (riscv_amo_base_instr_stream):
def __init__(self):
super().__init__()
self.lr_instr = vsc.attr(riscv_instr())
self.sc_instr = vsc.attr(riscv_instr())
@vsc.constraint
def legal_c(self):
self.num_amo == 1
self.num_mixed_instr in vsc.rangelist(vsc.rng(0, 15))
def gen_amo_instr(self):
allowed_lr_instr = []
allowed_sc_instr = []
if riscv_instr_group_t.RV32A in rcs.supported_isa:
allowed_lr_instr.append(riscv_instr_name_t.LR_W)
allowed_sc_instr.append(riscv_instr_name_t.SC_W)
if riscv_instr_group_t.RV64A in rcs.supported_isa:
allowed_lr_instr.append(riscv_instr_name_t.LR_D)
allowed_sc_instr.append(riscv_instr_name_t.SC_D)
self.lr_instr = riscv_instr.get_rand_instr(include_instr = allowed_lr_instr)
self.sc_instr = riscv_instr.get_rand_instr(include_instr = allowed_sc_instr)
with self.lr_instr.randomize_with():
# self.lr_instr.rs1 == self.rs1_reg[0] # TODO Getting error
with vsc.if_then(self.reserved_rd.size > 0):
self.lr_instr.rd.not_inside(vsc.rangelist(self.reserved_rd))
with vsc.if_then(cfg.reserved_regs.size > 0):
self.lr_instr.rd.not_inside(vsc.rangelist(cfg.reserved_regs))
# self.lr_instr.rd != self.rs1_reg[0] # TODO
with self.sc_instr.randomize_with():
# self.sc_instr.rs1 == self.rs1_reg[0] # TODO
with vsc.if_then(self.reserved_rd.size > 0):
self.sc_instr.rd.not_inside(vsc.rangelist(self.reserved_rd))
with vsc.if_then(cfg.reserved_regs.size > 0):
self.sc_instr.rd.not_inside(vsc.rangelist(cfg.reserved_regs))
# self.sc_instr.rd != self.rs1_reg[0] # TODO
self.instr_list.extend((self.lr_instr, self.sc_instr))
'''
section 8.3 Eventual Success of Store-Conditional Instructions
An LR/SC sequence begins with an LR instruction and ends with an SC instruction.
The dynamic code executed between the LR and SC instructions can only contain
instructions from the base I instruction set, excluding loads, stores, backward
jumps, taken backward branches, JALR, FENCE, and SYSTEM instructions. If the C
extension is supported, then compressed forms of the aforementioned I instructions
are also permitted.
'''
def add_mixed_instr(self, instr_cnt):
self.setup_allowed_instr(no_branch = 1, no_load_store = 1)
for i in range(instr_cnt):
instr = riscv_instr()
instr = self.randomize_instr(instr, include_group = [riscv_instr_group_t.RV32I,
riscv_instr_group_t.RV32C])
if instr.category not in [riscv_instr_category_t.SYSTEM, riscv_instr_category_t.SYNCH]:
self.insert_instr(instr)
@vsc.randobj
class riscv_amo_instr_stream (riscv_amo_base_instr_stream):
def __init__(self):
super().__init__()
self.amo_instr = []
@vsc.constraint
def reasonable_c(self):
vsc.solve_order(self.num_amo, self.num_mixed_instr)
self.num_amo in vsc.rangelist(vsc.rng(1, 10))
self.num_mixed_instr in vsc.rangelist(vsc.rng(0, self.num_amo))
@vsc.constraint
def num_of_rs1_reg_c(self):
vsc.solve_order(self.num_amo, self.num_of_rs1_reg)
self.num_of_rs1_reg in vsc.rangelist(vsc.rng(1, self.num_amo))
self.num_of_rs1_reg < 5
def gen_amo_instr(self):
for i in range(self.num_amo):
self.amo_instr.append(riscv_instr.get_rand_instr(
include_category=[riscv_instr_category_t.AMO]))
with self.amo_instr[i].randomize_with():
with vsc.if_then(self.reserved_rd.size > 0):
self.amo_instr[i].rd.not_inside(vsc.rangelist(self.reserved_rd))
with vsc.if_then(cfg.reserved_regs.size > 0):
self.amo_instr[i].rd.not_inside(vsc.rangelist(cfg.reserved_regs))
self.amo_instr[i].rs1.inside(vsc.rangelist(self.rs1_reg))
self.amo_instr[i].rd.inside(vsc.rangelist(self.rs1_reg))
self.instr_list.insert(0, self.amo_instr[i])
class riscv_vector_amo_instr_stream():
# TODO
pass

View file

@ -17,12 +17,12 @@ import random
import copy
import sys
import vsc
from bitstring import BitArray
from importlib import import_module
from pygen_src.riscv_instr_sequence import riscv_instr_sequence
from pygen_src.riscv_instr_pkg import (pkg_ins, privileged_reg_t,
privileged_mode_t, mtvec_mode_t,
misa_ext_t, riscv_instr_group_t)
misa_ext_t, riscv_instr_group_t,
satp_mode_t)
from pygen_src.riscv_instr_gen_config import cfg
from pygen_src.riscv_data_page_gen import riscv_data_page_gen
from pygen_src.riscv_privileged_common_seq import riscv_privileged_common_seq
@ -60,7 +60,7 @@ class riscv_asm_program_gen:
# Commenting out for now
# sub_program_name = []
self.instr_stream.append(f"h{int(hart)}_start:")
if(not(cfg.bare_program_mode)):
if not cfg.bare_program_mode:
self.setup_misa()
# Create all page tables
self.create_page_table(hart)
@ -95,7 +95,8 @@ class riscv_asm_program_gen:
self.main_program[hart].label_name = label_name
self.generate_directed_instr_stream(hart=hart,
label=self.main_program[hart].label_name,
original_instr_cnt=self.main_program[hart].instr_cnt,
original_instr_cnt=
self.main_program[hart].instr_cnt,
min_insert_cnt=1,
instr_stream=self.main_program[hart].directed_instr)
self.main_program[hart].gen_instr(is_main_program=1, no_branch=cfg.no_branch_jump)
@ -124,16 +125,16 @@ class riscv_asm_program_gen:
self.gen_data_page_begin(hart)
if not cfg.no_data_page:
self.gen_data_page(hart)
if((hart == 0) and ("RV32A" in rcs.supported_isa)):
if(hart == 0 and riscv_instr_group_t.RV32A
in rcs.supported_isa):
self.gen_data_page(hart, amo = 1)
self.gen_stack_section(hart)
if(not cfg.bare_program_mode):
if not cfg.bare_program_mode:
self.gen_kernel_sections(hart)
def gen_kernel_sections(self, hart):
if(rcs.SATP_MODE != "BARE"):
if rcs.SATP_MODE != satp_mode_t.BARE:
self.instr_stream.append(".align 12")
else:
self.instr_stream.append(".align 2")
@ -166,7 +167,7 @@ class riscv_asm_program_gen:
self.instr_stream.append(".include \"user_define.h\"")
self.instr_stream.append(".globl _start")
self.instr_stream.append(".section .text")
if(cfg.disable_compressed_instr):
if cfg.disable_compressed_instr:
self.instr_stream.append(".option norvc;")
string.append(".include \"user_init.s\"")
string.append("csrr x5, mhartid")
@ -180,13 +181,13 @@ class riscv_asm_program_gen:
self.instr_stream.append("{}: j h{}_start".format(hart, hart))
def gen_program_end(self, hart):
if(hart == 0):
if hart == 0:
self.gen_section("write_tohost", ["sw gp, tohost, t5"])
self.gen_section("_exit", ["j write_tohost"])
def gen_data_page_begin(self, hart):
self.instr_stream.append(".section .data")
if (hart == 0):
if hart == 0:
self.instr_stream.append(".align 6; .global tohost; tohost: .dword 0;")
self.instr_stream.append(".align 6; .global fromhost; fromhost: .dword 0;")
@ -197,13 +198,13 @@ class riscv_asm_program_gen:
def gen_stack_section(self, hart):
hart_prefix_string = pkg_ins.hart_prefix(hart)
if(cfg.use_push_data_section):
if cfg.use_push_data_section:
self.instr_stream.append(
".pushsection .{}user_stack,\"aw\",@progbits;".format(hart_prefix_string))
else:
self.instr_stream.append(
".section .{}user_stack,\"aw\",@progbits;".format(hart_prefix_string))
if(rcs.SATP_MODE != "BARE"):
if rcs.SATP_MODE != satp_mode_t.BARE:
self.instr_stream.append(".align 12")
else:
self.instr_stream.append(".align 2")
@ -214,18 +215,18 @@ class riscv_asm_program_gen:
self.instr_stream.append(".endr")
self.instr_stream.append(pkg_ins.get_label("user_stack_end:", hart))
self.instr_stream.append(".{}byte 0x0".format(rcs.XLEN // 8))
if (cfg.use_push_data_section):
if cfg.use_push_data_section:
self.instr_stream.push_back(".popsection;")
def gen_kernel_stack_section(self, hart):
hart_prefix_string = pkg_ins.hart_prefix(hart)
if(cfg.use_push_data_section):
if cfg.use_push_data_section:
self.instr_stream.append(
".pushsection .{}kernel_stack,\"aw\",@progbits;".format(hart_prefix_string))
else:
self.instr_stream.append(
".section .{}kernel_stack,\"aw\",@progbits;".format(hart_prefix_string))
if(rcs.SATP_MODE != "BARE"):
if rcs.SATP_MODE != satp_mode_t.BARE:
self.instr_stream.append(".align 12")
else:
self.instr_stream.append(".align 2")
@ -236,24 +237,24 @@ class riscv_asm_program_gen:
self.instr_stream.append(".endr")
self.instr_stream.append(pkg_ins.get_label("kernel_stack_end:", hart))
self.instr_stream.append(".{}byte 0x0".format(rcs.XLEN // 8))
if (cfg.use_push_data_section):
if cfg.use_push_data_section:
self.instr_stream.push_back(".popsection;")
def gen_init_section(self, hart):
string = pkg_ins.format_string("init:", pkg_ins.LABEL_STR_LEN)
self.instr_stream.append(string)
if (cfg.enable_floating_point):
if cfg.enable_floating_point:
self.init_floating_point_gpr()
self.init_gpr()
# Init stack pointer to point to the end of the user stack
string = "{}la x{}, {}user_stack_end".format(
pkg_ins.indent, cfg.sp.value, pkg_ins.hart_prefix(hart))
self.instr_stream.append(string)
if (cfg.enable_vector_extension):
if cfg.enable_vector_extension:
self.init_vector_engine()
self.core_is_initialized()
self.gen_dummy_csr_write()
if (rcs.support_pmp):
if rcs.support_pmp:
string = pkg_ins.indent + "j main"
self.instr_stream.append(string)
@ -268,46 +269,47 @@ class riscv_asm_program_gen:
misa[rcs.XLEN - 1:rcs.XLEN - 2] = 3
if cfg.check_misa_init_val:
self.instr_stream.append("{}csrr x15, {}".format(pkg_ins.indent,
hex(privileged_reg_t.MISA)))
for i in range(len(rcs.supported_isa)):
if rcs.supported_isa[i] in [riscv_instr_group_t.RV32C.name,
riscv_instr_group_t.RV64C.name,
riscv_instr_group_t.RV128C.name]:
hex(privileged_reg_t.MISA)))
for group in rcs.supported_isa:
if group in [riscv_instr_group_t.RV32C,
riscv_instr_group_t.RV64C,
riscv_instr_group_t.RV128C]:
misa[misa_ext_t.MISA_EXT_C] = 1
elif rcs.supported_isa[i] in [riscv_instr_group_t.RV32I.name,
riscv_instr_group_t.RV64I.name,
riscv_instr_group_t.RV128I.name]:
elif group in [riscv_instr_group_t.RV32I,
riscv_instr_group_t.RV64I,
riscv_instr_group_t.RV128I]:
misa[misa_ext_t.MISA_EXT_I] = 1
elif rcs.supported_isa[i] in [riscv_instr_group_t.RV32M.name,
riscv_instr_group_t.RV64M.name]:
elif group in [riscv_instr_group_t.RV32M,
riscv_instr_group_t.RV64M]:
misa[misa_ext_t.MISA_EXT_M] = 1
elif rcs.supported_isa[i] in [riscv_instr_group_t.RV32A.name,
riscv_instr_group_t.RV64A.name]:
elif group in [riscv_instr_group_t.RV32A,
riscv_instr_group_t.RV64A]:
misa[misa_ext_t.MISA_EXT_A] = 1
elif rcs.supported_isa[i] in [riscv_instr_group_t.RV32B.name,
riscv_instr_group_t.RV64B.name]:
elif group in [riscv_instr_group_t.RV32B,
riscv_instr_group_t.RV64B]:
misa[misa_ext_t.MISA_EXT_B] = 1
elif rcs.supported_isa[i] in [riscv_instr_group_t.RV32F.name,
riscv_instr_group_t.RV64F.name,
riscv_instr_group_t.RV32FC.name]:
elif group in [riscv_instr_group_t.RV32F,
riscv_instr_group_t.RV64F,
riscv_instr_group_t.RV32FC]:
misa[misa_ext_t.MISA_EXT_F] = 1
elif rcs.supported_isa[i] in [riscv_instr_group_t.RV32D.name,
riscv_instr_group_t.RV64D.name,
riscv_instr_group_t.RV32DC.name]:
elif group in [riscv_instr_group_t.RV32D,
riscv_instr_group_t.RV64D,
riscv_instr_group_t.RV32DC]:
misa[misa_ext_t.MISA_EXT_D] = 1
elif rcs.supported_isa[i] in [riscv_instr_group_t.RVV.name]:
elif group in [riscv_instr_group_t.RVV]:
misa[misa_ext_t.MISA_EXT_V] = 1
elif rcs.supported_isa[i] in [riscv_instr_group_t.RV32X.name,
riscv_instr_group_t.RV64X.name]:
elif group in [riscv_instr_group_t.RV32X,
riscv_instr_group_t.RV64X]:
misa[misa_ext_t.MISA_EXT_X] = 1
else:
logging.error("{} is not yet supported".format(rcs.supported_isa[i]))
logging.critical("{} is not yet supported".format(group.name))
sys.exit(1)
if privileged_mode_t.SUPERVISOR_MODE.name in rcs.supported_privileged_mode:
misa[misa_ext_t.MISA_EXT_S] = 1
self.instr_stream.append("{}li x{}, {}".format(pkg_ins.indent, cfg.gpr[0].value,
hex(misa.get_val())))
self.instr_stream.append("{}csrw {}, x{}".format(pkg_ins.indent,
hex(privileged_reg_t.MISA), cfg.gpr[0].value))
hex(misa.get_val())))
self.instr_stream.append("{}csrw {}, x{}".format(pkg_ins.indent, hex(privileged_reg_t.MISA),
cfg.gpr[0].value))
def core_is_initialized(self):
pass
@ -316,35 +318,28 @@ class riscv_asm_program_gen:
pass
def init_gpr(self):
reg_val = BitArray(uint = 0, length = pkg_ins.DATA_WIDTH)
# TODO Map the function with PyVSC std::randomize()
reg_val = vsc.rand_bit_t(pkg_ins.DATA_WIDTH)
for i in range(rcs.NUM_GPR):
if i in [cfg.sp.value, cfg.tp.value]:
continue
if i == 0:
reg_val = BitArray(hex='0x0')
elif i == 1:
reg_val = BitArray(hex='0x80000000')
elif i == 2:
temp = random.randrange(0x1, 0xf)
reg_val = BitArray(hex(temp), length=32)
elif i == 3:
temp = random.randrange(0x10, 0xefffffff)
reg_val = BitArray(hex(temp), length=32)
else:
temp = random.randrange(0xf0000000, 0xffffffff)
reg_val = BitArray(hex(temp), length=32)
init_string = "{}li x{}, {}".format(pkg_ins.indent, i, reg_val)
try:
with vsc.randomize_with(reg_val):
vsc.dist(reg_val, [vsc.weight(0, 1), vsc.weight(0x80000000, 1),
vsc.weight(vsc.rng(0x1, 0xf), 1),
vsc.weight(vsc.rng(0x10, 0xefffffff), 1),
vsc.weight(vsc.rng(0xf0000000, 0xffffffff), 1)])
except Exception:
logging.critical("Cannot Randomize reg_val")
sys.exit(1)
init_string = "{}li x{}, {}".format(pkg_ins.indent, i, hex(reg_val.get_val()))
self.instr_stream.append(init_string)
def init_floating_point_gpr(self):
for i in range(rcs.NUM_FLOAT_GPR):
# TODO randselect
'''
vsc.randselect([(1, lambda:self.init_floating_point_gpr_with_spf(i)),
('RV64D' in rcs.supported_isa, lambda:self.init_floating_point_gpr_with_dpf(i))])
'''
self.init_floating_point_gpr_with_spf(i)
vsc.randselect([
(1, lambda: self.init_floating_point_gpr_with_spf(i)),
(riscv_instr_group_t.RV64D in rcs.supported_isa,
lambda: self.init_floating_point_gpr_with_dpf(i))])
# Initialize rounding mode of FCSR
fsrmi_instr = "{}fsrmi {}".format(pkg_ins.indent, cfg.fcsr_rm)
self.instr_stream.append(fsrmi_instr)
@ -353,7 +348,7 @@ class riscv_asm_program_gen:
imm = self.get_rand_spf_value()
li_instr = "{}li x{}, {}".format(pkg_ins.indent, cfg.gpr[0].value, hex(imm))
fmv_instr = "{}fmv.w.x f{}, x{}".format(pkg_ins.indent, int_floating_gpr,
cfg.gpr[0].value)
cfg.gpr[0].value)
self.instr_stream.extend((li_instr, fmv_instr))
def init_floating_point_gpr_with_dpf(self, int_floating_gpr):
@ -391,7 +386,7 @@ class riscv_asm_program_gen:
self.instr_stream.append(string)
self.instr_stream.append(pkg_ins.indent + "li gp, 1")
if(cfg.bare_program_mode):
if cfg.bare_program_mode:
self.instr_stream.append(pkg_ins.indent + "j write_tohost")
else:
self.instr_stream.append(pkg_ins.indent + "ecall")
@ -404,7 +399,7 @@ class riscv_asm_program_gen:
# Generate sw/sd instructions
for i in range(32):
if (rcs.XLEN == 64):
if rcs.XLEN == 64:
string = "{}sd x{}, {}(x{})".format(
pkg_ins.indent, i, i * (rcs.XLEN / 8), cfg.gpr[0].value)
else:
@ -424,7 +419,7 @@ class riscv_asm_program_gen:
self.trap_vector_init(hart)
self.setup_pmp(hart)
if(cfg.virtual_addr_translation_on):
if cfg.virtual_addr_translation_on:
self.page_table_list.process_page_table(instr)
self.gen_section(pkg_ins.get_label("process_pt", hart), instr)
self.setup_epc(hart)
@ -435,7 +430,7 @@ class riscv_asm_program_gen:
for i in range(len(rcs.supported_privileged_mode)):
instr = []
csr_handshake = []
if(rcs.supported_privileged_mode[i] != cfg.init_privileged_mode.name):
if rcs.supported_privileged_mode[i] != cfg.init_privileged_mode:
continue
logging.info("Generating privileged mode routing for {}"
.format(rcs.supported_privileged_mode[i]))
@ -451,14 +446,14 @@ class riscv_asm_program_gen:
def setup_epc(self, hart):
instr = []
instr.append("la x{}, {}init".format(cfg.gpr[0].value, pkg_ins.hart_prefix(hart)))
if(cfg.virtual_addr_translation_on):
if cfg.virtual_addr_translation_on:
# For supervisor and user mode, use virtual address instead of physical address.
# Virtual address starts from address 0x0, here only the lower 12 bits are kept
# as virtual address offset.
instr.append("slli x{}, x{}, {}".format(cfg.gpr[0].value,
cfg.gpr[0].value, rcs.XLEN - 12) +
"srli x{}, x{}, {}".format(cfg.gpr[0].value,
cfg.gpr[0].value, rcs.XLEN - 12))
cfg.gpr[0].value, rcs.XLEN - 12) +
"srli x{}, x{}, {}".format(cfg.gpr[0].value,
cfg.gpr[0].value, rcs.XLEN - 12))
mode_name = cfg.init_privileged_mode.name
instr.append("csrw {}, x{}".format(hex(privileged_reg_t.MEPC), cfg.gpr[0].value))
if not rcs.support_pmp:
@ -472,7 +467,7 @@ class riscv_asm_program_gen:
self.gen_delegation_instr(hart, "MEDELEG", "MIDELEG",
cfg.m_mode_exception_delegation,
cfg.m_mode_interrupt_delegation)
if(rcs.support_umode_trap):
if rcs.support_umode_trap:
self.gen_delegation_instr(hart, "SEDELEG", "SIDELEG",
cfg.s_mode_exception_delegation,
cfg.s_mode_interrupt_delegation)
@ -483,28 +478,28 @@ class riscv_asm_program_gen:
def trap_vector_init(self, hart):
instr = []
for items in rcs.supported_privileged_mode:
if(items == "MACHINE_MODE"):
for mode in rcs.supported_privileged_mode:
if mode == privileged_mode_t.MACHINE_MODE:
trap_vec_reg = privileged_reg_t.MTVEC
elif(items == "SUPERVISOR_MODE"):
elif mode == privileged_mode_t.SUPERVISOR_MODE:
trap_vec_reg = privileged_reg_t.STVEC
elif(items == "USER_MODE"):
elif mode == privileged_mode_t.USER_MODE:
trap_vec_reg = privileged_reg_t.UTVEC
else:
logging.critical(
"[riscv_asm_program_gen] Unsupported privileged_mode {}".format(items))
logging.critical("Unsupported privileged_mode {}".format(mode.name))
sys.exit(1)
if(items == "USER_MODE" and not (rcs.support_umode_trap)):
if(mode == privileged_mode_t.USER_MODE and not (rcs.support_umode_trap)):
continue
if(items < cfg.init_privileged_mode.name):
if mode < cfg.init_privileged_mode:
continue
tvec_name = trap_vec_reg.name
tvec_name = tvec_name.lower()
instr.append("la x{}, {}{}_handler".format(
cfg.gpr[0].value, pkg_ins.hart_prefix(hart), tvec_name))
if(rcs.SATP_MODE != "BARE" and items != "MACHINE_MODE"):
if(rcs.SATP_MODE != satp_mode_t.BARE and mode != privileged_mode_t.MACHINE_MODE):
instr.append("slli x{}, x{}, {}\n".format(cfg.gpr[0].value,
cfg.gpr[0].value, rcs.XLEN - 20) +
"srli x{}, x{}, {}".format(cfg.gpr[0].value,
@ -518,7 +513,7 @@ class riscv_asm_program_gen:
self.gen_section(pkg_ins.get_label("trap_vec_init", hart), instr)
def gen_all_trap_handler(self, hart):
if(not rcs.support_pmp):
if not rcs.support_pmp:
self.gen_trap_handlers(hart)
self.gen_ecall_handler(hart)
self.gen_instr_fault_handler(hart)
@ -537,7 +532,7 @@ class riscv_asm_program_gen:
is_interrupt = 1
tvec_name = ""
instr = []
if (cfg.mtvec_mode == mtvec_mode_t.VECTORED):
if cfg.mtvec_mode == mtvec_mode_t.VECTORED:
self.gen_interrupt_vector_table(hart, mode, status, cause, ie, ip, scratch, instr)
else:
# Push user mode GPR to kernel stack before executing exception handling,
@ -552,14 +547,17 @@ class riscv_asm_program_gen:
instr.append("csrr x{}, {} # {}".format(
cfg.gpr[0].value, hex(status.value), status.name))
instr.append("csrr x{}, {} # {}\n".format(cfg.gpr[0].value, hex(cause.value),
cause.name) +
cause.name) +
"{}srli x{}, x{}, {}\n".format(pkg_ins.indent, cfg.gpr[0].value,
cfg.gpr[0].value, rcs.XLEN - 1) + "{}bne x{}, x0, {}{}mode_instr_handler"
.format(pkg_ins.indent, cfg.gpr[0].value, pkg_ins.hart_prefix(hart), mode))
cfg.gpr[0].value, rcs.XLEN - 1) +
"{}bne x{}, x0, {}{}mode_instr_handler".format(pkg_ins.indent,
cfg.gpr[0].value,
pkg_ins.hart_prefix(hart),
mode))
# The trap handler will occupy one 4KB page, it will be allocated one entry in
# the page table with a specific privileged mode.
if (rcs.SATP_MODE != "BARE"):
if rcs.SATP_MODE != satp_mode_t.BARE:
self.instr_stream.append(".align 12")
else:
self.instr_stream.append(".align {}".format(cfg.tvec_alignment))
@ -614,46 +612,47 @@ class riscv_asm_program_gen:
def gen_interrupt_handler_section(self, mode, hart):
interrupt_handler_instr = []
ls_unit = "w" if (rcs.XLEN == 32) else "d"
# TODO
# if(mode.value < cfg.init_privileged_mode):
# return
if(mode is privileged_mode_t.USER_MODE.name and not (rcs.support_umode_trap)):
ls_unit = "w" if rcs.XLEN == 32 else "d"
if mode < cfg.init_privileged_mode:
return
if(mode == privileged_mode_t.MACHINE_MODE.name):
if(mode is privileged_mode_t.USER_MODE and not (rcs.support_umode_trap)):
return
if mode == privileged_mode_t.MACHINE_MODE:
mode_prefix = "m"
status = privileged_reg_t.MSTATUS
ip = privileged_reg_t.MIP
ie = privileged_reg_t.MIE
scratch = privileged_reg_t.MSCRATCH
elif(mode is privileged_mode_t.SUPERVISOR_MODE.name):
elif mode is privileged_mode_t.SUPERVISOR_MODE:
mode_prefix = "s"
status = privileged_reg_t.SSTATUS
ip = privileged_reg_t.SIP
ie = privileged_reg_t.SIE
scratch = privileged_reg_t.SSCRATCH
elif(mode == privileged_mode_t.USER_MODE.name):
elif mode == privileged_mode_t.USER_MODE:
mode_prefix = "u"
status = privileged_reg_t.USTATUS
ip = privileged_reg_t.UIP
ie = privileged_reg_t.UIE
scratch = privileged_reg_t.USCRATCH
else:
logging.critical("Unsupported mode: %0s" % (mode))
logging.critical("Unsupported mode: {}".format(mode.name))
sys.exit(1)
if(cfg.enable_nested_interrupt):
if cfg.enable_nested_interrupt:
interrupt_handler_instr.append("csrr x%0d, 0x%0x" % (cfg.gpr[0].value, scratch.value))
interrupt_handler_instr.append("bgtz x%0d, 1f" % (cfg.gpr[0].value))
interrupt_handler_instr.append("csrwi 0x%0x, 0x1" % (scratch.value))
if(status == privileged_reg_t.MSTATUS):
if status == privileged_reg_t.MSTATUS:
interrupt_handler_instr.append("csrsi 0x%0x, 0x%0x" % (status.value, 8))
elif(status == privileged_reg_t.SSTATUS):
elif status == privileged_reg_t.SSTATUS:
interrupt_handler_instr.append("csrsi 0x%0x, 0x%0x" % (status.value, 2))
elif(status == privileged_reg_t.USTATUS):
elif status == privileged_reg_t.USTATUS:
interrupt_handler_instr.append("csrsi 0x%0x, 0x%0x" % (status.value, 1))
else:
logging.critical("Unsupported status %0s" % (status.value))
logging.critical("Unsupported status {}".format(status.name))
sys.exit(1)
interrupt_handler_instr.append("1: csrwi 0x%0x,0" % (scratch.value))
@ -674,7 +673,7 @@ class riscv_asm_program_gen:
cfg.sp, cfg.tp, interrupt_handler_instr)
interrupt_handler_instr.append("%0sret;" % (mode_prefix))
if(rcs.SATP_MODE != "BARE"):
if rcs.SATP_MODE != satp_mode_t.BARE:
self.instr_stream.append(".align 12")
else:
self.instr_stream.append(".align 2")
@ -686,7 +685,7 @@ class riscv_asm_program_gen:
pass
def gen_section(self, label, instr):
if(label != ""):
if label != "":
string = pkg_ins.format_string("{}:".format(label), pkg_ins.LABEL_STR_LEN)
self.instr_stream.append(string)
for items in instr:
@ -737,12 +736,12 @@ class riscv_asm_program_gen:
min_insert_cnt = 0, kernel_mode = 0, instr_stream = []):
instr_insert_cnt = 0
idx = 0
if(cfg.no_directed_instr):
if cfg.no_directed_instr:
return
for instr_stream_name in self.directed_instr_stream_ratio:
instr_insert_cnt = int(original_instr_cnt *
self.directed_instr_stream_ratio[instr_stream_name] // 1000)
if(instr_insert_cnt <= min_insert_cnt):
if instr_insert_cnt <= min_insert_cnt:
instr_insert_cnt = min_insert_cnt
logging.info("Insert directed instr stream %0s %0d/%0d times",
instr_stream_name, instr_insert_cnt, original_instr_cnt)
@ -750,11 +749,11 @@ class riscv_asm_program_gen:
name = "{}_{}".format(instr_stream_name, i)
object_h = factory(instr_stream_name)
object_h.name = name
if(object_h is None):
if not object_h:
logging.critical("Cannot create instr stream %0s", name)
sys.exit(1)
new_instr_stream = copy.deepcopy(object_h)
if(new_instr_stream):
if new_instr_stream:
new_instr_stream.hart = hart
new_instr_stream.label = "{}_{}".format(label, idx)
new_instr_stream.kernel_mode = kernel_mode

View file

@ -9,18 +9,19 @@ 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.
"""
from pygen_src.riscv_instr_pkg import imm_t
from pygen_src.isa.riscv_instr import riscv_instr
from pygen_src.isa.riscv_compressed_instr import riscv_compressed_instr
from pygen_src.isa.riscv_floating_point_instr import riscv_floating_point_instr
from pygen_src.isa.riscv_b_instr import riscv_b_instr
from pygen_src.isa.riscv_amo_instr import riscv_amo_instr
# Regular integer instruction
def DEFINE_INSTR(instr_n, instr_format, instr_category,
instr_group, imm_tp=imm_t.IMM, g=globals()):
instr_group, imm_tp = imm_t.IMM, g = globals()):
class_name = "riscv_{}_instr".format(instr_n.name)
def __init__(self):
@ -42,7 +43,7 @@ def DEFINE_INSTR(instr_n, instr_format, instr_category,
# Compressed instruction
def DEFINE_C_INSTR(instr_n, instr_format, instr_category,
instr_group, imm_tp=imm_t.IMM, g=globals()):
instr_group, imm_tp = imm_t.IMM, g = globals()):
class_name = "riscv_{}_instr".format(instr_n.name)
def __init__(self):
@ -63,7 +64,7 @@ def DEFINE_C_INSTR(instr_n, instr_format, instr_category,
# Floating point instruction
def DEFINE_FP_INSTR(instr_n, instr_format, instr_category,
instr_group, imm_tp=imm_t.IMM, g=globals()):
instr_group, imm_tp = imm_t.IMM, g = globals()):
class_name = "riscv_{}_instr".format(instr_n.name)
def __init__(self):
@ -84,7 +85,7 @@ def DEFINE_FP_INSTR(instr_n, instr_format, instr_category,
# Floating point compressed instruction
def DEFINE_FC_INSTR(instr_n, instr_format, instr_category,
instr_group, imm_tp=imm_t.IMM, g=globals()):
instr_group, imm_tp = imm_t.IMM, g = globals()):
class_name = "riscv_{}_instr".format(instr_n.name)
def __init__(self):
@ -103,6 +104,48 @@ def DEFINE_FC_INSTR(instr_n, instr_format, instr_category,
g[class_name] = NewClass
# B-extension instruction
def DEFINE_B_INSTR(instr_n, instr_format, instr_category,
instr_group, imm_tp = imm_t.IMM, g = globals()):
class_name = "riscv_{}_instr".format(instr_n.name)
def __init__(self):
riscv_b_instr.__init__(self)
self.instr_name = instr_n
self.format = instr_format
self.category = instr_category
self.group = instr_group
self.imm_type = imm_tp
self.set_imm_len()
self.set_rand_mode()
NewClass = type(class_name, (riscv_b_instr,), {
"__init__": __init__,
"valid": riscv_b_instr.register(instr_n, instr_group)
})
g[class_name] = NewClass
# A-extension instruction
def DEFINE_AMO_INSTR(instr_n, instr_format, instr_category,
instr_group, imm_tp = imm_t.IMM, g = globals()):
class_name = "riscv_{}_instr".format(instr_n.name)
def __init__(self):
riscv_amo_instr.__init__(self)
self.instr_name = instr_n
self.format = instr_format
self.category = instr_category
self.group = instr_group
self.imm_type = imm_tp
self.set_imm_len()
self.set_rand_mode()
NewClass = type(class_name, (riscv_amo_instr,), {
"__init__": __init__,
"valid": riscv_amo_instr.register(instr_n, instr_group)
})
g[class_name] = NewClass
'''
TODO
@vsc.constraint

View file

@ -45,6 +45,45 @@ class riscv_directed_instr_stream(riscv_rand_instr_stream):
self.instr_list[0].has_label = 1
@vsc.randobj
class riscv_mem_access_stream(riscv_directed_instr_stream):
def __init__(self):
super().__init__()
self.max_data_page_id = vsc.int32_t()
self.load_store_shared_memory = 0
self.data_page = {}
def pre_randomize(self):
if self.load_store_shared_memory:
self.data_page = cfg.amo_region
elif self.kernel_mode:
self.data_page = cfg.s_mem_region
else:
self.data_page = cfg.mem_region
self.max_data_page_id = len(self.data_page)
def add_rs1_init_la_instr(self, gpr, idx, base = 0):
la_instr = riscv_pseudo_instr()
la_instr.pseudo_instr_name = riscv_pseudo_instr_name_t.LA
la_instr.rd = gpr
if self.load_store_shared_memory:
la_instr.imm_str = "{}+{}".format(cfg.amo_region[idx]['name'], base)
elif self.kernel_mode:
la_instr.imm_str = "{}{}+{}".format(pkg_ins.hart_prefix(self.hart),
cfg.s_mem_region[idx]['name'], base)
else:
la_instr.imm_str = "{}{}+{}".format(pkg_ins.hart_prefix(self.hart),
cfg.mem_region[idx]['name'], base)
self.instr_list.insert(0, la_instr)
def add_mixed_instr(self, instr_cnt):
self.setup_allowed_instr(1, 1)
for i in range(instr_cnt):
instr = riscv_instr()
instr = self.randomize_instr(instr)
self.insert_instr(instr)
@vsc.randobj
class riscv_jal_instr(riscv_rand_instr_stream):
def __init__(self):
@ -73,7 +112,7 @@ class riscv_jal_instr(riscv_rand_instr_stream):
jal.append(riscv_instr_name_t.C_J)
if rcs.XLEN == 32:
jal.append(riscv_instr_name_t.C_JAL)
self.jump_start = riscv_instr.get_instr(riscv_instr_name_t.JAL.name)
self.jump_start = riscv_instr.get_instr(riscv_instr_name_t.JAL)
with self.jump_start.randomize_with() as it:
self.jump_start.rd == RA
self.jump_start.imm_str = "{}f".format(order[0])
@ -83,7 +122,7 @@ class riscv_jal_instr(riscv_rand_instr_stream):
self.jump_end = self.randomize_instr(self.jump_end)
self.jump_end.label = "{}".format(self.num_of_jump_instr)
for i in range(self.num_of_jump_instr):
self.jump[i] = riscv_instr.get_rand_instr(include_instr = [jal[0].name])
self.jump[i] = riscv_instr.get_rand_instr(include_instr = [jal[0]])
with self.jump[i].randomize_with() as it:
if self.jump[i].has_rd:
vsc.dist(self.jump[i].rd, [vsc.weight(riscv_reg_t.RA, 5), vsc.weight(
@ -119,23 +158,24 @@ class int_numeric_e(IntEnum):
class riscv_int_numeric_corner_stream(riscv_directed_instr_stream):
def __init__(self):
super().__init__()
self.num_of_avail_regs = 10
self.num_of_avail_regs = vsc.uint32_t(10)
self.num_of_instr = vsc.rand_uint8_t()
self.init_val = vsc.rand_list_t(vsc.rand_bit_t(rcs.XLEN - 1), sz = 10)
self.init_val_type = vsc.rand_list_t(vsc.enum_t(int_numeric_e), sz =10)
self.init_val = vsc.randsz_list_t(vsc.rand_bit_t(rcs.XLEN - 1))
self.init_val_type = vsc.randsz_list_t(vsc.enum_t(int_numeric_e))
self.init_instr = []
@vsc.constraint
def init_val_c(self):
# TO DO
# solve init_val_type before init_val;
self.init_val_type.size == self.num_of_avail_regs
self.init_val.size == self.num_of_avail_regs
# TODO
vsc.solve_order(self.init_val_type, self.init_val)
self.init_val_type.size == 10 # self.num_of_avail_regs
self.init_val.size == 10 # self.num_of_avail_regs
self.num_of_instr in vsc.rangelist(vsc.rng(15, 30))
@vsc.constraint
def avail_regs_c(self):
self.avail_regs.size == self.num_of_avail_regs
# TODO
self.avail_regs.size == 10 # self.num_of_avail_regs
vsc.unique(self.avail_regs)
with vsc.foreach(self.avail_regs, idx = True) as i:
self.avail_regs[i].not_inside(cfg.reserved_regs)
@ -177,8 +217,8 @@ class riscv_push_stack_instr(riscv_rand_instr_stream):
self.num_of_redundant_instr = 0
self.push_stack_instr = []
self.saved_regs = []
self.branch_instr = riscv_instr()
self.enable_branch = vsc.rand_bit_t()
self.branch_instr = vsc.attr(riscv_instr())
self.enable_branch = vsc.rand_bit_t(1)
self.push_start_label = ''
def init(self):
@ -203,7 +243,7 @@ class riscv_push_stack_instr(riscv_rand_instr_stream):
with self.push_stack_instr[0].randomize_with() as it:
self.push_stack_instr[0].rd == cfg.sp
self.push_stack_instr[0].rs1 == cfg.sp
self.push_stack_instr[0].imm == (~cfg.stack_len) + 1
self.push_stack_instr[0].imm == (~cfg.stack_len + 1)
self.push_stack_instr[0].imm_str = '-{}'.format(self.stack_len)
for i in range(len(self.saved_regs)):
@ -222,14 +262,15 @@ class riscv_push_stack_instr(riscv_rand_instr_stream):
self.push_stack_instr[i + 1].process_load_store = 0
if allow_branch:
# TODO `DV_CHECK_STD_RANDOMIZE_FATAL(enable_branch)
# TODO
# vsc.randomize(self.enable_branch)
pass
else:
self.enable_branch = 0
if self.enable_branch:
self.branch_instr = \
riscv_instr.get_rand_instr(include_category=[riscv_instr_name_t.BRANCH.name])
# `DV_CHECK_STD_RANDOMIZE_FATAL(branch_instr)
self.branch_instr.randomize()
self.branch_instr.imm_str = self.push_start_label
self.branch_instr.brach_assigned = 1
self.push_stack_instr[0].label = self.push_start_label
@ -250,7 +291,7 @@ class riscv_pop_stack_instr(riscv_rand_instr_stream):
self.stack_len = 0
self.num_of_reg_to_save = 0
self.num_of_redundant_instr = 0
self.pop_stack_instr = []
self.pop_stack_instr = vsc.list_t(vsc.attr(riscv_instr()))
self.saved_regs = []
def init(self):
@ -286,12 +327,14 @@ class riscv_pop_stack_instr(riscv_rand_instr_stream):
self.imm == 8 * (i + 1)
self.pop_stack_instr[i].process_load_store = 0
# addi sp,sp,imm
''' TODO `DV_CHECK_RANDOMIZE_WITH_FATAL(pop_stack_instr[num_of_reg_to_save],
rd == cfg.sp; rs1 == cfg.sp; imm == stack_len;) '''
with self.pop_stack_instr[self.num_of_reg_to_save].randomize_with() as it:
self.rd == cfg.sp
self.rs1 == cfg.sp
self.imm == self.stack_len
self.pop_stack_instr[self.num_of_reg_to_save] = riscv_instr.get_instr(
riscv_instr_name_t.ADDI.name)
self.pop_stack_instr[self.num_of_reg_to_save].imm_str = pkg_ins.format_string(
'{}', self.stack_len)
'{}'.format(self.stack_len))
self.mix_instr_stream(self.pop_stack_instr)
for i in range(len(self.instr_list)):
self.instr_list[i].atomic = 1

View file

@ -19,19 +19,21 @@ import vsc
from importlib import import_module
from pygen_src.riscv_instr_pkg import (mtvec_mode_t, f_rounding_mode_t,
riscv_reg_t, privileged_mode_t,
riscv_instr_group_t, data_pattern_t)
riscv_instr_group_t, data_pattern_t,
riscv_instr_category_t, satp_mode_t)
@vsc.randobj
class riscv_instr_gen_config:
def __init__(self):
# TODO Support for command line argument
self.main_program_instr_cnt = 100 # count of main_prog
self.main_program_instr_cnt = vsc.rand_int32_t() # count of main_prog
self.sub_program_instr_cnt = [] # count of sub_prog
self.debug_program_instr_cnt = 0 # count of debug_rom
self.debug_sub_program_instr_cnt = [] # count of debug sub_progrms
self.max_directed_instr_stream_seq = 20
self.data_page_pattern = vsc.rand_enum_t(data_pattern_t)
self.init_delegation()
self.argv = self.parse_args()
self.args_dict = vars(self.argv)
@ -65,13 +67,7 @@ class riscv_instr_gen_config:
self.fcsr_rm = vsc.rand_enum_t(f_rounding_mode_t)
self.enable_sfence = vsc.rand_bit_t(1)
self.gpr = []
# Helper fields for gpr
self.gpr0 = vsc.rand_enum_t(riscv_reg_t)
self.gpr1 = vsc.rand_enum_t(riscv_reg_t)
self.gpr2 = vsc.rand_enum_t(riscv_reg_t)
self.gpr3 = vsc.rand_enum_t(riscv_reg_t)
self.gpr = vsc.rand_list_t(vsc.enum_t(riscv_reg_t), sz=4)
self.scratch_reg = vsc.rand_enum_t(riscv_reg_t)
self.pmp_reg = vsc.rand_enum_t(riscv_reg_t)
@ -179,9 +175,15 @@ class riscv_instr_gen_config:
self.march_isa = self.argv.march_isa
if len(self.march_isa) != 0:
rcs.supported_isa = self.march_isa
if "RV32C" not in rcs.supported_isa:
rcs.supported_isa.append(self.march_isa)
if riscv_instr_group_t.RV32C not in rcs.supported_isa:
self.disable_compressed_instr = 1
self.setup_instr_distribution()
self.get_invalid_priv_lvl_csr()
@vsc.constraint
def default_c(self):
self.main_program_instr_cnt in vsc.rangelist(vsc.rng(10, self.instr_cnt))
@vsc.constraint
def sp_tp_c(self):
@ -189,21 +191,16 @@ class riscv_instr_gen_config:
self.sp == riscv_reg_t.SP
self.sp != self.tp
self.sp.not_inside(vsc.rangelist(riscv_reg_t.GP,
riscv_reg_t.RA, riscv_reg_t.ZERO))
riscv_reg_t.RA, riscv_reg_t.ZERO))
self.tp.not_inside(vsc.rangelist(riscv_reg_t.GP,
riscv_reg_t.RA, riscv_reg_t.ZERO))
riscv_reg_t.RA, riscv_reg_t.ZERO))
@vsc.constraint
def gpr_c(self):
self.gpr0.not_inside(vsc.rangelist(self.sp, self.tp, self.scratch_reg, self.pmp_reg,
riscv_reg_t.ZERO, riscv_reg_t.RA, riscv_reg_t.GP))
self.gpr1.not_inside(vsc.rangelist(self.sp, self.tp, self.scratch_reg, self.pmp_reg,
riscv_reg_t.ZERO, riscv_reg_t.RA, riscv_reg_t.GP))
self.gpr2.not_inside(vsc.rangelist(self.sp, self.tp, self.scratch_reg, self.pmp_reg,
riscv_reg_t.ZERO, riscv_reg_t.RA, riscv_reg_t.GP))
self.gpr3.not_inside(vsc.rangelist(self.sp, self.tp, self.scratch_reg, self.pmp_reg,
riscv_reg_t.ZERO, riscv_reg_t.RA, riscv_reg_t.GP))
vsc.unique(self.gpr0, self.gpr1, self.gpr2, self.gpr3)
with vsc.foreach(self.gpr, idx = True) as i:
self.gpr[i].not_inside(vsc.rangelist(self.sp, self.tp, self.scratch_reg, self.pmp_reg,
riscv_reg_t.ZERO, riscv_reg_t.RA, riscv_reg_t.GP))
vsc.unique(self.gpr)
@vsc.constraint
def ra_c(self):
@ -214,21 +211,21 @@ class riscv_instr_gen_config:
@vsc.constraint
def reserve_scratch_reg_c(self):
self.scratch_reg.not_inside(vsc.rangelist(riscv_reg_t.ZERO, self.sp,
self.tp, self.ra, riscv_reg_t.GP))
self.tp, self.ra, riscv_reg_t.GP))
@vsc.constraint
def mtvec_c(self):
self.mtvec_mode.inside(vsc.rangelist(mtvec_mode_t.DIRECT, mtvec_mode_t.VECTORED))
if(self.mtvec_mode == mtvec_mode_t.DIRECT):
with vsc.if_then(self.mtvec_mode == mtvec_mode_t.DIRECT):
vsc.soft(self.tvec_alignment == 2)
else:
vsc.soft(self.tvec_alignment == (rcs.XLEN * 4) / 8)
with vsc.else_then():
vsc.soft(self.tvec_alignment == (rcs.XLEN * 4) // 8)
@vsc.constraint
def floating_point_c(self):
if self.enable_floating_point:
with vsc.if_then(self.enable_floating_point):
self.mstatus_fs == 1
else:
with vsc.else_then():
self.mstatus_fs == 0
@vsc.constraint
@ -237,7 +234,7 @@ class riscv_instr_gen_config:
self.mstatus_mprv == 1
else:
self.mstatus_mprv == 0
if rcs.SATP_MODE == "BARE":
if rcs.SATP_MODE == satp_mode_t.BARE:
self.mstatus_mxr == 0
self.mstatus_sum == 0
self.mstatus_tvm == 0
@ -247,15 +244,18 @@ class riscv_instr_gen_config:
support_128b = 0
# check the valid isa support
for x in rcs.supported_isa:
if x in ["RV64I", "RV64M", "RV64A", "RV64F", "RV64D", "RV64C", "RV64B"]:
for group in rcs.supported_isa:
if group in [riscv_instr_group_t.RV64I, riscv_instr_group_t.RV64M,
riscv_instr_group_t.RV64A, riscv_instr_group_t.RV64F,
riscv_instr_group_t.RV64D, riscv_instr_group_t.RV64C,
riscv_instr_group_t.RV64B]:
support_64b = 1
logging.info("support_64b = {}".format(support_64b))
logging.debug("Supported ISA = {}".format(x))
elif x in ["RV128I", "RV128C"]:
logging.debug("Supported ISA = {}".format(group.name))
elif group in [riscv_instr_group_t.RV128I, riscv_instr_group_t.RV128C]:
support_128b = 1
logging.info("support_128b = {}".format(support_128b))
logging.debug("Supported ISA = {}".format(x))
logging.debug("Supported ISA = {}".format(group.name))
if support_128b and rcs.XLEN != 128:
logging.critical("XLEN should be set to 128 based on \
@ -275,43 +275,41 @@ class riscv_instr_gen_config:
logging.info("XLEN Value = {}".format(rcs.XLEN))
sys.exit("XLEN is not equal to 32, set it Accordingly!")
if not(support_128b or support_64b) and not(rcs.SATP_MODE in ['SV32', "BARE"]):
logging.critical("SATP mode {} is not supported for RV32G ISA".format(rcs.SATP_MODE))
if not(support_128b or support_64b) and \
not(rcs.SATP_MODE in [satp_mode_t.SV32, satp_mode_t.BARE]):
logging.critical("SATP mode {} is not supported for RV32G ISA"
.format(rcs.SATP_MODE.name))
sys.exit("Supported SATP mode is not provided")
# TODO
def setup_instr_distribution(self):
if self.dist_control_mode:
category_iter = iter([x for x in riscv_instr_category_t.__members__])
category = riscv_instr_category_t(0)
while True:
opts = "dist_{}".format(category.name)
opts = opts.lower()
if self.args_dict[opts]:
self.category_dist[category] = self.args_dict[opts]
else:
self.category_dist[category] = 10
logging.info("Set dist[{}] = {}".format(category, self.category_dist[category]))
category = next(category_iter)
if category != riscv_instr_category_t(0):
break
# TODO
def init_delegation(self):
pass
def init_delegation(self):
for i in self.mode_exp_lst:
if i == self.mode_exp_lst[0]:
continue
self.m_mode_exception_delegation[i] = 0
self.s_mode_exception_delegation[i] = 0
for j in self.mode_intrpt_lst:
if j == self.mode_intrpt_lst[0]:
continue
self.m_mode_interrupt_delegation[j] = 0
self.s_mode_interrupt_delegation[j] = 0
def pre_randomize(self):
# Clearing the contents of self.gpr after each randomization.
# As it is being extended in post_randomize function.
self.gpr.clear()
for x in rcs.supported_privileged_mode:
if x == privileged_mode_t.SUPERVISOR_MODE:
for mode in rcs.supported_privileged_mode:
if mode == privileged_mode_t.SUPERVISOR_MODE:
self.support_supervisor_mode = 1
def get_non_reserved_gpr(self):
pass
def post_randomize(self):
self.reserved_regs = []
# Temporary fix for gpr_c constraint.
self.gpr.extend((self.gpr0, self.gpr1, self.gpr2, self.gpr3))
self.reserved_regs.append(self.tp)
self.reserved_regs.append(self.sp)
self.reserved_regs.append(self.scratch_reg)
@ -328,36 +326,26 @@ class riscv_instr_gen_config:
invalid_lvl = []
# Debug CSRs are inaccessible from all but Debug Mode
# and we cannot boot into Debug Mode.
invalid_lvl.append('D')
# TODO Need to change the logic once the constraints are up.
for mode in self.init_privileged_mode:
if mode == privileged_mode_t.MACHINE_MODE:
continue
if mode == privileged_mode_t.SUPERVISOR_MODE:
invalid_lvl.append('M')
logging.info("supr_mode---")
logging.debug(invalid_lvl)
elif mode == privileged_mode_t.USER_MODE:
invalid_lvl.append('S')
invalid_lvl.append('M')
logging.info("usr_mode---")
logging.debug(invalid_lvl)
else:
logging.critical("Unsupported initialization privilege mode")
invalid_lvl.append("D")
if self.init_privileged_mode == privileged_mode_t.MACHINE_MODE:
pass
elif self.init_privileged_mode == privileged_mode_t.SUPERVISOR_MODE:
invalid_lvl.append("M")
logging.info("supr_mode---")
logging.debug(invalid_lvl)
elif self.init_privileged_mode == privileged_mode_t.USER_MODE:
invalid_lvl.append("S")
invalid_lvl.append("M")
logging.info("usr_mode---")
logging.debug(invalid_lvl)
else:
logging.critical("Unsupported initialization privilege mode")
sys.exit(1)
# implemented_csr from riscv_core_setting.py
for x in rcs.implemented_csr:
if x[0] in invalid_lvl:
self.invalid_priv_mode_csrs.append(x)
# This function calls all the above defined function which should
# be called in init function as per SV logic.This function as to be
# called after every instance of the gen_config handle
def func_call_init(self):
self.init_delegation()
# self.setup_instr_distribution() # TODO
self.get_invalid_priv_lvl_csr()
for csr in rcs.implemented_csr:
if csr in invalid_lvl:
self.invalid_priv_mode_csrs.append(csr)
def parse_args(self):
parse = argparse.ArgumentParser()

View file

@ -1455,7 +1455,7 @@ class riscv_instr_pkg:
indent = LABEL_STR_LEN * " "
def hart_prefix(self, hart=0):
if (rcs.NUM_HARTS <= 1):
if rcs.NUM_HARTS <= 1:
return ""
else:
return f"h{hart}_"
@ -1481,11 +1481,11 @@ class riscv_instr_pkg:
def push_gpr_to_kernel_stack(self, status, scratch, mprv, sp, tp, instr):
store_instr = ''
if(rcs.XLEN == 32):
if rcs.XLEN == 32:
store_instr = "sw"
else:
store_instr = "sd"
if (scratch.name in rcs.implemented_csr):
if scratch in rcs.implemented_csr:
# Use kernal stack for handling exceptions. Save the user mode stack
# pointer to the scratch register
instr.append(pkg_ins.format_string(
@ -1495,10 +1495,10 @@ class riscv_instr_pkg:
# If MPRV is set and MPP is S/U mode, it means the address translation and
# memory protection for load/store instruction is the same as the mode indicated
# by MPP. In this case, we need to use the virtual address to access the kernel stack.
if((status.name == "MSTATUS") and (rcs.SATP_MODE != "BARE")):
if(status.name == privileged_reg_t.MSTATUS and rcs.SATP_MODE != satp_mode_t.BARE):
# We temporarily use tp to check mstatus to avoid changing other GPR. The value
# of sp has been saved to xScratch and can be restored later.
if(mprv):
if mprv:
instr.append(pkg_ins.format_string(
"csrr x{}, 0x{} // MSTATUS".format(tp, status.value)))
instr.append(pkg_ins.format_string(
@ -1526,7 +1526,7 @@ class riscv_instr_pkg:
def pop_gpr_from_kernel_stack(self, status, scratch, mprv, sp, tp, instr):
load_instr = ''
if(rcs.XLEN == 32):
if rcs.XLEN == 32:
load_instr = "lw"
else:
load_instr = "ld"
@ -1537,7 +1537,7 @@ class riscv_instr_pkg:
# Restore kernel stack pointer
instr.append(pkg_ins.format_string(
"addi x{}, x{}, {}".format(sp, sp, int(31 * (rcs.XLEN / 8)))))
if (scratch in rcs.implemented_csr):
if scratch in rcs.implemented_csr:
# Move SP to TP
instr.append(pkg_ins.format_string("add x{}, x{}, zero".format(tp, sp)))
# Restore user mode stack pointer

View file

@ -21,7 +21,7 @@ from collections import defaultdict
from pygen_src.riscv_instr_stream import riscv_rand_instr_stream
from pygen_src.riscv_instr_gen_config import cfg
from pygen_src.riscv_instr_pkg import (pkg_ins, riscv_instr_name_t, riscv_reg_t,
riscv_instr_category_t)
riscv_instr_category_t)
from pygen_src.riscv_directed_instr_lib import riscv_pop_stack_instr, riscv_push_stack_instr
rcs = import_module("pygen_src.target." + cfg.argv.target + ".riscv_core_setting")
@ -35,7 +35,7 @@ class riscv_instr_sequence:
self.is_debug_program = 0
self.label_name = ""
self.instr_string_list = [] # Save the instruction list
self.program_stack_len = 0 # Stack space allocated for this program
self.program_stack_len = vsc.int32_t(0) # Stack space allocated for this program
self.directed_instr = [] # List of all directed instruction stream
self.illegal_instr_pct = 0 # Percentage of illegal instructions
self.hint_instr_pct = 0 # Percentage of hint instructions
@ -54,9 +54,21 @@ class riscv_instr_sequence:
self.gen_stack_enter_instr()
self.gen_stack_exit_instr()
# TODO
def gen_stack_enter_instr(self):
pass
allow_branch = 0 if (self.illegal_instr_pct > 0 or self.hint_instr_pct > 0) else 1
allow_branch &= not cfg.no_branch_jump
try:
with vsc.randomize_with(self.program_stack_len):
self.program_stack_len in vsc.rangelist(vsc.rng(cfg.min_stack_len_per_program,
cfg.max_stack_len_per_program))
self.program_stack_len % (rcs.XLEN // 8) == 0
except Exception:
logging.critical("Cannot randomize program_stack_len")
sys.exit(1)
self.instr_stack_enter.push_start_label = self.label_name + "_stack_p"
self.instr_stack_enter.gen_push_stack_instr(self.program_stack_len,
allow_branch = allow_branch)
self.instr_stream.instr_list.extend((self.instr_stack_enter.instr_list))
# Recover the saved GPR from the stack
# Advance the stack pointer(SP) to release the allocated stack space.
@ -151,7 +163,6 @@ class riscv_instr_sequence:
logging.info("Processing branch instruction[%0d]:%0s # %0d -> %0d", j,
self.instr_stream.instr_list[j].convert2asm(),
self.instr_stream.instr_list[j].idx, branch_target_label)
logging.info("Branch", branch_target_label)
self.instr_stream.instr_list[j].imm_str = "{}f".format(branch_target_label)
self.instr_stream.instr_list[j].branch_assigned = 1
branch_target[branch_target_label] = 1
@ -166,7 +177,20 @@ class riscv_instr_sequence:
logging.info("Finished post-processing instructions")
def insert_jump_instr(self):
pass # TODO
# TODO riscv_jump_instr class implementation
"""
jump_instr = riscv_jump_instr()
jump_instr.target_program_label = target_label
if(not self.is_main_program):
jump_instr.stack_exit_instr = self.instr_stack_exit.pop_stack_instr
jump_instr.label = self.label_name
jump_instr.idx = idx
jump_instr.use_jalr = self.is_main_program
jump_instr.randomize()
self.instr_stream.insert_instr_stream(jump_instr.instr_list)
logging.info("{} -> {}...done".format(jump_instr.jump.instr_name.name, target_label))
"""
pass
def generate_instr_stream(self, no_label = 0):
prefix = ''
@ -201,9 +225,14 @@ class riscv_instr_sequence:
string = ''
jump_instr = [riscv_instr_name_t.JALR]
rand_lsb = random.randrange(0, 1)
ra = vsc.enum_t(riscv_reg_t)
# TODO
# `DV_CHECK_STD_RANDOMIZE_WITH_FATAL(ra,!(ra inside {cfg.reserved_regs}) ra != ZERO)
ra = vsc.rand_enum_t(riscv_reg_t)
try:
with vsc.randomize_with(ra):
ra.not_inside(vsc.rangelist(cfg.reserved_regs))
ra != riscv_reg_t.ZERO
except Exception:
logging.critical("Cannot randomize ra")
sys.exit(1)
string = (prefix + pkg_ins.format_string("{}addi x{} x{} {}".format(ra.name,
cfg.ra.name, rand_lsb)))
self.instr_string_list.append(string)

View file

@ -34,7 +34,7 @@ class riscv_instr_stream:
self.instr_cnt = 0
self.label = ""
# User can specify a small group of available registers to generate various hazard condition
self.avail_regs = vsc.rand_list_t(vsc.enum_t(riscv_reg_t), sz = 10)
self.avail_regs = vsc.randsz_list_t(vsc.enum_t(riscv_reg_t))
# Some additional reserved registers that should not be used as rd register
# by this instruction stream
self.reserved_rd = vsc.list_t(vsc.enum_t(riscv_reg_t))
@ -165,6 +165,10 @@ class riscv_rand_instr_stream(riscv_instr_stream):
self.allowed_instr = []
self.category_dist = []
@vsc.constraint
def avail_reg_c(self):
self.avail_regs.size == 10
def create_instr_instance(self):
for i in range(self.instr_cnt):
self.instr_list.append(None)
@ -181,9 +185,19 @@ class riscv_rand_instr_stream(riscv_instr_stream):
riscv_instr.instr_category[riscv_instr_category_t.STORE.name])
self.setup_instruction_dist(no_branch, no_load_store)
# TODO
def randomize_avail_regs(self):
pass
if self.avail_regs.size > 0:
try:
with vsc.randomize_with(self.avail_regs):
vsc.unique(self.avail_regs)
self.avail_regs[0].inside(vsc.rangelist(vsc.rng(riscv_reg_t.S0,
riscv_reg_t.A5)))
with vsc.foreach(self.avail_regs, idx = True) as i:
self.avail_regs[i].not_inside(vsc.rangelist(cfg.reserved_regs,
self.reserved_rd))
except Exception:
logging.critical("Cannot randomize avail_regs")
sys.exit(1)
def setup_instruction_dist(self, no_branch = 0, no_load_store = 1):
if cfg.dist_control_mode:
@ -204,7 +218,7 @@ class riscv_rand_instr_stream(riscv_instr_stream):
if len(self.instr_list) == 0:
break
def randomize_instr(self, instr, is_in_debug = 0):
def randomize_instr(self, instr, is_in_debug = 0, disable_dist = 0, include_group = []):
exclude_instr = []
is_SP_in_reserved_rd = riscv_reg_t.SP in self.reserved_rd
is_SP_in_reserved_regs = riscv_reg_t.SP in cfg.reserved_regs
@ -225,27 +239,28 @@ class riscv_rand_instr_stream(riscv_instr_stream):
exclude_instr.extend([riscv_instr_name_t.EBREAK.name,
riscv_instr_name_t.C_EBREAK.name])
instr = riscv_instr.get_rand_instr(
include_instr = self.allowed_instr, exclude_instr = exclude_instr)
include_instr = self.allowed_instr, exclude_instr = exclude_instr,
include_group = include_group)
instr = self.randomize_gpr(instr)
return instr
def randomize_gpr(self, instr):
with instr.randomize_with() as it:
if self.avail_regs.size > 0:
if instr.has_rs1:
with vsc.if_then(self.avail_regs.size > 0):
with vsc.if_then(instr.has_rs1):
instr.rs1.inside(vsc.rangelist(self.avail_regs))
if instr.has_rs2:
with vsc.if_then(instr.has_rs2):
instr.rs2.inside(vsc.rangelist(self.avail_regs))
if instr.has_rd:
with vsc.if_then(instr.has_rd):
instr.rd.inside(vsc.rangelist(self.avail_regs))
with vsc.foreach(self.reserved_rd, idx = True) as i:
if instr.has_rd == 1:
with vsc.if_then(instr.has_rd):
instr.rd != self.reserved_rd[i]
if instr.format == riscv_instr_format_t.CB_FORMAT:
with vsc.if_then(instr.format == riscv_instr_format_t.CB_FORMAT):
instr.rs1 != self.reserved_rd[i]
with vsc.foreach(cfg.reserved_regs, idx = True) as i:
with vsc.if_then(instr.has_rd == 1):
with vsc.if_then(instr.has_rd):
instr.rd != cfg.reserved_regs[i]
with vsc.if_then(instr.format == riscv_instr_format_t.CB_FORMAT):
instr.rs1 != cfg.reserved_regs[i]

View file

@ -15,7 +15,8 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
import logging
import vsc
from importlib import import_module
from pygen_src.riscv_instr_pkg import pkg_ins, privileged_reg_t
from pygen_src.riscv_instr_pkg import (pkg_ins, privileged_reg_t,
privileged_mode_t, satp_mode_t)
from pygen_src.riscv_instr_gen_config import cfg
from pygen_src.riscv_privil_reg import riscv_privil_reg
rcs = import_module("pygen_src.target." + cfg.argv.target + ".riscv_core_setting")
@ -27,18 +28,22 @@ class riscv_privileged_common_seq():
self.hart = 0
self.mstatus = vsc.attr(riscv_privil_reg)
self.mie = vsc.attr(riscv_privil_reg)
self.sstatus = vsc.attr(riscv_privil_reg)
self.sie = vsc.attr(riscv_privil_reg)
self.ustatus = vsc.attr(riscv_privil_reg)
self.uie = vsc.attr(riscv_privil_reg)
def enter_privileged_mode(self, mode, instrs):
label = pkg_ins.format_string("{}init_{}:"
.format(pkg_ins.hart_prefix(self.hart), mode),
.format(pkg_ins.hart_prefix(self.hart), mode.name),
pkg_ins.LABEL_STR_LEN)
ret_instr = ["mret"]
regs = vsc.list_t(vsc.attr(riscv_privil_reg()))
label = label.lower()
self.setup_mmode_reg(mode, regs)
if mode == "SUPERVISOR_MODE":
if mode == privileged_mode_t.SUPERVISOR_MODE:
self.setup_smode_reg(mode, regs)
if mode == "USER_MODE":
if mode == privileged_mode_t.USER_MODE:
self.setup_umode_reg(mode, regs)
if cfg.virtual_addr_translation_on:
self.setup_satp(instrs)
@ -49,10 +54,58 @@ class riscv_privileged_common_seq():
instrs[i] = pkg_ins.indent + instrs[i]
instrs.insert(0, label)
# TODO
def setup_mmode_reg(self, mode, regs):
self.mstatus = riscv_privil_reg()
self.mstatus.init_reg(privileged_reg_t.MSTATUS)
self.mstatus_set_field(mode, regs)
self.mie_set_field(mode, regs)
def setup_smode_reg(self, mode, regs):
self.sstatus = riscv_privil_reg()
self.sstatus.init_reg(privileged_reg_t.SSTATUS)
self.sstatus.randomize()
self.sstatus_set_field(mode, regs)
self.sie_set_field(mode, regs)
def setup_umode_reg(self, mode, regs):
# For implementations that do not provide any U-mode CSRs, return immediately
if not rcs.support_umode_trap:
return
self.ustatus = riscv_privil_reg()
self.ustatus.init_reg(privileged_reg_t.USTATUS)
self.ustatus.randomize()
self.ustatus_set_field(mode, regs)
self.uie_set_field(mode, regs)
def gen_csr_instr(self, regs, instrs):
for i in range(len(regs)):
instrs.append("li x{}, {}".format(cfg.gpr[0].value, hex(regs[i].get_val())))
instrs.append("csrw {}, x{} # {}".format(hex(regs[i].reg_name.value),
cfg.gpr[0], regs[i].reg_name.name))
def setup_satp(self, instrs):
satp_ppn_mask = vsc.bit_t(rcs.XLEN)
if rcs.SATP_MODE == satp_mode_t.BARE:
return
satp = riscv_privil_reg()
satp.init_reg(privileged_reg_t.SATP)
satp.set_field("MODE", rcs.SATP_MODE)
li0_instr = "li x{}, {}".format(cfg.gpr[0], hex(satp.get_val()))
csrw_instr = "csrw {}, x{} // satp".format(hex(privileged_reg_t.SATP), cfg.gpr[0])
fld_name = satp.get_field_by_name("PPN")
satp_ppn_mask = hex((2**rcs.XLEN) - 1) >> (rcs.XLEN - fld_name.bit_width)
# Load the root page table physical address
la_instr = "la x{}, page_table_0".format(cfg.gpr[0])
# Right shift to get PPN at 4k granularity
srli_instr = "srli x{}, x{}, 12".format(cfg.gpr[0], cfg.gpr[0])
li1_instr = "li x{}, {}".format(cfg.gpr[1], hex(satp_ppn_mask))
and_instr = "and x{}, x{}, x{}".format(cfg.gpr[0], cfg.gpr[0], cfg.gpr[1])
# Set the PPN field for SATP
csrs_instr = "csrs {}, x{} // satp".format(hex(privileged_reg_t.SATP), cfg.gpr[0])
instrs.extend((li0_instr, csrw_instr, la_instr, srli_instr,
li1_instr, and_instr, csrs_instr))
def mstatus_set_field(self, mode, regs):
if cfg.randomize_csr:
self.mstatus.set_val(cfg.mstatus)
self.mstatus.set_field("MPRV", cfg.mstatus_mprv)
@ -62,11 +115,12 @@ class riscv_privileged_common_seq():
self.mstatus.set_field("TW", cfg.set_mstatus_tw)
self.mstatus.set_field("FS", cfg.mstatus_fs)
self.mstatus.set_field("VS", cfg.mstatus_vs)
if (not("SUPERVISOR_MODE" in rcs.supported_privileged_mode) and (rcs.XLEN != 32)):
if (not(privileged_mode_t.SUPERVISOR_MODE in rcs.supported_privileged_mode) and
(rcs.XLEN != 32)):
self.mstatus.set_field("SXL", 0)
elif rcs.XLEN == 64:
self.mstatus.set_field("SXL", 2)
if (not("USER_MODE" in rcs.supported_privileged_mode) and (rcs.XLEN != 32)):
if (not(privileged_mode_t.USER_MODE in rcs.supported_privileged_mode) and (rcs.XLEN != 32)):
self.mstatus.set_field("UXL", 0)
elif rcs.XLEN == 64:
self.mstatus.set_field("UXL", 2)
@ -74,7 +128,7 @@ class riscv_privileged_common_seq():
self.mstatus.set_field("SD", 0)
self.mstatus.set_field("UIE", 0)
# Set the previous privileged mode as the target mode
self.mstatus.set_field("MPP", 3) # TODO pass mode value as parameter
self.mstatus.set_field("MPP", mode.value)
self.mstatus.set_field("SPP", 0)
# Enable Interrupt
self.mstatus.set_field("MPIE", cfg.enable_interrupt)
@ -85,8 +139,33 @@ class riscv_privileged_common_seq():
self.mstatus.set_field("UIE", rcs.support_umode_trap)
logging.info("self.mstatus_val: {}".format(hex(self.mstatus.get_val())))
regs.append(self.mstatus)
def sstatus_set_field(self, mode, regs):
if cfg.randomize_csr:
self.sstatus.set_val(cfg.sstatus)
self.sstatus.set_field("SPIE", cfg.enable_interrupt)
self.sstatus.set_field("SIE", cfg.enable_interrupt)
self.sstatus.set_field("UPIE", cfg.enable_interrupt)
self.sstatus.set_field("UIE", rcs.support_umode_trap)
if rcs.XLEN == 64:
self.sstatus.set_field("UXL", 2)
self.sstatus.set_field("FS", cfg.mstatus_fs)
self.sstatus.set_field("XS", 0)
self.sstatus.set_field("SD", 0)
self.sstatus.set_field("UIE", 0)
self.sstatus.set_field("SPP", 0)
regs.append(self.sstatus)
def ustatus_set_field(self, mode, regs):
if cfg.randomize_csr:
self.ustatus.set_val(cfg.ustatus)
self.ustatus.set_field("UIE", cfg.enable_interrupt)
self.ustatus.set_field("UPIE", cfg.enable_interrupt)
regs.append(self.ustatus)
def mie_set_field(self, mode, regs):
# Enable external and timer interrupt
if "MIE" in rcs.implemented_csr:
if privileged_reg_t.MIE in rcs.implemented_csr:
self.mie = riscv_privil_reg()
self.mie.init_reg(privileged_reg_t.MIE)
if cfg.randomize_csr:
@ -102,20 +181,28 @@ class riscv_privileged_common_seq():
self.mie.set_field("UTIE", cfg.enable_interrupt & cfg.enable_timer_irq)
regs.append(self.mie)
# TODO
def setup_smode_reg(self, mode, regs):
pass
def sie_set_field(self, mode, regs):
# Enable external and timer interrupt
if privileged_reg_t.SIE in rcs.implemeted_csr:
self.sie = riscv_privil_reg()
self.sie.init_reg(privileged_reg_t.SIE)
if cfg.randomize_csr:
self.sie.set_val(cfg.sie)
self.sie.set_field("UEIE", cfg.enable_interrupt)
self.sie.set_field("SEIE", cfg.enable_interrupt)
self.sie.set_field("USIE", cfg.enable_interrupt)
self.sie.set_field("SSIE", cfg.enable_interrupt)
self.sie.set_field("STIE", cfg.enable_interrupt & cfg.enable_timer_irq)
self.sie.set_field("UTIE", cfg.enable_interrupt & cfg.enable_timer_irq)
regs.append(self.sie)
# TODO
def setup_umode_reg(self, mode, regs):
pass
# TODO
def setup_satp(self, instrs):
pass
def gen_csr_instr(self, regs, instrs):
for i in range(len(regs)):
instrs.append("li x{}, {}".format(cfg.gpr[0].value, hex(regs[i].get_val())))
instrs.append("csrw {}, x{} # {}".format(hex(regs[i].reg_name.value),
cfg.gpr[0], regs[i].reg_name.name))
def uie_set_field(self, mode, regs):
if privileged_reg_t.UIE in rcs.implemented_csr:
self.uie = riscv_privil_reg()
self.uie.init_reg(privileged_reg_t.UIE)
if cfg.randomize_csr:
self.uie.set_val(cfg.uie)
self.uie.set_field("UEIE", cfg.enable_interrupt)
self.uie.set_field("USIE", cfg.enable_interrupt)
self.uie.set_field("UTIE", cfg.enable_interrupt & cfg.enable_timer_irq)
regs.append(self.uie)

View file

@ -107,13 +107,14 @@ class riscv_reg:
logging.critical("Cannot match found field {}".format(fld_name))
sys.exit(1)
# TODO
def rand_field(self, fld_name):
pass
fld_hd = self.get_field_by_name(fld_name)
fld_hd.randomize()
# TODO
def set_field_rand_mode(self, fld_name, rand_on):
pass
fld_hd = self.get_field_by_name(fld_name)
with vsc.raw_mode():
fld_hd.rand_mode = bool(rand_on)
def reset(self):
for i in range((len(self.fld) - 1), -1, -1):

View file

@ -18,14 +18,18 @@ from tabulate import tabulate
from pygen_src.riscv_instr_gen_config import cfg
from pygen_src.riscv_directed_instr_lib import (riscv_directed_instr_stream,
riscv_int_numeric_corner_stream,
riscv_jal_instr)
riscv_jal_instr, riscv_mem_access_stream)
from pygen_src.riscv_amo_instr_lib import (riscv_lr_sc_instr_stream, riscv_amo_instr_stream)
def factory(obj_of):
objs = {
"riscv_directed_instr_stream": riscv_directed_instr_stream,
"riscv_int_numeric_corner_stream": riscv_int_numeric_corner_stream,
"riscv_jal_instr": riscv_jal_instr
"riscv_jal_instr": riscv_jal_instr,
"riscv_mem_access_stream": riscv_mem_access_stream,
"riscv_lr_sc_instr_stream": riscv_lr_sc_instr_stream,
"riscv_amo_instr_stream": riscv_amo_instr_stream
}
try:

View file

@ -10,18 +10,24 @@ 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.
"""
from pygen_src.riscv_instr_pkg import (privileged_reg_t, satp_mode_t,
riscv_instr_group_t, privileged_mode_t)
XLEN = 32
implemented_csr = ['MVENDORID', 'MARCHID', 'MIMPID', 'MHARTID', 'MSTATUS', 'MISA', 'MIE',
'MTVEC', 'MCOUNTEREN', 'MSCRATCH', 'MEPC', 'MCAUSE', 'MTVAL', 'MIP']
implemented_csr = [privileged_reg_t.MVENDORID, privileged_reg_t.MARCHID, privileged_reg_t.MIMPID,
privileged_reg_t.MHARTID, privileged_reg_t.MSTATUS,
privileged_reg_t.MISA, privileged_reg_t.MIE,
privileged_reg_t.MTVEC, privileged_reg_t.MCOUNTEREN, privileged_reg_t.MSCRATCH,
privileged_reg_t.MEPC, privileged_reg_t.MCAUSE,
privileged_reg_t.MTVAL, privileged_reg_t.MIP]
SATP_MODE = 'BARE'
SATP_MODE = satp_mode_t.BARE
supported_isa = ['RV32I']
supported_privileged_mode = ['MACHINE_MODE']
supported_isa = [riscv_instr_group_t.RV32I]
supported_privileged_mode = [privileged_mode_t.MACHINE_MODE]
NUM_HARTS = 1
support_pmp = 0

View file

@ -0,0 +1,80 @@
"""
Copyright 2020 Google LLC
Copyright 2020 PerfectVIPs Inc.
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.
"""
from pygen_src.riscv_instr_pkg import (privileged_reg_t, interrupt_cause_t,
exception_cause_t, satp_mode_t,
riscv_instr_group_t, privileged_mode_t,
mtvec_mode_t)
XLEN = 32
implemented_csr = [privileged_reg_t.MVENDORID, privileged_reg_t.MARCHID,
privileged_reg_t.MIMPID, privileged_reg_t.MHARTID,
privileged_reg_t.MSTATUS, privileged_reg_t.MISA, privileged_reg_t.MIE,
privileged_reg_t.MTVEC, privileged_reg_t.MCOUNTEREN, privileged_reg_t.MSCRATCH,
privileged_reg_t.MEPC, privileged_reg_t.MCAUSE,
privileged_reg_t.MTVAL, privileged_reg_t.MIP]
SATP_MODE = satp_mode_t.BARE
supported_isa = [riscv_instr_group_t.RV32I, riscv_instr_group_t.RV32M,
riscv_instr_group_t.RV32C, riscv_instr_group_t.RV32F,
riscv_instr_group_t.RV32FC, riscv_instr_group_t.RV32D,
riscv_instr_group_t.RV32DC, riscv_instr_group_t.RV32A]
supported_privileged_mode = [privileged_mode_t.MACHINE_MODE]
supported_interrupt_mode = [mtvec_mode_t.DIRECT, mtvec_mode_t.VECTORED]
max_interrupt_vector_num = 16
support_debug_mode = 0
NUM_HARTS = 1
support_pmp = 0
unsupported_instr = []
support_umode_trap = 0
support_sfence = 0
support_unaligned_load_store = 1
NUM_FLOAT_GPR = 32
NUM_GPR = 32
NUM_VEC_GPR = 32
VECTOR_EXTENSION_ENABLE = 0
VLEN = 512
ELEN = 32
SELEN = 0
MAX_MUL = 8
implemented_interrupt = [interrupt_cause_t.M_SOFTWARE_INTR,
interrupt_cause_t.M_TIMER_INTR,
interrupt_cause_t.M_EXTERNAL_INTR]
implemented_exception = [exception_cause_t.INSTRUCTION_ACCESS_FAULT,
exception_cause_t.ILLEGAL_INSTRUCTION,
exception_cause_t.BREAKPOINT,
exception_cause_t.LOAD_ADDRESS_MISALIGNED,
exception_cause_t.LOAD_ACCESS_FAULT,
exception_cause_t.ECALL_MMODE]

View file

@ -10,19 +10,29 @@ 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.
"""
from pygen_src.riscv_instr_pkg import (privileged_reg_t, interrupt_cause_t,
exception_cause_t, satp_mode_t,
riscv_instr_group_t, privileged_mode_t,
mtvec_mode_t)
XLEN = 32
implemented_csr = ['MVENDORID', 'MARCHID', 'MIMPID', 'MHARTID', 'MSTATUS', 'MISA', 'MIE',
'MTVEC', 'MCOUNTEREN', 'MSCRATCH', 'MEPC', 'MCAUSE', 'MTVAL', 'MIP']
implemented_csr = [privileged_reg_t.MVENDORID, privileged_reg_t.MARCHID, privileged_reg_t.MIMPID,
privileged_reg_t.MHARTID, privileged_reg_t.MSTATUS,
privileged_reg_t.MISA, privileged_reg_t.MIE,
privileged_reg_t.MTVEC, privileged_reg_t.MCOUNTEREN, privileged_reg_t.MSCRATCH,
privileged_reg_t.MEPC, privileged_reg_t.MCAUSE,
privileged_reg_t.MTVAL, privileged_reg_t.MIP]
SATP_MODE = 'BARE'
SATP_MODE = satp_mode_t.BARE
supported_isa = ['RV32I', 'RV32M', 'RV32C']
supported_isa = [riscv_instr_group_t.RV32I, riscv_instr_group_t.RV32M,
riscv_instr_group_t.RV32C]
supported_privileged_mode = ['MACHINE_MODE']
supported_privileged_mode = [privileged_mode_t.MACHINE_MODE]
supported_interrupt_mode = ['DIRECT', 'VECTORED']
supported_interrupt_mode = [mtvec_mode_t.DIRECT, mtvec_mode_t.VECTORED]
max_interrupt_vector_num = 16
@ -55,8 +65,12 @@ SELEN = 0
MAX_MUL = 8
implemented_interrupt = ['M_SOFTWARE_INTR', 'M_TIMER_INTR', 'M_EXTERNAL_INTR']
implemented_interrupt = [interrupt_cause_t.M_SOFTWARE_INTR,
interrupt_cause_t.M_TIMER_INTR,
interrupt_cause_t.M_EXTERNAL_INTR]
implemented_exception = ['INSTRUCTION_ACCESS_FAULT', 'ILLEGAL_INSTRUCTION',
'BREAKPOINT', 'LOAD_ADDRESS_MISALIGNED', 'LOAD_ACCESS_FAULT',
'ECALL_MMODE']
implemented_exception = [exception_cause_t.INSTRUCTION_ACCESS_FAULT,
exception_cause_t.ILLEGAL_INSTRUCTION,
exception_cause_t.BREAKPOINT, exception_cause_t.LOAD_ADDRESS_MISALIGNED,
exception_cause_t.LOAD_ACCESS_FAULT,
exception_cause_t.ECALL_MMODE]

View file

@ -0,0 +1,22 @@
# riscOVPsim configuration file converted from YAML
--variant RV32I
--override riscvOVPsim/cpu/add_Extensions=MCB
--override riscvOVPsim/cpu/misa_MXL=1
--override riscvOVPsim/cpu/misa_MXL_mask=0x0 # 0
--override riscvOVPsim/cpu/misa_Extensions_mask=0x0 # 0
--override riscvOVPsim/cpu/unaligned=T
--override riscvOVPsim/cpu/mtvec_mask=0x0 # 0
--override riscvOVPsim/cpu/user_version=2.3
--override riscvOVPsim/cpu/priv_version=1.11
--override riscvOVPsim/cpu/mvendorid=0
--override riscvOVPsim/cpu/marchid=0
--override riscvOVPsim/cpu/mimpid=0
--override riscvOVPsim/cpu/mhartid=0
--override riscvOVPsim/cpu/cycle_undefined=F
--override riscvOVPsim/cpu/instret_undefined=F
--override riscvOVPsim/cpu/time_undefined=T
--override riscvOVPsim/cpu/reset_address=0x80000000
--override riscvOVPsim/cpu/simulateexceptions=T
--override riscvOVPsim/cpu/defaultsemihost=F
--override riscvOVPsim/cpu/wfi_is_nop=T
--exitonsymbol _exit

View file

@ -0,0 +1,78 @@
"""
Copyright 2020 Google LLC
Copyright 2020 PerfectVIPs Inc.
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.
"""
from pygen_src.riscv_instr_pkg import (privileged_reg_t, interrupt_cause_t,
exception_cause_t, satp_mode_t,
riscv_instr_group_t, privileged_mode_t,
mtvec_mode_t)
XLEN = 32
implemented_csr = [privileged_reg_t.MVENDORID, privileged_reg_t.MARCHID,
privileged_reg_t.MIMPID, privileged_reg_t.MHARTID,
privileged_reg_t.MSTATUS, privileged_reg_t.MISA,
privileged_reg_t.MIE, privileged_reg_t.MTVEC,
privileged_reg_t.MCOUNTEREN, privileged_reg_t.MSCRATCH,
privileged_reg_t.MEPC, privileged_reg_t.MCAUSE,
privileged_reg_t.MTVAL, privileged_reg_t.MIP]
SATP_MODE = satp_mode_t.BARE
supported_isa = [riscv_instr_group_t.RV32I, riscv_instr_group_t.RV32M,
riscv_instr_group_t.RV32C, riscv_instr_group_t.RV32B]
supported_privileged_mode = [privileged_mode_t.MACHINE_MODE]
supported_interrupt_mode = [mtvec_mode_t.DIRECT, mtvec_mode_t.VECTORED]
max_interrupt_vector_num = 16
support_debug_mode = 0
NUM_HARTS = 1
support_pmp = 0
unsupported_instr = []
support_umode_trap = 0
support_sfence = 0
support_unaligned_load_store = 1
# GPR Setting
NUM_FLOAT_GPR = 32
NUM_GPR = 32
NUM_VEC_GPR = 32
VECTOR_EXTENSION_ENABLE = 0
VLEN = 512
ELEN = 32
SELEN = 8
MAX_LMUL = 8
implemented_interrupt = [interrupt_cause_t.M_SOFTWARE_INTR,
interrupt_cause_t.M_TIMER_INTR,
interrupt_cause_t.M_EXTERNAL_INTR]
implemented_exception = [exception_cause_t.INSTRUCTION_ACCESS_FAULT,
exception_cause_t.ILLEGAL_INSTRUCTION,
exception_cause_t.BREAKPOINT,
exception_cause_t.LOAD_ADDRESS_MISALIGNED,
exception_cause_t.LOAD_ACCESS_FAULT,
exception_cause_t.ECALL_MMODE]

View file

@ -1,63 +0,0 @@
"""
Copyright 2020 Google LLC
Copyright 2020 PerfectVIPs Inc.
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.
"""
XLEN = 32
implemented_csr = ['MVENDORID', 'MARCHID', 'MIMPID', 'MHARTID', 'MSTATUS', 'MISA', 'MIE',
'MTVEC', 'MCOUNTEREN', 'MSCRATCH', 'MEPC', 'MCAUSE', 'MTVAL', 'MIP']
SATP_MODE = 'BARE'
supported_isa = ['RV32I', 'RV32M', 'RV32C', 'RV32F', 'RV32FC', 'RV32D', 'RV32DC']
supported_privileged_mode = ['MACHINE_MODE']
supported_interrupt_mode = ['DIRECT', 'VECTORED']
max_interrupt_vector_num = 16
support_debug_mode = 0
NUM_HARTS = 1
support_pmp = 0
unsupported_instr = []
support_umode_trap = 0
support_sfence = 0
support_unaligned_load_store = 1
NUM_FLOAT_GPR = 32
NUM_GPR = 32
NUM_VEC_GPR = 32
VECTOR_EXTENSION_ENABLE = 0
VLEN = 512
ELEN = 32
SELEN = 0
MAX_MUL = 8
implemented_interrupt = ['M_SOFTWARE_INTR', 'M_TIMER_INTR', 'M_EXTERNAL_INTR']
implemented_exception = ['INSTRUCTION_ACCESS_FAULT', 'ILLEGAL_INSTRUCTION',
'BREAKPOINT', 'LOAD_ADDRESS_MISALIGNED',
'LOAD_ACCESS_FAULT', 'ECALL_MMODE']

View file

@ -1,7 +1,6 @@
"""
Copyright 2020 Google LLC
Copyright 2020 PerfectVIPs Inc.
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
@ -12,11 +11,12 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
import sys
import logging
sys.path.append("pygen/")
from pygen_src.riscv_instr_pkg import *
from pygen_src.riscv_instr_gen_config import cfg # NOQA
for isa in rcs.supported_isa:
import_module("pygen_src.isa." + isa.lower() + "_instr")
import_module("pygen_src.isa." + isa.name.lower() + "_instr")
from pygen_src.isa.riscv_instr import riscv_instr # NOQA
from pygen_src.riscv_asm_program_gen import riscv_asm_program_gen # NOQA
from pygen_src.riscv_utils import gen_config_table
@ -26,22 +26,27 @@ class riscv_instr_base_test:
def __init__(self):
self.start_idx = cfg.argv.start_idx
self.asm_file_name = cfg.argv.asm_file_name
self.asm = ""
def run_phase(self):
for _ in range(cfg.num_of_tests):
cfg.randomize()
gen_config_table()
asm = riscv_asm_program_gen()
self.randomize_cfg()
self.asm = riscv_asm_program_gen()
riscv_instr.create_instr_list(cfg)
if cfg.asm_test_suffix != "":
self.asm_file_name = "{}.{}".format(self.asm_file_name,
cfg.asm_test_suffix)
test_name = "{}_{}.S".format(self.asm_file_name,
_ + self.start_idx)
asm.get_directed_instr_stream()
asm.gen_program()
asm.gen_test_file(test_name)
self.asm.get_directed_instr_stream()
self.asm.gen_program()
self.asm.gen_test_file(test_name)
def randomize_cfg(self):
cfg.randomize()
logging.info("riscv_instr_gen_config is randomized")
gen_config_table()
riscv_instr_base_test = riscv_instr_base_test()
riscv_instr_base_test.run_phase()
riscv_base_test_ins = riscv_instr_base_test()
riscv_base_test_ins.run_phase()

View file

@ -0,0 +1,42 @@
"""
Copyright 2020 Google LLC
Copyright 2020 PerfectVIPs Inc.
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.
"""
import sys
import logging
sys.path.append("pygen/")
from pygen_src.test.riscv_instr_base_test import riscv_instr_base_test
from pygen_src.riscv_instr_gen_config import cfg
from pygen_src.riscv_utils import gen_config_table
class riscv_rand_instr_test(riscv_instr_base_test):
def __init__(self):
super().__init__()
def randomize_cfg(self):
cfg.instr_cnt = 10000
cfg.num_of_sub_program = 5
cfg.randomize()
logging.info("riscv_instr_gen_config is randomized")
gen_config_table()
def apply_directed_instr(self):
self.asm.add_directed_instr_stream("riscv_load_store_rand_instr_stream", 4)
self.asm.add_directed_instr_stream("riscv_loop_instr", 3)
self.asm.add_directed_instr_stream("riscv_jal_instr", 4)
self.asm.add_directed_instr_stream("riscv_hazard_instr_stream", 4)
self.asm.add_directed_instr_stream("riscv_load_store_hazard_instr_stream", 4)
self.asm.add_directed_instr_stream("riscv_multi_page_load_store_instr_stream", 4)
self.asm.add_directed_instr_stream("riscv_mem_region_stress_test", 4)
riscv_rand_test_ins = riscv_rand_instr_test()

View file

@ -228,7 +228,7 @@ def run_csr_test(cmd_list, cwd, csr_file, isa, iterations, lsf_cmd,
(" --xlen {}".format(
re.search(r"(?P<xlen>[0-9]+)", isa).group("xlen"))) + \
(" --iterations {}".format(iterations)) + \
(" --out {}/asm_tests".format(output_dir)) + \
(" --out {}/asm_test".format(output_dir)) + \
(" --end_signature_addr {}".format(end_signature_addr))
if lsf_cmd:
cmd_list.append(cmd)
@ -297,7 +297,7 @@ def do_simulate(sim_cmd, simulator, test_list, cwd, sim_opts, seed_gen,
cmd = lsf_cmd + " " + sim_cmd.rstrip() + \
(" --num_of_tests={}".format(test_cnt)) + \
(" --start_idx={}".format(i * batch_size)) + \
(" --asm_file_name={}/asm_tests/{}".format(
(" --asm_file_name={}/asm_test/{}".format(
output_dir, test['test'])) + \
(" --log_file_name={}/sim_{}_{}{}.log ".format(
output_dir,
@ -308,7 +308,7 @@ def do_simulate(sim_cmd, simulator, test_list, cwd, sim_opts, seed_gen,
(" +UVM_TESTNAME={} ".format(test['gen_test'])) + \
(" +num_of_tests={} ".format(test_cnt)) + \
(" +start_idx={} ".format(i * batch_size)) + \
(" +asm_file_name={}/asm_tests/{} ".format(
(" +asm_file_name={}/asm_test/{} ".format(
output_dir, test['test'])) + \
(" -l {}/sim_{}_{}{}.log ".format(
output_dir, test['test'], i, log_suffix))
@ -403,7 +403,7 @@ def gcc_compile(test_list, output_dir, isa, mabi, opts, debug_cmd):
for i in range(0, test['iterations']):
if 'no_gcc' in test and test['no_gcc'] == 1:
continue
prefix = ("{}/asm_tests/{}_{}".format(output_dir, test['test'], i))
prefix = ("{}/asm_test/{}_{}".format(output_dir, test['test'], i))
asm = prefix + ".S"
elf = prefix + ".o"
binary = prefix + ".bin"
@ -463,11 +463,11 @@ def run_assembly(asm_test, iss_yaml, isa, mabi, gcc_opts, iss_opts, output_dir,
report = ("{}/iss_regr.log".format(output_dir)).rstrip()
asm = re.sub(r"^.*\/", "", asm_test)
asm = re.sub(r"\.S$", "", asm)
prefix = ("{}/directed_asm_tests/{}".format(output_dir, asm))
prefix = ("{}/directed_asm_test/{}".format(output_dir, asm))
elf = prefix + ".o"
binary = prefix + ".bin"
iss_list = iss_opts.split(",")
run_cmd("mkdir -p {}/directed_asm_tests".format(output_dir))
run_cmd("mkdir -p {}/directed_asm_test".format(output_dir))
logging.info("Compiling assembly test : {}".format(asm_test))
# gcc compilation
@ -556,11 +556,11 @@ def run_c(c_test, iss_yaml, isa, mabi, gcc_opts, iss_opts, output_dir,
report = ("{}/iss_regr.log".format(output_dir)).rstrip()
c = re.sub(r"^.*\/", "", c_test)
c = re.sub(r"\.c$", "", c)
prefix = ("{}/directed_c_tests/{}".format(output_dir, c))
prefix = ("{}/directed_c_test/{}".format(output_dir, c))
elf = prefix + ".o"
binary = prefix + ".bin"
iss_list = iss_opts.split(",")
run_cmd("mkdir -p {}/directed_c_tests".format(output_dir))
run_cmd("mkdir -p {}/directed_c_test".format(output_dir))
logging.info("Compiling c test : {}".format(c_test))
# gcc compilation
@ -647,7 +647,7 @@ def iss_sim(test_list, output_dir, iss_list, iss_yaml, iss_opts,
continue
else:
for i in range(0, test['iterations']):
prefix = ("{}/asm_tests/{}_{}".format(
prefix = ("{}/asm_test/{}_{}".format(
output_dir, test['test'], i))
elf = prefix + ".o"
log = ("{}/{}.{}.log".format(log_dir, test['test'], i))
@ -683,7 +683,7 @@ def iss_cmp(test_list, iss, output_dir, stop_on_first_error, exp, debug_cmd):
run_cmd("rm -rf {}".format(report))
for test in test_list:
for i in range(0, test['iterations']):
elf = ("{}/asm_tests/{}_{}.o".format(output_dir, test['test'], i))
elf = ("{}/asm_test/{}_{}.o".format(output_dir, test['test'], i))
logging.info("Comparing ISS sim result {}/{} : {}".format(
iss_list[0], iss_list[1], elf))
log_list = []
@ -756,7 +756,7 @@ def parse_args(cwd):
parser.add_argument("--target", type=str, default="rv32imc",
help="Run the generator with pre-defined targets: \
rv32imc, rv32i, rv32imfdc, rv64imc, rv64gc")
rv32imc, rv32i, rv32imafdc, rv64imc, rv64gc")
parser.add_argument("-o", "--output", type=str,
help="Output directory name", dest="o")
parser.add_argument("-tl", "--testlist", type=str, default="",
@ -817,9 +817,9 @@ def parse_args(cwd):
help="Path for the riscv_core_setting.sv")
parser.add_argument("-ext", "--user_extension_dir", type=str, default="",
help="Path for the user extension directory")
parser.add_argument("--asm_tests", type=str, default="",
parser.add_argument("--asm_test", type=str, default="",
help="Directed assembly tests")
parser.add_argument("--c_tests", type=str, default="",
parser.add_argument("--c_test", type=str, default="",
help="Directed c tests")
parser.add_argument("--log_suffix", type=str, default="",
help="Simulation log name suffix")
@ -918,9 +918,9 @@ def load_config(args, cwd):
if args.target == "rv32imc":
args.mabi = "ilp32"
args.isa = "rv32imc"
elif args.target == "rv32imfdc":
elif args.target == "rv32imafdc":
args.mabi = "ilp32"
args.isa = "rv32imfdc"
args.isa = "rv32imafdc"
elif args.target == "rv32imc_sv32":
args.mabi = "ilp32"
args.isa = "rv32imc"
@ -979,9 +979,9 @@ def main():
if style_err: logging.info(
"Found style error: \nERROR: " + style_err)
# Run any handcoded/directed assembly tests specified by args.asm_tests
if args.asm_tests != "":
asm_test = args.asm_tests.split(',')
# Run any handcoded/directed assembly tests specified by args.asm_test
if args.asm_test != "":
asm_test = args.asm_test.split(',')
for path_asm_test in asm_test:
full_path = os.path.expanduser(path_asm_test)
# path_asm_test is a directory
@ -1001,9 +1001,9 @@ def main():
sys.exit(RET_FAIL)
return
# Run any handcoded/directed c tests specified by args.c_tests
if args.c_tests != "":
c_test = args.c_tests.split(',')
# Run any handcoded/directed c tests specified by args.c_test
if args.c_test != "":
c_test = args.c_test.split(',')
for path_c_test in c_test:
full_path = os.path.expanduser(path_c_test)
# path_c_test is a directory
@ -1023,7 +1023,7 @@ def main():
sys.exit(RET_FAIL)
return
run_cmd_output(["mkdir", "-p", ("{}/asm_tests".format(output_dir))])
run_cmd_output(["mkdir", "-p", ("{}/asm_test".format(output_dir))])
# Process regression test list
matched_list = []
# Any tests in the YAML test list that specify a directed assembly test
@ -1035,21 +1035,21 @@ def main():
process_regression_list(args.testlist, args.test, args.iterations,
matched_list, cwd)
for t in list(matched_list):
# Check mutual exclusive between gen_test, asm_tests, and c_tests
if 'asm_tests' in t:
if 'gen_test' in t or 'c_tests' in t:
# Check mutual exclusive between gen_test, asm_test, and c_test
if 'asm_test' in t:
if 'gen_test' in t or 'c_test' in t:
logging.error(
'asm_tests must not be defined in the testlist '
'together with the gen_test or c_tests field')
'asm_test must not be defined in the testlist '
'together with the gen_test or c_test field')
sys.exit(RET_FATAL)
asm_directed_list.append(t)
matched_list.remove(t)
if 'c_tests' in t:
if 'gen_test' in t or 'asm_tests' in t:
if 'c_test' in t:
if 'gen_test' in t or 'asm_test' in t:
logging.error(
'c_tests must not be defined in the testlist '
'together with the gen_test or asm_tests field')
'c_test must not be defined in the testlist '
'together with the gen_test or asm_test field')
sys.exit(RET_FATAL)
c_directed_list.append(t)
matched_list.remove(t)
@ -1066,7 +1066,7 @@ def main():
gcc_opts = args.gcc_opts
gcc_opts += test_entry.get('gcc_opts', '')
path_asm_test = os.path.expanduser(
test_entry.get('asm_tests'))
test_entry.get('asm_test'))
if path_asm_test:
# path_asm_test is a directory
if os.path.isdir(path_asm_test):
@ -1093,7 +1093,7 @@ def main():
for test_entry in c_directed_list:
gcc_opts = args.gcc_opts
gcc_opts += test_entry.get('gcc_opts', '')
path_c_test = os.path.expanduser(test_entry.get('c_tests'))
path_c_test = os.path.expanduser(test_entry.get('c_test'))
if path_c_test:
# path_c_test is a directory
if os.path.isdir(path_c_test):

10
vendor/google_riscv-dv/scripts/check-status vendored Executable file
View file

@ -0,0 +1,10 @@
#!/bin/bash
# Check the return code of run.py in order to give a pass/fail indication to Metrics
echo "run.py return code:" $1
if [ $1 == 0 ]; then
echo "Test passed";
else
echo "Test failed";
fi

View file

@ -0,0 +1,65 @@
#!/usr/bin/python3
## Summary:
## This Python script will create regression_list.json file which was referred by by .metrics.json
## Limitation:
## Only generate tests targeted for build "rv32imc"
##
## Note: Currently available testlists
## <rootDir>/yaml/base_testlist.yaml
## <rootDir>/yaml/cov_testlist.yaml
## <rootDir>/target/rv64gcv/testlist.yaml
## <rootDir>/target/rv64gc/testlist.yaml
## <rootDir>/target/rv32imcb/testlist.yaml
## <rootDir>/target/multi_harts/testlist.yaml
## <rootDir>/target/rv64imc/testlist.yaml
## <rootDir>/target/rv32imc/testlist.yaml
## <rootDir>/target/rv64imcb/testlist.yaml
## <rootDir>/target/ml/testlist.yaml
## <rootDir>/target/rv32i/testlist.yaml
import json
runCmdBase = "cd /mux-flow/results; python3 <rootDir>/run.py --test TESTNAME --simulator dsim --iss ovpsim --seed <seed> --so --out <rootDir>/out --verbose; <rootDir>/scripts/check-status $?; rm -fr <rootDir>/out/dsim"
## Based on testlist located in <rootDir>/yaml/base_testlist.yaml
base_testList = ["riscv_arithmetic_basic_test",
"riscv_rand_instr_test",
"riscv_jump_stress_test",
"riscv_loop_test",
"riscv_rand_jump_test",
"riscv_mmu_stress_test",
"riscv_no_fence_test",
"riscv_illegal_instr_test",
"riscv_ebreak_test",
"riscv_ebreak_debug_mode_test",
"riscv_full_interrupt_test",
## remove, will cause incomplete sim, need customized RTL
##"riscv_csr_test",
"riscv_unaligned_load_store_test"]
## Based on testlist located in <rootDir>/target/rv32imc/testlist.yaml
rv32imc_testList = [
"riscv_non_compressed_instr_test",
"riscv_hint_instr_test",
"riscv_pmp_test"
]
metricsList = []
## Note: Build is targeting rv32imc only.
for testName in base_testList + rv32imc_testList:
test = {}
test["name"] = testName
test["build"] = "rv32imc"
test["cmd"] = runCmdBase.replace("TESTNAME", testName)
test["wavesCmd"] = test["cmd"]
test["logFile"] = "simulation.log"
test["isPass"] = "Test passed"
test["metricsFile"] = "metrics.db"
test["seed"] = "random"
metricsList.append(test)
with open("regression_list.json", "w") as f:
json.dump(metricsList, f)

View file

@ -214,6 +214,7 @@ def gen_setup(test_file):
test_file.write(".section .text.init\n")
test_file.write(".globl _start\n")
test_file.write(".option norvc\n")
test_file.write(".org 0x80\n")
test_file.write("_start:\n")

View file

@ -0,0 +1,116 @@
#!/usr/bin/python3
import json
import http.client
import argparse
import os
import time
import math
def make_http_request( req_type, endpoint, params=None ):
headers = { 'Content-Type': 'application/json',
'Private-Token': str(os.environ['METRICS_CI_TOKEN'])
}
conn = http.client.HTTPSConnection(server)
conn.request(req_type, endpoint, params, headers)
response = conn.getresponse()
data = response.read()
regressionData = json.loads(data.decode('utf-8'))
conn.close()
return response, regressionData
## Parse arguments to get regression name and project ID
parser = argparse.ArgumentParser(prog='metrics-regress',
description='Launch a regression on the Metrics platform and query results')
parser.add_argument('regressionName', help='The name of the regression to run')
parser.add_argument('projectId', help='The ID of the Metrics project')
args = parser.parse_args()
## Server
server = 'chipsalliance.metrics.ca:443'
## API Endpoints
postRegression = '/api/v1/projects/'+args.projectId+'/regressionRuns'
getRegressionRunInfo = '/api/v1/projects/'+args.projectId+'/regressionRuns/'
## Start regression
reqParams = {}
reqParams['regressionName'] = args.regressionName
reqParams['branch'] = str(os.environ['GITHUB_REF'])
params = json.dumps(reqParams)
response, regressionData = make_http_request('POST', postRegression, params)
## Check response
if response.status is not 201:
print('Error, regression was not started. Response: ' + str(response.status) + ':' \
+ str(response.reason))
print('Exit with code 1')
exit(1)
else:
print('Regression started. Id = ' + regressionData['id'])
## Start polling regression status
regressionRunId = regressionData['id']
while True:
time.sleep(10)
response, regressionData = make_http_request('GET', getRegressionRunInfo+regressionRunId)
if response.status is 200:
if 'complete' in regressionData['status']:
print('Regression complete')
break
if 'buildFailed' in regressionData['status']:
print('A build has failed. No tests will be run')
print('Debug at: https://chipsalliance.metrics.ca/' + args.projectId + \
'/results/regressionRuns/' + regressionRunId)
exit(1)
## Print test status
print('\n')
print('Regression results')
print('==================')
print('Total number of tests: ' + str(regressionData['testRuns']['total']))
print('Passed tests: ' + str(regressionData['testRuns']['passed']))
print('Failed tests: ' + str(regressionData['testRuns']['failed']))
print('Incomplete tests: ' + str(regressionData['testRuns']['incomplete']))
print('\n')
## Poll for coverage data
#while True:
# time.sleep(10)
# response, regressionData = make_http_request('GET', getRegressionRunInfo+regressionRunId)
# if response.status is 200:
# if regressionData['functionalCoverage'] is not None :
# break
## Print functional coverage
#print('Coverage results')
#print('================')
#print('Functional: ' + str(math.trunc(regressionData['functionalCoverage']*100)/100))
#if regressionData['assertionCoverage'] is not None:
# print('Assertion: ' + str(math.trunc(regressionData['assertionCoverage']*100) /100))
#if regressionData['lineCoverage'] is not None:
# print('Code (block): ' + str(math.trunc(regressionData['lineCoverage']*100) /100))
#print('\n')
print('Full results at: https://chipsalliance.metrics.ca/' + args.projectId + \
'/results/regressionRuns/' + regressionRunId)
## Set the exit code to be used by github action
if regressionData['testRuns']['failed'] > 0 or \
regressionData['testRuns']['incomplete'] > 0:
print('One or more tests has failed/is incomplete. Exit with code 1.')
exit(1)
else:
print('All tests have passed. Exit with code 0.')
exit(0)

View file

@ -27,10 +27,10 @@ sys.path.insert(0, os.path.dirname(os.path.realpath(__file__)))
from riscv_trace_csv import *
from lib import *
RD_RE = re.compile(r"(?P<pri>\d) 0x(?P<addr>[a-f0-9]+?) " \
RD_RE = re.compile(r"(core\s+\d+:\s+)?(?P<pri>\d) 0x(?P<addr>[a-f0-9]+?) " \
"\((?P<bin>.*?)\) (?P<reg>[xf]\s*\d*?) 0x(?P<val>[a-f0-9]+)")
CORE_RE = re.compile(
r"core.*0x(?P<addr>[a-f0-9]+?) \(0x(?P<bin>.*?)\) (?P<instr>.*?)$")
r"core\s+\d+:\s+0x(?P<addr>[a-f0-9]+?) \(0x(?P<bin>.*?)\) (?P<instr>.*?)$")
ADDR_RE = re.compile(
r"(?P<rd>[a-z0-9]+?),(?P<imm>[\-0-9]+?)\((?P<rs1>[a-z0-9]+)\)")
ILLE_RE = re.compile(r"trap_illegal_instruction")

View file

@ -20,6 +20,8 @@ class riscv_floating_point_instr extends riscv_instr;
rand riscv_fpr_t fs2;
rand riscv_fpr_t fs3;
rand riscv_fpr_t fd;
rand f_rounding_mode_t rm;
rand bit use_rounding_mode_from_instr;
bit has_fs1 = 1'b1;
bit has_fs2 = 1'b1;
bit has_fs3 = 1'b0;
@ -67,6 +69,13 @@ class riscv_floating_point_instr extends riscv_instr;
default:
`uvm_fatal(`gfn, $sformatf("Unsupported floating point format: %0s", format.name()))
endcase
if ((category == ARITHMETIC) && use_rounding_mode_from_instr &&
!(instr_name inside {FMIN_S, FMAX_S, FMIN_D, FMAX_D, FMV_W_X, FMV_X_W,
FMV_D_X, FMV_X_D, FCLASS_S, FCLASS_D,
FCVT_D_S, FCVT_D_W, FCVT_D_WU,
FSGNJ_S, FSGNJN_S, FSGNJX_S, FSGNJ_D, FSGNJN_D, FSGNJX_D})) begin
asm_str = {asm_str, ", ", rm.name()};
end
if(comment != "")
asm_str = {asm_str, " #",comment};
return asm_str.tolower();
@ -174,9 +183,9 @@ class riscv_floating_point_instr extends riscv_instr;
// FSW rs2 is fp
fs2 = get_fpr(operands[0]);
fs2_value = get_gpr_state(operands[0]);
rs1 = get_gpr(operands[2]);
rs1_value = get_gpr_state(operands[2]);
get_val(operands[1], imm);
rs1 = get_gpr(operands[1]);
rs1_value = get_gpr_state(operands[1]);
get_val(operands[2], imm);
end
R_FORMAT: begin
// convert Pseudoinstructions for ovpsim

View file

@ -196,7 +196,7 @@ class riscv_privileged_common_seq extends uvm_sequence;
satp.init_reg(SATP);
satp.set_field("MODE", SATP_MODE);
instrs.push_back($sformatf("li x%0d, 0x%0x", cfg.gpr[0], satp.get_val()));
instrs.push_back($sformatf("csrw 0x%0x, x%0d // satp", SATP, cfg.gpr[0]));
instrs.push_back($sformatf("csrw 0x%0x, x%0d # satp", SATP, cfg.gpr[0]));
satp_ppn_mask = '1 >> (XLEN - satp.get_field_by_name("PPN").bit_width);
// Load the root page table physical address
instrs.push_back($sformatf("la x%0d, page_table_0", cfg.gpr[0]));
@ -205,7 +205,7 @@ class riscv_privileged_common_seq extends uvm_sequence;
instrs.push_back($sformatf("li x%0d, 0x%0x", cfg.gpr[1], satp_ppn_mask));
instrs.push_back($sformatf("and x%0d, x%0d, x%0d", cfg.gpr[0], cfg.gpr[0], cfg.gpr[1]));
// Set the PPN field for SATP
instrs.push_back($sformatf("csrs 0x%0x, x%0d // satp", SATP, cfg.gpr[0]));
instrs.push_back($sformatf("csrs 0x%0x, x%0d # satp", SATP, cfg.gpr[0]));
endfunction
endclass

View file

@ -30,7 +30,7 @@ privileged_mode_t supported_privileged_mode[] = {MACHINE_MODE};
riscv_instr_name_t unsupported_instr[];
// ISA supported by the processor
riscv_instr_group_t supported_isa[$] = {RV32I, RV32M, RV32C, RV32F, RV32FC};
riscv_instr_group_t supported_isa[$] = {RV32I, RV32M, RV32C, RV32F, RV32FC, RV32D, RV32DC, RV32A};
// Interrupt mode support
mtvec_mode_t supported_interrupt_mode[$] = {DIRECT, VECTORED};
@ -96,8 +96,8 @@ parameter int NUM_HARTS = 1;
privileged_reg_t implemented_csr[] = {
`else
const privileged_reg_t implemented_csr[] = {
`endif //
Machine mode mode CSR
`endif
// Machine mode mode CSR
MVENDORID, // Vendor ID
MARCHID, // Architecture ID
MIMPID, // Implementation ID
@ -119,8 +119,8 @@ bit[11:0] custom_csr[] = {
};
// ----------------------------------------------------------------------------
// Supported interrupt / exception setting, used for functional coverage //
----------------------------------------------------------------------------
// Supported interrupt / exception setting, used for functional coverage
// ----------------------------------------------------------------------------
`ifdef DSIM
interrupt_cause_t implemented_interrupt[] = {

View file

@ -33,6 +33,74 @@
- import: <riscv_dv_root>/target/rv32imc/testlist.yaml
- test: riscv_machine_mode_rand_test
description: >
Machine mode random instruction test
iterations: 2
gen_test: riscv_instr_base_test
gen_opts: >
+instr_cnt=10000
+num_of_sub_program=5
+boot_mode=m
rtl_test: core_base_test
- test: riscv_privileged_mode_rand_test
description: >
Random previliged mode test
iterations: 2
gen_test: riscv_instr_base_test
gen_opts: >
+instr_cnt=10000
+num_of_sub_program=5
rtl_test: core_base_test
# TODO: Only enable booting into U-mode for now, as OVPsim doesn't support some debug CSRs
- test: riscv_invalid_csr_test
description: >
Boot core into random privileged mode and generate csr accesses to invalid CSRs (at a higher priv mode)
iterations: 2
gen_test: riscv_rand_instr_test
gen_opts: >
+instr_cnt=6000
+num_of_sub_program=0
+enable_access_invalid_csr_level=1
+boot_mode=u
rtl_test: core_invalid_csr_test
sim_opts: >
+require_signature_addr=1
# TODO: Re-enable this test after all the data/instruction page organization changes are done
- test: riscv_page_table_exception_test
description: >
Test random page table exception handling. An exception handling routine is
designed to fix the page table error and resume execution.
iterations: 0
gen_test: riscv_rand_instr_test
gen_opts: >
+enable_page_table_exception=1
rtl_test: core_base_test
- test: riscv_sfence_exception_test
description: >
Random instruction test with S.FENCE exceptions
iterations: 2
gen_test: riscv_rand_instr_test
gen_opts: >
+allow_sfence_exception=1
rtl_test: core_base_test
- test: riscv_amo_test
description: >
RISC-V atomic instruction extension test
iterations: 2
gen_test: riscv_rand_instr_test
gen_opts: >
+instr_cnt=5000
+num_of_sub_program=5
# +directed_instr_0=riscv_lr_sc_instr_stream,10
+directed_instr_1=riscv_amo_instr_stream,10
rtl_test: core_base_test
- test: riscv_floating_point_arithmetic_test
description: >
Enable floating point instructions

View file

@ -7,10 +7,11 @@ class riscv_instr_cov_test extends uvm_test;
riscv_instr_cover_group instr_cg;
string trace_csv[$];
string trace[string];
bit report_illegal_instr;
int unsigned entry_cnt;
int unsigned total_entry_cnt;
int unsigned skipped_cnt;
int unsigned unexpected_illegal_instr_cnt;
int unsigned illegal_instr_cnt;
`uvm_component_utils(riscv_instr_cov_test)
`uvm_component_new
@ -23,6 +24,7 @@ class riscv_instr_cov_test extends uvm_test;
string header[$];
string entry[$];
int fd;
void'($value$plusargs("report_illegal_instr=%0d", report_illegal_instr));
while(1) begin
args = {$sformatf("trace_csv_%0d", i), "=%s"};
if ($value$plusargs(args, csv)) begin
@ -42,9 +44,6 @@ class riscv_instr_cov_test extends uvm_test;
bit expect_illegal_instr;
entry_cnt = 0;
instr_cg.reset();
if (uvm_is_match("*illegal*", trace_csv[i]) || uvm_is_match("*unknown*", trace_csv[i]) ) begin
expect_illegal_instr = 1;
end
`uvm_info(`gfn, $sformatf("Processing CSV trace[%0d]: %s", i, trace_csv[i]), UVM_LOW)
fd = $fopen(trace_csv[i], "r");
if (fd) begin
@ -79,11 +78,11 @@ class riscv_instr_cov_test extends uvm_test;
continue;
end
if (!sample()) begin
if (!expect_illegal_instr) begin
if (report_illegal_instr) begin
`uvm_error(`gfn, $sformatf("Found unexpected illegal instr: %0s [%0s]",
trace["instr"], line))
unexpected_illegal_instr_cnt++;
end
illegal_instr_cnt++;
end
end
entry_cnt += 1;
@ -97,9 +96,9 @@ class riscv_instr_cov_test extends uvm_test;
end
`uvm_info(`gfn, $sformatf("Finished processing %0d trace CSV, %0d instructions",
trace_csv.size(), total_entry_cnt), UVM_LOW)
if ((skipped_cnt > 0) || (unexpected_illegal_instr_cnt > 0)) begin
if ((skipped_cnt > 0) || ((illegal_instr_cnt > 0) && report_illegal_instr)) begin
`uvm_error(`gfn, $sformatf("%0d instructions skipped, %0d illegal instruction",
skipped_cnt, unexpected_illegal_instr_cnt))
skipped_cnt, illegal_instr_cnt))
end else begin
`uvm_info(`gfn, "TEST PASSED", UVM_NONE);