Update google_riscv-dv to google/riscv-dv@ea8dd25

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

* Upgrade bitmanip v.0.92 to v.0.93, enable simultaneous use with
  v.1.00 (Pirmin Vogel)
* Added v1.0.0 bitmanip support (Henrik Fegran)
* Remove the pyucis-viewer from requirements.txt (aneels3)
* Update README.md for PyFlow & add pyucis-viewer in requiremen.txt
  (aneels3)
* Fix typo with fs3_sign (aneels3)
* Add hint_cg and illegal_compressed_instr_cg covergroups (aneels3)
* override deepcopy method (aneels3)
* Fix issue with illegal_instr_testi and randselect (aneels3)
* Fixed b_extension_c() issue (shrujal20)
* Fixed get_rand_spf_dpf_value() issue (shrujal20)
* Add support for RV32C coverage (aneels3)
* Add README.md for PyFlow (aneels3)
* Add gen_timeout for PyFlow (aneels3)
* Issue google/riscv-dv#778 fix, change mie behavior in
  setup_mmode_reg (Henrik Fegran)
* Fixed wrong length of I, S, B-type immediates causing wrong sign
  extension for certain instructions (Henrik Fegran)
* Update riscv_compressed_instr.sv (AryamanAg)
* Update var binary of function convert2bin (AryamanAg)
* Improve status reporting (Philipp Wagner)
* update ml/testlist.yaml to get better coverage (Udi Jonnalagadda)
* add m extension covgroup (ishita71)
* Update pygen_src files (aneels3)

Signed-off-by: Pirmin Vogel <vogelpi@lowrisc.org>
This commit is contained in:
Pirmin Vogel 2021-12-03 11:39:28 +01:00
parent 169785d071
commit d8e50dcc2c
62 changed files with 4042 additions and 1611 deletions

View file

@ -51,7 +51,14 @@ ISS := spike
# ISS runtime options
ISS_OPTS :=
# ISA
ISA := rv32imcb
# Both an updated compiler and ISS are required to verify the bitmanip v.1.00
# and draft v.0.93 extensions. For now, disable the bitmanip tests and verify
# RV32IMC only.
# For details, refer to https://github.com/lowRISC/ibex/issues/1470
#ISA := rv32imcb
#ISA_ISS := rv32imc_Zba_Zbb_Zbc_Zbs_Xbitmanip
ISA := rv32imc
ISA_ISS := rv32imc
# Test name (default: full regression)
TEST := all
TESTLIST := riscv_dv_extension/testlist.yaml
@ -125,7 +132,6 @@ CSR_OPTS=--csr_yaml=${CSR_FILE} \
--end_signature_addr=${SIGNATURE_ADDR}
RISCV_DV_OPTS=--custom_target=riscv_dv_extension \
--isa="${ISA}" \
--mabi=ilp32 \
# To avoid cluttering the output directory with stamp files, we place them in
@ -244,7 +250,7 @@ tests-and-seeds := \
#
# To do this variable tracking, we dump each of the variables to a Makefile
# fragment and try to load it up the next time around.
gen-var-deps := GEN_OPTS SIMULATOR RISCV_DV_OPTS CSR_OPTS \
gen-var-deps := GEN_OPTS SIMULATOR RISCV_DV_OPTS ISA CSR_OPTS \
SIGNATURE_ADDR PMP_REGIONS PMP_GRANULARITY TEST_OPTS
# Load up the generation stage's saved variable values. If this fails, that's
@ -281,6 +287,7 @@ $(metadata)/instr_gen.gen.stamp: \
--lsf_cmd="${LSF_CMD}" \
--simulator="${SIMULATOR}" \
${RISCV_DV_OPTS} \
--isa=${ISA} \
${TEST_OPTS} \
${CSR_OPTS} \
--sim_opts="+uvm_set_inst_override=riscv_asm_program_gen,ibex_asm_program_gen,"uvm_test_top.asm_gen" \
@ -304,7 +311,8 @@ $(metadata)/instr_gen.compile.stamp: \
--steps=gcc_compile \
${TEST_OPTS} \
--gcc_opts=-mno-strict-align \
${RISCV_DV_OPTS} && \
${RISCV_DV_OPTS} \
--isa=${ISA} && \
touch $@
.PHONY: gcc_compile
@ -329,7 +337,7 @@ $(metadata)/instr_gen.iss.stamp: \
${TEST_OPTS} \
--iss="${ISS}" \
--iss_opts="${ISS_OPTS}" \
--isa="${ISA}" \
--isa="${ISA_ISS}" \
${RISCV_DV_OPTS}
$(call dump-vars,$(metadata)/iss-vars.mk,iss,$(iss-var-deps))
@touch $@

View file

@ -52,7 +52,8 @@ riscv_instr_name_t unsupported_instr[] = {FENCE_I};
bit support_unaligned_load_store = 1'b1;
// ISA supported by the processor
riscv_instr_group_t supported_isa[$] = {RV32I, RV32M, RV32C, RV32B};
riscv_instr_group_t supported_isa[$] = {RV32I, RV32M, RV32C,
RV32ZBA, RV32ZBB, RV32ZBC, RV32ZBS, RV32B};
// Interrupt mode support
mtvec_mode_t supported_interrupt_mode[$] = {VECTORED};

View file

@ -715,28 +715,41 @@
# Disable cosim for bitmanip tests for now as Ibex implements a different
# version of the spec compared to the Spike version used for the cosim.
- test: riscv_bitmanip_full_test
desc: >
Random instruction test with supported B extension instructions in full configuration
iterations: 10
gen_test: riscv_rand_instr_test
gen_opts: >
+enable_b_extension=1
+enable_bitmanip_groups=zbb,zb_tmp,zbt,zbs,zbp,zbf,zbe,zbc,zbr
+disable_cosim=1
rtl_test: core_ibex_base_test
rtl_params:
RV32B: "ibex_pkg::RV32BFull"
- test: riscv_bitmanip_balanced_test
desc: >
Random instruction test with supported B extension instructions in balanced configuration
iterations: 10
gen_test: riscv_rand_instr_test
gen_opts: >
+enable_b_extension=1
+enable_bitmanip_groups=zbb,zb_tmp,zbt,zbs,zbf
+disable_cosim=1
rtl_test: core_ibex_base_test
rtl_params:
RV32B: ["ibex_pkg::RV32BFull", "ibex_pkg::RV32BBalanced"]
# Both an updated compiler and ISS are required to verify the bitmanip v.1.00
# and draft v.0.93 extensions. For now, disable the bitmanip tests.
# For details, refer to https://github.com/lowRISC/ibex/issues/1470
#ISA := rv32imcb
#ISA_ISS := rv32imc_Zba_Zbb_Zbc_Zbs_Xbitmanip
#- test: riscv_bitmanip_full_test
# desc: >
# Random instruction test with supported B extension instructions in full configuration
# iterations: 10
# gen_test: riscv_rand_instr_test
# gen_opts: >
# +enable_zba_extension=1
# +enable_zbb_extension=1
# +enable_zbc_extension=1
# +enable_zbs_extension=1
# +enable_b_extension=1
# +enable_bitmanip_groups=zbe,zbf,zbp,zbr,zbt
# +disable_cosim=1
# rtl_test: core_ibex_base_test
# rtl_params:
# RV32B: "ibex_pkg::RV32BFull"
#
#- test: riscv_bitmanip_balanced_test
# desc: >
# Random instruction test with supported B extension instructions in balanced configuration
# iterations: 10
# gen_test: riscv_rand_instr_test
# gen_opts: >
# +enable_zba_extension=1
# +enable_zbb_extension=1
# +enable_zbs_extension=1
# +enable_b_extension=1
# +enable_bitmanip_groups=zbf,zbt
# +disable_cosim=1
# rtl_test: core_ibex_base_test
# rtl_params:
# RV32B: ["ibex_pkg::RV32BFull", "ibex_pkg::RV32BBalanced"]

View file

@ -9,6 +9,6 @@
upstream:
{
url: https://github.com/google/riscv-dv
rev: 59dcd8c813484eb6dcca67e7e36089fe772b9cc8
rev: ea8dd25140178eed13c3e0f3d3a97a0c07ab44a0
}
}

View file

@ -0,0 +1,99 @@
## Overview
RISCV-DV-PyFlow is a purely Python based open-source instruction generator for RISC-V processor
verification. It uses [PyVSC](https://github.com/fvutils/pyvsc) as the main library for
randomization and coverage collection. It currently supports the following features:
- Supported instruction set: RV32IMAFDC
- Supported privileged modes: For now only machine mode is supported.
- Illegal instruction and HINT instruction generation
- Random forward/backward branch instructions
- Supports mixing directed instructions with random instruction stream
- Support for direct & vectored interrupt table.
- Multi-hart support
- Functional coverage framework (reports GUI as well as text, currently
supports RV32IMFDC extensions)
- Supported ISS : Spike, OVPsim
## Supported tests
- riscv_arithmetic_basic_test
- riscv_amo_test
- riscv_floating_point_arithmetic_test
- riscv_floating_point_rand_test
- riscv_floating_point_mmu_stress_test
- riscv_b_ext_test
- riscv_rand_instr_test
- riscv_jump_stress_test
- riscv_rand_jump_test
- riscv_mmu_stress_test
- riscv_illegal_instr_test
- riscv_unaligned_load_store_test
- riscv_single_hart_test
- riscv_non_compressed_instr_test
- riscv_loop_test
## Getting Started
### Prerequisites
To be able to run the generator, you need to have RISCV-GCC compiler toolchain and ISS
(Instruction Set Simulator) installed (Spike is preferred).
### Install RISCV-DV-PyFlow
Getting the source
```bash
git clone https://github.com/google/riscv-dv.git
```
```bash
pip3 install -r requirements.txt # install dependencies (only once)
python3 run.py --help
```
## Running the Generator
Command to run a single test:
```bash
python3 run.py --test=riscv_arithmetic_basic_test --simulator=pyflow
```
--simulator=pyflow will invoke the Python generator.
Run a single test 10 times
```bash
python3 run.py --test=riscv_arithmetic_basic_test --iterations=10 --simulator=pyflow
```
Run the generator only, do not compile and simluation with ISS
```bash
python3 run.py --test=riscv_arithmetic_basic_test --simulator=pyflow --steps gen
```
## Coverage Model
The coverage model of PyFlow is developed using PyVSC library.
Command to generate the coverage report.
#### Process spike simulation log and collect functional coverage
```bash
python3 cov.py --dir out/spike_sim/ --simulator=pyflow --enable_visualization
```
--enable_visualization helps enabling coverage report visualization for pyflow.
#### Get the command reference
```bash
cov --help
```
#### Run the coverage flow with predefined targets
```bash
python3 cov.py --dir out/spike_sim/ --simulator=pyflow --enable_visualization --target rv32imc
```
The coverage reports can be viewed using two ways:
1) Text format: By opening the CoverageReport.txt file.
2) GUI format: By opening the cov_db.xml using pyucis-viewer.
The GUI format could be enabled using "--enable_visualization" command option.
```bash
pyucis-viewer cov_db.xml
```
## Note
Currently, time to generate a single program with larger than 10k instructions is around
12 minutes. We are working on improving the overall performance.

View file

@ -223,6 +223,6 @@ class riscv_compressed_instr(riscv_instr):
def get_c_opcode(self):
pass
# TOD0
# TODO
def get_func3(self):
pass

View file

@ -19,11 +19,11 @@ import vsc
import logging
from importlib import import_module
from enum import Enum, IntEnum, auto
from bitstring import BitArray
from pygen_src.riscv_instr_pkg import *
from pygen_src.riscv_instr_gen_config import cfg
rcs = import_module("pygen_src.target." + cfg.argv.target + ".riscv_core_setting")
class operand_sign_e(IntEnum):
POSITIVE = 0
NEGATIVE = auto()
@ -35,6 +35,11 @@ class div_result_e(IntEnum):
DIV_OVERFLOW = auto()
class div_result_ex_overflow_e(IntEnum):
DIV_NORMAL = 0
DIV_BY_ZERO = auto()
class compare_result_e(IntEnum):
EQUAL = 0
LARGER = auto()
@ -142,7 +147,7 @@ class riscv_cov_instr:
if self.imm_type.name == "UIMM":
self.imm_len = 5
else:
self.imm_len = 11
self.imm_len = 12
def set_mode(self):
# mode setting for Instruction Format
@ -320,10 +325,11 @@ class riscv_cov_instr:
the result of the check_hazard_condition won't be accurate. Need to
explicitly extract the destination register from the operands '''
if pre_instr.has_rd:
if ((self.has_rs1 and self.rs1 == pre_instr.rd) or
(self.has_rs2 and self.rs1 == pre_instr.rd)):
if ((self.has_rs1 and (self.rs1 == pre_instr.rd)) or
(self.has_rs2 and (self.rs1 == pre_instr.rd))):
logging.info("pre_instr {}".format(pre_instr.instr.name))
self.gpr_hazard = hazard_e["RAW_HAZARD"]
elif self.has_rd and self.rd == pre_instr.rd:
elif self.has_rd and (self.rd == pre_instr.rd):
self.gpr_hazard = hazard_e["WAW_HAZARD"]
elif (self.has_rd and
((pre_instr.has_rs1 and (pre_instr.rs1 == self.rd)) or
@ -333,16 +339,16 @@ class riscv_cov_instr:
self.gpr_hazard = hazard_e["NO_HAZARD"]
if self.category == riscv_instr_category_t.LOAD:
if (pre_instr.category == riscv_instr_category_t.STORE and
pre_instr.mem_addr.get_val() == self.mem_addr.get_val()):
(pre_instr.mem_addr.get_val() == self.mem_addr.get_val())):
self.lsu_hazard = hazard_e["RAW_HAZARD"]
else:
self.lsu_hazard = hazard_e["NO_HAZARD"]
if self.category == riscv_instr_category_t.STORE:
if (pre_instr.category == riscv_instr_category_t.STORE and
pre_instr.mem_addr.get_val() == self.mem_addr.get_val()):
(pre_instr.mem_addr.get_val() == self.mem_addr.get_val())):
self.lsu_hazard = hazard_e["WAW_HAZARD"]
elif (pre_instr.category == riscv_instr_category_t.LOAD and
pre_instr.mem_addr.get_val() == self.mem_addr.get_val()):
(pre_instr.mem_addr.get_val() == self.mem_addr.get_val())):
self.lsu_hazard = hazard_e["WAR_HAZARD"]
else:
self.lsu_hazard = hazard_e["NO_HAZARD"]

View file

@ -116,7 +116,7 @@ class riscv_floating_point_instr(riscv_instr):
self.has_fs1 = 0
self.has_fd = 0
else:
logging.info("Unsupported format %0s", self.format.name)
logging.info("Unsupported format {}".format(self.format.name))
def pre_randomize(self):
super().pre_randomize()

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
@ -9,7 +8,6 @@ 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 logging
@ -110,12 +108,32 @@ class riscv_instr:
with vsc.if_then(self.XLEN != 32):
self.imm[11:6] == 0
@vsc.constraint
def csr_c(self):
# TODO
pass
@classmethod
def register(cls, instr_name, instr_group):
logging.info("Registering {}".format(instr_name.name))
cls.instr_registry[instr_name] = instr_group
return 1
def __deepcopy__(self, memo):
cls = self.__class__ # Extract the class of the object.
# Create a new instance of the object based on extracted class.
result = cls.__new__(cls)
memo[id(self)] = result
for k, v in self.__dict__.items():
if k in ["_ro_int", "tname", "__field_info"]:
continue # Skip the fields which are not required.
else:
# Copy over attributes by copying directly.
setattr(result, k, copy.deepcopy(v, memo))
return result
# Create the list of instructions based on the supported ISA extensions and configuration
# of the generator
@classmethod
def create_instr_list(cls, cfg):
cls.instr_names.clear()
@ -129,6 +147,7 @@ class riscv_instr:
if not instr_inst.is_supported(cfg):
continue
# C_JAL is RV32C only instruction
if ((rcs.XLEN != 32) and (instr_name == riscv_instr_name_t.C_JAL)):
continue
if ((riscv_reg_t.SP in cfg.reserved_regs) and
@ -310,7 +329,7 @@ class riscv_instr:
if self.imm_type.name == "UIMM":
self.imm_len = 5
else:
self.imm_len = 11
self.imm_len = 12
self.imm_mask = (self.imm_mask << self.imm_len) & self.shift_t
def extend_imm(self):

View file

@ -14,13 +14,13 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
import vsc
import random
from importlib import import_module
from pygen_src.riscv_instr_gen_config import cfg
from pygen_src.isa.riscv_instr import riscv_instr
from pygen_src.riscv_pseudo_instr import riscv_pseudo_instr
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")
@ -62,7 +62,6 @@ class riscv_amo_base_instr_stream(riscv_mem_access_stream):
@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
@ -73,7 +72,7 @@ class riscv_amo_base_instr_stream(riscv_mem_access_stream):
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']
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):
@ -81,7 +80,7 @@ class riscv_amo_base_instr_stream(riscv_mem_access_stream):
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'],
la_instr.imm_str = "{}+{}".format(cfg.amo_region[self.data_page_id].name,
self.offset[i])
self.instr_list.insert(0, la_instr)

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
@ -9,7 +8,6 @@ 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 logging
@ -31,35 +29,43 @@ from pygen_src.riscv_privileged_common_seq import riscv_privileged_common_seq
from pygen_src.riscv_utils import factory
rcs = import_module("pygen_src.target." + cfg.argv.target + ".riscv_core_setting")
'''
RISC-V assembly program generator
This is the main class to generate a complete RISC-V program, including the init routine,
instruction section, data section, stack section, page table, interrupt and exception
handling etc. Check gen_program() function to see how the program is generated.
'''
# ----------------------------------------------------------------------------------
# RISC-V assembly program generator
# This is the main class to generate a complete RISC-V program, including the init routine,
# instruction section, data section, stack section, page table, interrupt and exception
# handling etc. Check gen_program() function to see how the program is generated.
# ----------------------------------------------------------------------------------
@vsc.randobj
class riscv_asm_program_gen:
def __init__(self):
self.instr_stream = []
# Directed instruction ratio, occurance per 1000 instructions
self.directed_instr_stream_ratio = {}
self.hart = 0
self.page_table_list = []
self.main_program = []
self.sub_program = []
self.data_page_gen = None
self.spf_val = vsc.rand_bit_t(32)
self.dpf_val = vsc.rand_bit_t(64)
# ----------------------------------------------------------------------------------
# Main function to generate the whole program
# ----------------------------------------------------------------------------------
# This is the main function to generate all sections of the program.
def gen_program(self):
# Generate program header
self.instr_stream.clear()
# Generate program header
self.gen_program_header()
for hart in range(cfg.num_of_harts):
# Commenting out for now
# TODO support for sub_program
# sub_program_name = []
self.instr_stream.append(f"h{int(hart)}_start:")
if not cfg.bare_program_mode:
@ -70,7 +76,6 @@ class riscv_asm_program_gen:
self.pre_enter_privileged_mode(hart)
# Init section
self.gen_init_section(hart)
# To DO
'''
If PMP is supported, we want to generate the associated trap handlers and the test_done
section at the start of the program so we can allow access through the pmpcfg0 CSR
@ -87,7 +92,8 @@ class riscv_asm_program_gen:
self.gen_store_fault_handler(hart)
if hart == 0:
self.gen_test_done()
# Generate sub program
# TODO gen_sub_program()
# Generate main program
gt_lbl_str = pkg_ins.get_label("main", hart)
label_name = gt_lbl_str
@ -103,8 +109,10 @@ class riscv_asm_program_gen:
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)
# Setup jump instruction among main program and sub programs
# TODO gen_callstack()
self.main_program[hart].post_process_instr()
logging.info("Post-processing main program...done")
self.main_program[hart].generate_instr_stream()
logging.info("Generating main program instruction stream...done")
self.instr_stream.extend(self.main_program[hart].instr_string_list)
@ -113,14 +121,14 @@ class riscv_asm_program_gen:
to test_done section at the end of main_program, as the test_done
will have moved to the beginning of the program
"""
self.instr_stream.append("{}j test_done".format(pkg_ins.indent))
'''
Test done section
If PMP isn't supported, generate this in the normal location
'''
self.instr_stream.extend(("{}la x{}, test_done".format(pkg_ins.indent, cfg.scratch_reg),
"{}jalr x0, x{}, 0".format(pkg_ins.indent, cfg.scratch_reg)))
# Test done section
# If PMP isn't supported, generate this in the normal location
if(hart == 0 and not(rcs.support_pmp)):
self.gen_test_done()
# Shuffle the sub programs and insert to the instruction stream
# TODO inser_sub_program()
logging.info("Main/sub program generation...done")
# program end
self.gen_program_end(hart)
@ -138,6 +146,7 @@ class riscv_asm_program_gen:
# AMO memory region
if(hart == 0 and riscv_instr_group_t.RV32A in rcs.supported_isa):
self.gen_data_page(hart, amo = 1)
# Stack section
self.gen_stack_section(hart)
if not cfg.bare_program_mode:
# Generate kernel program/data/stack section
@ -145,6 +154,10 @@ class riscv_asm_program_gen:
# Page table
self.gen_page_table_section(hart)
# ----------------------------------------------------------------------------------
# Generate kernel program/data/stack sections
# ----------------------------------------------------------------------------------
def gen_kernel_sections(self, hart):
if rcs.SATP_MODE != satp_mode_t.BARE:
self.instr_stream.append(".align 12")
@ -152,56 +165,84 @@ class riscv_asm_program_gen:
self.instr_stream.append(".align 2")
self.instr_stream.append(pkg_ins.get_label("kernel_instr_start:", hart))
self.instr_stream.append(".text")
# Kernel programs
# TODO
# All trap/interrupt handling is in the kernel region
# Trap/interrupt delegation to user mode is not supported now
# Trap handler
self.gen_all_trap_handler(hart)
# Interrupt handling subroutine
for mode in rcs.supported_privileged_mode:
self.gen_interrupt_handler_section(mode, hart)
self.instr_stream.append(pkg_ins.get_label("kernel_instr_end: nop", hart))
# User stack and data pages may not be accessible when executing trap handling programs in
# machine/supervisor mode. Generate separate kernel data/stack sections to solve it.
if not cfg.virtual_addr_translation_on:
if rcs.SATP_MODE != satp_mode_t.BARE:
self.instr_stream.append(".align 12")
else:
self.instr_stream.append(".align 2")
# Kernel data pages
self.instr_stream.append(pkg_ins.get_label("kernel_data_start:", hart))
if not cfg.no_data_page:
# Data section
self.gen_data_page(hart, 1)
# Kernel stack section
self.gen_kernel_stack_section(hart)
def gen_kernel_program(self, hart, seq):
# TODO
pass
# ----------------------------------------------------------------------------------
# Generate any subprograms and set up the callstack
# ----------------------------------------------------------------------------------
def gen_sub_program(self, hart, sub_program,
sub_program_name, num_sub_program,
is_debug = 0, prefix = "sub"):
# TODO
pass
def gen_callstack(self, main_program, sub_program,
sub_program_name, num_sub_program):
# TODO
pass
def insert_sub_program(self, sub_program, instr_list):
# TODO
pass
# ----------------------------------------------------------------------------------
# Major sections - init, stack, data, test_done etc.
# ----------------------------------------------------------------------------------
def gen_program_header(self):
string = []
self.instr_stream.append(".include \"user_define.h\"")
self.instr_stream.append(".globl _start")
self.instr_stream.append(".section .text")
header_string = []
self.instr_stream.extend((".include \"user_define.h\"", ".globl _start", ".section .text"))
if cfg.disable_compressed_instr:
self.instr_stream.append(".option norvc;")
string.append(".include \"user_init.s\"")
string.append("csrr x5, mhartid")
header_string.extend((".include \"user_init.s\"",
"csrr x5, {}".format(hex(privileged_reg_t.MHARTID))))
for hart in range(cfg.num_of_harts):
string.append("li x6, {}\n{}beq x5, x6, {}f".format(hart, pkg_ins.indent, hart))
self.gen_section("_start", string)
header_string.extend(("li x6, {}".format(hart),
"beq x5, x6, {}f".format(hart)))
self.gen_section("_start", header_string)
for hart in range(cfg.num_of_harts):
self.instr_stream.append("{}: j h{}_start".format(hart, hart))
self.instr_stream.extend(("{}: la x{}, h{}_start".format(hart, cfg.scratch_reg, hart),
"jalr x0, x{}, 0".format(cfg.scratch_reg)))
def gen_program_end(self, hart):
if hart == 0:
# Use write_tohost to terminate spike simulation
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:
self.instr_stream.append(".align 6; .global tohost; tohost: .dword 0;")
self.instr_stream.append(".align 6; .global fromhost; fromhost: .dword 0;")
self.instr_stream.extend((".align 6; .global tohost; tohost: .dword 0;",
".align 6; .global fromhost; fromhost: .dword 0;"))
def gen_data_page(self, hart, is_kernel = 0, amo = 0):
self.data_page_gen = riscv_data_page_gen()
@ -221,15 +262,15 @@ class riscv_asm_program_gen:
else:
self.instr_stream.append(".align 2")
self.instr_stream.append(pkg_ins.get_label("user_stack_start:", hart))
self.instr_stream.append(".rept {}".format(cfg.stack_len - 1))
self.instr_stream.append(".{}byte 0x0".format(rcs.XLEN // 8))
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))
self.instr_stream.extend((pkg_ins.get_label("user_stack_start:", hart),
".rept {}".format(cfg.stack_len - 1),
".{}byte 0x0".format(rcs.XLEN // 8), ".endr",
pkg_ins.get_label("user_stack_end:", hart),
".{}byte 0x0".format(rcs.XLEN // 8)))
if cfg.use_push_data_section:
self.instr_stream.push_back(".popsection;")
self.instr_stream.append(".popsection;")
# The kernal stack is used to save user program context before executing exception handling
def gen_kernel_stack_section(self, hart):
hart_prefix_string = pkg_ins.hart_prefix(hart)
if cfg.use_push_data_section:
@ -242,33 +283,31 @@ class riscv_asm_program_gen:
self.instr_stream.append(".align 12")
else:
self.instr_stream.append(".align 2")
self.instr_stream.append(pkg_ins.get_label("kernel_stack_start:", hart))
self.instr_stream.append(".rept {}".format(cfg.kernel_stack_len - 1))
self.instr_stream.append(".{}byte 0x0".format(rcs.XLEN // 8))
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))
self.instr_stream.extend((pkg_ins.get_label("kernel_stack_start:", hart),
".rept {}".format(cfg.stack_len - 1),
".{}byte 0x0".format(rcs.XLEN // 8), ".endr",
pkg_ins.get_label("kernel_stack_end:", hart),
".{}byte 0x0".format(rcs.XLEN // 8)))
if cfg.use_push_data_section:
self.instr_stream.push_back(".popsection;")
self.instr_stream.append(".popsection;")
def gen_init_section(self, hart):
string = pkg_ins.format_string(pkg_ins.get_label("init:", hart), pkg_ins.LABEL_STR_LEN)
self.instr_stream.append(string)
init_string = pkg_ins.format_string(pkg_ins.get_label("init:", hart), pkg_ins.LABEL_STR_LEN)
self.instr_stream.append(init_string)
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(
init_string = "{}la x{}, {}user_stack_end".format(
pkg_ins.indent, cfg.sp, pkg_ins.hart_prefix(hart))
self.instr_stream.append(string)
self.instr_stream.append(init_string)
if cfg.enable_vector_extension:
self.init_vector_engine()
self.randomize_vec_gpr_and_csr()
self.core_is_initialized()
self.gen_dummy_csr_write()
if rcs.support_pmp:
string = pkg_ins.indent + "j main"
self.instr_stream.append(string)
init_string = pkg_ins.indent + "j main"
self.instr_stream.append(init_string)
# Setup MISA based on supported extensions
def setup_misa(self):
@ -316,21 +355,37 @@ class riscv_asm_program_gen:
else:
logging.critical("{} is not yet supported".format(group.name))
sys.exit(1)
if privileged_mode_t.SUPERVISOR_MODE.name in rcs.supported_privileged_mode:
if privileged_mode_t.SUPERVISOR_MODE 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],
hex(misa.get_val())))
self.instr_stream.append("{}csrw {}, x{}".format(pkg_ins.indent, hex(privileged_reg_t.MISA),
cfg.gpr[0]))
self.instr_stream.extend(("{}li x{}, {}".format(pkg_ins.indent, cfg.gpr[0],
hex(misa.get_val())),
"{}csrw {}, x{}".format(pkg_ins.indent,
hex(privileged_reg_t.MISA), cfg.gpr[0])))
# Write to the signature_addr with values to indicate to the core testbench
# that is safe to start sending interrupt and debug stimulus
def core_is_initialized(self):
pass
instr = []
if cfg.require_signature_addr:
if cfg.signature_addr != 0xdeadbeef:
self.gen_signature_handshake(instr, signature_type_t.CORE_STATUS,
core_status_t.INITIALIZED)
self.format_section(instr)
self.instr_stream.append(instr)
else:
logging.critical("The signature_addr is not properly configured!")
sys.exit(1)
# Generate some dummy writes to xSTATUS/xIE at the beginning of the test to check
# repeated writes to these CSRs.
def gen_dummy_csr_write(self):
# TODO
pass
# Initialize general purpose registers with random value
def init_gpr(self):
reg_val = vsc.rand_bit_t(pkg_ins.DATA_WIDTH)
# Init general purpose registers with random values
for i in range(rcs.NUM_GPR):
if i in [cfg.sp.value, cfg.tp.value]:
continue
@ -343,19 +398,25 @@ class riscv_asm_program_gen:
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)
self.instr_stream.append("{}li x{}, {}".format(pkg_ins.indent, i,
hex(reg_val.get_val())))
# Initialize vector general purpose registers
def init_vec_gpr(self):
# TODO
pass
# Initialize floating point general purpose registers
def init_floating_point_gpr(self):
for i in range(rcs.NUM_FLOAT_GPR):
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)
# Initialize rounding mode of FCSR and append to the instr_stream
self.instr_stream.append("{}fsrmi {}".format(pkg_ins.indent, cfg.fcsr_rm))
# get instructions initialize floating_point_gpr with single precision floating value
def init_floating_point_gpr_with_spf(self, int_floating_gpr):
imm = self.get_rand_spf_value()
li_instr = "{}li x{}, {}".format(pkg_ins.indent, cfg.gpr[0], hex(imm))
@ -363,6 +424,7 @@ class riscv_asm_program_gen:
cfg.gpr[0])
self.instr_stream.extend((li_instr, fmv_instr))
# get instructions initialize floating_point_gpr with double precision floating value
def init_floating_point_gpr_with_dpf(self, int_floating_gpr):
imm = vsc.bit_t(64)
imm = self.get_rand_dpf_value()
@ -378,114 +440,205 @@ class riscv_asm_program_gen:
fmv_instr = "{}fmv.d.x f{}, x{}".format(pkg_ins.indent, int_floating_gpr, int_gpr2)
self.instr_stream.extend((li_instr0, slli_instr, li_instr1, or_instr, fmv_instr))
# Get a random single precision floating value
def get_randselect(self, addr_range1, addr_range2, flag):
if flag:
# Get a random double precision floating value
with vsc.raw_mode():
with vsc.randomize_with(self.dpf_val):
self.dpf_val in vsc.rangelist(addr_range1, addr_range2)
else:
# Get a random single precision floating value
with vsc.raw_mode():
with vsc.randomize_with(self.spf_val):
self.spf_val in vsc.rangelist(addr_range1, addr_range2)
def get_rng(self, val0, val1, spf_dpf, flag):
if flag == 0 and spf_dpf == 32:
with vsc.raw_mode():
with vsc.randomize_with(self.spf_val): self.spf_val[val0 : val1] > 0
elif flag == 0 and spf_dpf == 64:
with vsc.raw_mode():
with vsc.randomize_with(self.dpf_val): self.dpf_val[val0 : val1] > 0
elif flag == 1 and spf_dpf == 32:
with vsc.raw_mode():
with vsc.randomize_with(self.spf_val): self.spf_val[val0 : val1] == 0
else:
with vsc.raw_mode():
with vsc.randomize_with(self.dpf_val): self.dpf_val[val0 : val1] == 0
def get_rand_spf_value(self):
# TODO randcase
value = random.randrange(0, 2**32 - 1)
return value
vsc.randselect([
# Infinity
(1, lambda: self.get_randselect(0x7f80_0000, 0xff80_0000, 0)),
# Largest
(1, lambda: self.get_randselect(0x7f7f_ffff, 0xff7f_ffff, 0)),
# Zero
(1, lambda: self.get_randselect(0x0000_0000, 0x8000_0000, 0)),
# NaN
(1, lambda: self.get_randselect(0x7f80_0001, 0x7fc0_0000, 0)),
# Normal
(1, lambda: self.get_rng(30, pkg_ins.SINGLE_PRECISION_FRACTION_BITS, 32, 0)),
# Subnormal
(1, lambda: self.get_rng(30, pkg_ins.SINGLE_PRECISION_FRACTION_BITS, 32, 1))])
return self.spf_val
# Get a random double precision floating value
def get_rand_dpf_value(self):
value = vsc.bit_t(64)
# TODO randcase
return value
vsc.randselect([
# Infinity
(1, lambda: self.get_randselect(0x7ff0_0000_0000_0000, 0xfff0_0000_0000_0000, 1)),
# largest
(1, lambda: self.get_randselect(0x7fef_ffff_ffff_ffff, 0xffef_ffff_ffff_ffff, 1)),
# Zero
(1, lambda: self.get_randselect(0x0000_0000_0000_0000, 0x8000_0000_0000_0000, 1)),
# NaN
(1, lambda: self.get_randselect(0x7ff0_0000_0000_0001, 0x7ff8_0000_0000_0000, 1)),
# Normal
(1, lambda: self.get_rng(62, pkg_ins.DOUBLE_PRECISION_FRACTION_BITS, 64 , 0)),
# Subnormal
(1, lambda: self.get_rng(62, pkg_ins.DOUBLE_PRECISION_FRACTION_BITS, 64, 1))])
return self.dpf_val
def init_vector_engine(self):
pass
# Generate "test_done" section, test is finished by an ECALL instruction
# The ECALL trap handler will handle the clean up procedure before finishing the test.
def gen_test_done(self):
string = pkg_ins.format_string("test_done:", pkg_ins.LABEL_STR_LEN)
self.instr_stream.append(string)
self.instr_stream.append(pkg_ins.indent + "li gp, 1")
self.instr_stream.extend((pkg_ins.format_string("test_done:", pkg_ins.LABEL_STR_LEN),
pkg_ins.indent + "li gp, 1"))
if cfg.bare_program_mode:
self.instr_stream.append(pkg_ins.indent + "j write_tohost")
else:
self.instr_stream.append(pkg_ins.indent + "ecall")
def gen_register_dump(self):
string = ""
# Dump all GPR to the starting point of the program
# TB can check the GPR value for this memory location to compare with expected value generated
# by the ISA simulator. If the processor doesn't have a good tracer unit, it might not be
# possible to compare the GPR value after each instruction execution.
def gen_register_dump(self, instr):
# load base address
string = "{}la x{}, _start".format(pkg_ins.indent, cfg.gpr[0])
self.instr_stream.append(string)
instr.append("la x{}, _start".format(cfg.gpr[0]))
# Generate sw/sd instructions
for i in range(32):
if rcs.XLEN == 64:
string = "{}sd x{}, {}(x{})".format(
pkg_ins.indent, i, i * (rcs.XLEN / 8), cfg.gpr[0])
dump_str = "sd x{}, {}(x{})".format(i, i * (rcs.XLEN // 8), cfg.gpr[0])
else:
string = "{}sw x{}, {}(x{})".format(
pkg_ins.indent, i, int(i * (rcs.XLEN / 8)), cfg.gpr[0])
self.instr_stream.append(string)
dump_str = "sw x{}, {}(x{})".format(i, i * (rcs.XLEN // 8), cfg.gpr[0])
instr.append(dump_str)
# ----------------------------------------------------------------------------------
# Privileged mode entering routine
# ----------------------------------------------------------------------------------
def pre_enter_privileged_mode(self, hart):
instr = []
string = []
string.append("la x{}, {}kernel_stack_end".format(cfg.tp, pkg_ins.hart_prefix(hart)))
self.gen_section(pkg_ins.get_label("kernel_sp", hart), string)
privil_str = []
# Setup kernel stack pointer
privil_str.append("la x{}, {}kernel_stack_end".format(cfg.tp, pkg_ins.hart_prefix(hart)))
self.gen_section(pkg_ins.get_label("kernel_sp", hart), privil_str)
# Setup interrupt and exception delegation
if not cfg.no_delegation and (cfg.init_privileged_mode != privileged_mode_t.MACHINE_MODE):
self.gen_delegation(hart)
# Setup trap vector register
self.trap_vector_init(hart)
# Setup PMP CSRs
self.setup_pmp(hart)
# Generate PMPADDR write test sequence
self.gen_pmp_csr_write(hart)
# Initialize PTE (link page table based on their real physical address)
if cfg.virtual_addr_translation_on:
self.page_table_list.process_page_table(instr)
# TODO
# self.page_table_list.process_page_table(instr)
self.gen_section(pkg_ins.get_label("process_pt", hart), instr)
# Setup mepc register, jump to init entry
self.setup_epc(hart)
# Initialization of any implementation-specific custom CSRs
self.setup_custom_csrs(hart)
# Setup initial privilege mode
self.gen_privileged_mode_switch_routine(hart)
def gen_privileged_mode_switch_routine(self, hart):
privil_seq = riscv_privileged_common_seq()
for i in range(len(rcs.supported_privileged_mode)):
for privil_mode in rcs.supported_privileged_mode:
instr = []
# csr_handshake = []
if rcs.supported_privileged_mode[i] != cfg.init_privileged_mode:
if privil_mode != cfg.init_privileged_mode:
continue
logging.info("Generating privileged mode routing for {}"
.format(rcs.supported_privileged_mode[i]))
.format(privil_mode.name))
# Enter Privileged mode
privil_seq.hart = hart
privil_seq.randomize()
privil_seq.enter_privileged_mode(rcs.supported_privileged_mode[i], instr)
# TODO
privil_seq.enter_privileged_mode(privil_mode, instr)
if cfg.require_signature_addr:
# TODO
pass
self.instr_stream.extend(instr)
# Setup EPC before entering target privileged mode
def setup_epc(self, hart):
instr = []
instr.append("la x{}, {}init".format(cfg.gpr[0], pkg_ins.hart_prefix(hart)))
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], cfg.gpr[0], rcs.XLEN - 12) +
"srli x{}, x{}, {}".format(cfg.gpr[0], cfg.gpr[0], rcs.XLEN - 12))
mode_name = cfg.init_privileged_mode.name
instr.extend(("slli x{}, x{}, {}".format(cfg.gpr[0], cfg.gpr[0], rcs.XLEN - 12),
"srli x{}, x{}, {}".format(cfg.gpr[0], cfg.gpr[0], rcs.XLEN - 12)))
instr.append("csrw {}, x{}".format(hex(privileged_reg_t.MEPC), cfg.gpr[0]))
if not rcs.support_pmp:
instr.append("j {}init_{}".format(pkg_ins.hart_prefix(hart), mode_name.lower()))
self.gen_section(pkg_ins.get_label("mepc_setup", hart), instr)
# Setup PMP CSR configuration
def setup_pmp(self, hart):
# TODO
pass
# Generates a directed stream of instructions to write random values to all supported
# pmpaddr CSRs to test write accessibility.
# The original CSR values are restored afterwards.
def gen_pmp_csr_write(self, hart):
# TODO
pass
# Handles creation of a subroutine to initialize any custom CSRs
def setup_custom_csrs(self, hart):
# TODO
pass
# This function should be overridden in the riscv_asm_program_gen extended class
# corresponding to the RTL implementation if it has any custom CSRs defined.
# All that needs to be done in the overridden function is to manually create
# the instruction strings to set up any custom CSRs and then to push those strings
# into the instr queue.
def init_custom_csr(self, instr):
# TODO
pass
# ---------------------------------------------------------------------------------------
# Privileged CSR setup for interrupt and exception handling and delegation
# ---------------------------------------------------------------------------------------
# Interrupt and exception delegation setting.
# The lower level exception and interrupt can be delegated to higher level handler.
def gen_delegation(self, hart):
self.gen_delegation_instr(hart, "MEDELEG", "MIDELEG",
self.gen_delegation_instr(hart,
privileged_reg_t.MEDELEG,
privileged_reg_t.MIDELEG,
cfg.m_mode_exception_delegation,
cfg.m_mode_interrupt_delegation)
if rcs.support_umode_trap:
self.gen_delegation_instr(hart, "SEDELEG", "SIDELEG",
self.gen_delegation_instr(hart,
privileged_reg_t.SEDELEG,
privileged_reg_t.SIDELEG,
cfg.s_mode_exception_delegation,
cfg.s_mode_interrupt_delegation)
def gen_delegation_instr(self, hart, edeleg, ideleg,
edeleg_enable, ideleg_enable):
# TODO
pass
# Setup trap vector - MTVEC, STVEC, UTVEC
def trap_vector_init(self, hart):
instr = []
for mode in rcs.supported_privileged_mode:
@ -498,43 +651,73 @@ class riscv_asm_program_gen:
else:
logging.critical("Unsupported privileged_mode {}".format(mode.name))
sys.exit(1)
# Skip utvec init if trap delegation to u_mode is not supported
if(mode == privileged_mode_t.USER_MODE and not (rcs.support_umode_trap)):
continue
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], pkg_ins.hart_prefix(hart), tvec_name))
if(rcs.SATP_MODE != satp_mode_t.BARE and mode != privileged_mode_t.MACHINE_MODE):
# For supervisor and user mode, use virtual address instead of physical address.
# Virtual address starts from address 0x0, here only the lower 20 bits are kept
# as virtual address offset.
instr.append("slli x{}, x{}, {}\n".format(cfg.gpr[0], cfg.gpr[0], rcs.XLEN - 20) +
"srli x{}, x{}, {}".format(cfg.gpr[0], cfg.gpr[0], rcs.XLEN - 20))
instr.append("ori x{}, x{}, {}".format(cfg.gpr[0], cfg.gpr[0], cfg.mtvec_mode))
instr.append("csrw {}, x{} # {}".format(
hex(trap_vec_reg), cfg.gpr[0], trap_vec_reg.name))
instr.extend(("ori x{}, x{}, {}".format(cfg.gpr[0], cfg.gpr[0], cfg.mtvec_mode),
"csrw {}, x{} # {}".format(hex(trap_vec_reg), cfg.gpr[0],
trap_vec_reg.name)))
self.gen_section(pkg_ins.get_label("trap_vec_init", hart), instr)
# ---------------------------------------------------------------------------------------
# Exception handling routine
# ---------------------------------------------------------------------------------------
# Trap handling routine
def gen_all_trap_handler(self, hart):
instr = []
# If PMP isn't supported, generate the relevant trap handler sections as per usual
if not rcs.support_pmp:
self.gen_trap_handlers(hart)
# Ecall handler
self.gen_ecall_handler(hart)
# Instruction fault handler
self.gen_instr_fault_handler(hart)
# Load fault handler
self.gen_load_fault_handler(hart)
# Store fault handler
self.gen_store_fault_handler(hart)
# Ebreak handler
self.gen_ebreak_handler(hart)
# Illegal instruction handler
self.gen_illegal_instr_handler(hart)
# Generate page table fault handling routine
# Page table fault is always handled in machine mode, as virtual address translation may be
# broken when page fault happens.
self.gen_signature_handshake(instr, signature_type_t.CORE_STATUS,
core_status_t.HANDLING_EXCEPTION)
if not self.page_table_list:
# TODO
# self.page_table_list.gen_page_fault_handling_routine(instr)
pass
else:
instr.append("nop")
self.gen_section(pkg_ins.get_label("pt_fault_handler", hart), instr)
def gen_trap_handlers(self, hart):
# TODO
self.gen_trap_handler_section(hart, "m", privileged_reg_t.MCAUSE,
privileged_reg_t.MTVEC, privileged_reg_t.MTVAL,
privileged_reg_t.MEPC, privileged_reg_t.MSCRATCH,
privileged_reg_t.MSTATUS, privileged_reg_t.MIE,
privileged_reg_t.MIP)
# Generate the interrupt and trap handler for different privileged mode.
# The trap handler checks the xCAUSE to determine the type of the exception and jumps to
# corresponding exeception handling routine.
def gen_trap_handler_section(self, hart, mode, cause, tvec,
tval, epc, scratch, status, ie, ip):
# is_interrupt = 1
@ -546,7 +729,6 @@ class riscv_asm_program_gen:
# Push user mode GPR to kernel stack before executing exception handling,
# this is to avoid exception handling routine modify user program state
# unexpectedly
# TODO
pkg_ins.push_gpr_to_kernel_stack(
status, scratch, cfg.mstatus_mprv, cfg.sp, cfg.tp, instr)
# Checking xStatus can be optional if ISS (like spike) has different implementation of
@ -554,6 +736,9 @@ class riscv_asm_program_gen:
if cfg.check_xstatus:
instr.append("csrr x{}, {} # {}".format(
cfg.gpr[0], hex(status), status.name))
# Use scratch CSR to save a GPR value
# Check if the exception is caused by an interrupt, if yes, jump to interrupt
# handler Interrupt is indicated by xCause[XLEN-1]
instr.append("csrr x{}, {} # {}\n".format(cfg.gpr[0], hex(cause),
cause.name) +
"{}srli x{}, x{}, {}\n".format(pkg_ins.indent, cfg.gpr[0],
@ -564,26 +749,29 @@ class riscv_asm_program_gen:
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 != satp_mode_t.BARE:
self.instr_stream.append(".align 12")
else:
self.instr_stream.append(".align {}".format(cfg.tvec_alignment))
tvec_name = tvec.name
self.gen_section(pkg_ins.get_label("{}_handler".format(tvec_name.lower()), hart), instr)
# TODO Exception handlers
# Exception handler
instr = []
if cfg.mtvec_mode == mtvec_mode_t.VECTORED:
pkg_ins.push_gpr_to_kernel_stack(status, scratch,
cfg.mstatus_mprv, cfg.sp, cfg.tp, instr)
pkg_ins.push_gpr_to_kernel_stack(
status, scratch, cfg.mstatus_mprv, cfg.sp, cfg.tp, instr)
self.gen_signature_handshake(instr, signature_type_t.CORE_STATUS,
core_status_t.HANDLING_EXCEPTION)
# The trap is caused by an exception, read back xCAUSE, xEPC to see if these
# CSR values are set properly. The checking is done by comparing against the log
# generated by ISA simulator (spike).
instr.extend(("csrr x{}, 0x{} # {}".format(cfg.gpr[0], epc, epc.name),
"csrr x{}, 0x{} # {}".format(cfg.gpr[0], cause, cause.name),
# TODO
instr.extend(("csrr x{}, {} # {}".format(cfg.gpr[0], hex(epc), epc.name),
"csrr x{}, {} # {}".format(cfg.gpr[0], hex(cause), cause.name),
# Check if it's an ECALL exception. Jump to ECALL exception handler
# TODO ECALL_SMODE, ECALL_UMODE
"li x{}, {} # ECALL_MMODE".format(cfg.gpr[1],
hex(exception_cause_t.ECALL_MMODE)),
"beq x{}, x{}, {}ecall_handler".format(
cfg.gpr[0], cfg.gpr[1], pkg_ins.hart_prefix(hart)),
# Illegal instruction exception
"li x{}, {} # ILLEGAL_INSTRUCTION".format(
cfg.gpr[1], hex(exception_cause_t.ILLEGAL_INSTRUCTION)),
@ -596,6 +784,7 @@ class riscv_asm_program_gen:
"jalr x1, x{}, 0".format(cfg.scratch_reg)))
self.gen_section(pkg_ins.get_label("{}mode_exception_handler".format(mode), hart), instr)
# Generate for interrupt vector table
def gen_interrupt_vector_table(self, hart, mode, status, cause, ie,
ip, scratch, instr):
'''In vector mode, the BASE address is shared between interrupt 0 and exception handling.
@ -634,21 +823,37 @@ class riscv_asm_program_gen:
"jalr x0, x{}, 0".format(cfg.scratch_reg)))
self.gen_section(pkg_ins.get_label(
"{}mode_intr_vector_{}".format(mode, i), hart), intr_handler)
# ECALL trap handler
# It does some clean up like dump GPRs before communicating with host to terminate the test.
# User can extend this function if some custom clean up routine is needed.
def gen_ecall_handler(self, hart):
string = ""
string = pkg_ins.format_string(pkg_ins.get_label(
"ecall_handler:", hart), pkg_ins.LABEL_STR_LEN)
self.instr_stream.append(string)
self.dump_perf_stats()
self.gen_register_dump()
string = pkg_ins.format_string(" ", pkg_ins.LABEL_STR_LEN)
string = string + "j write_tohost"
self.instr_stream.append(string)
instr = []
self.dump_perf_stats(instr)
self.gen_register_dump(instr)
instr.extend(("la x{}, write_tohost".format(cfg.scratch_reg),
"jalr x0, x{}, 0".format(cfg.scratch_reg)))
self.gen_section(pkg_ins.get_label("ecall_handler", hart), instr)
# Ebreak trap handler
# When breakpoint exception happens, epc will be written with ebreak instruction
# itself. Add epc by 4 and resume execution.
# Note the breakpoint could be triggered by a C.EBREAK instruction, the generated program
# guarantees that epc + 4 is a valid instruction boundary
# TODO: Support random operations in debug mode
# TODO: Support ebreak exception delegation
# TODO: handshake the correct Xcause CSR based on delegation privil. mode
def gen_ebreak_handler(self, hart):
# TODO
pass
# Illegal instruction handler
# Note: Save the illegal instruction to MTVAL is optional in the spec, and mepc could be
# a virtual address that cannot be used in machine mode handler. As a result, there's no way to
# know the illegal instruction is compressed or not. This hanlder just simply adds the PC by
# 4 and resumes execution. The way that the illegal instruction is injected guarantees that
# PC + 4 is a valid instruction boundary.
# TODO: handshake the corret Xcause CSR based on delegation setup
def gen_illegal_instr_handler(self, hart):
instr = []
self.gen_signature_handshake(instr, signature_type_t.CORE_STATUS,
@ -662,24 +867,47 @@ class riscv_asm_program_gen:
instr.append("mret")
self.gen_section(pkg_ins.get_label("illegal_instr_handler", hart), instr)
# TODO: handshake correct csr based on delegation
def gen_instr_fault_handler(self, hart):
# TODO
pass
# TODO: handshake correct csr based on delegation
def gen_load_fault_handler(self, hart):
# TODO
pass
# TODO: handshake correct csr based on delegation
def gen_store_fault_handler(self, hart):
# TODO
pass
# ---------------------------------------------------------------------------------------
# Page table setup
# ---------------------------------------------------------------------------------------
# Create page table if virtual address translation is supported.
# The page is created based on the address translation mode - SV32, SV39, SV48
# Right now only the lowest level 4KB page table is configured as leaf page table entry (PTE),
# all the other super pages are link PTE.
def create_page_table(self, hart):
# TODO
pass
# Generate the page table section of the program
# The page table is generated as a group of continuous 4KB data sections.
def gen_page_table_section(self, hart):
# TODO
pass
# Only extend this function if the core utilizes a PLIC for handling interrupts
# In this case, the core will write to a specific location as the response to the interrupt, and
# external PLIC unit can detect this response and process the interrupt clean up accordingly.
def gen_plic_section(self, interrupt_handler_instr):
# TODO
pass
# Interrupt handler routine
def gen_interrupt_handler_section(self, mode, hart):
interrupt_handler_instr = []
# ls_unit = "w" if rcs.XLEN == 32 else "d"
@ -708,11 +936,12 @@ class riscv_asm_program_gen:
else:
logging.critical("Unsupported mode: {}".format(mode.name))
sys.exit(1)
# If nested interrupts are enabled, set xSTATUS.xIE in the interrupt handler
# to re-enable interrupt handling capabilities
if cfg.enable_nested_interrupt:
interrupt_handler_instr.append("csrr x{}, {}".format(cfg.gpr[0], hex(scratch)))
interrupt_handler_instr.append("bgtz x{}, 1f".format(cfg.gpr[0]))
interrupt_handler_instr.append("csrwi {}, 0x1".format(hex(scratch)))
interrupt_handler_instr.extend(("csrr x{}, {}".format(cfg.gpr[0], hex(scratch)),
"bgtz x{}, 1f".format(cfg.gpr[0]),
"csrwi {}, 0x1".format(hex(scratch))))
if status == privileged_reg_t.MSTATUS:
interrupt_handler_instr.append("csrsi {}, {}".format(hex(status), hex(8)))
@ -725,7 +954,8 @@ class riscv_asm_program_gen:
sys.exit(1)
interrupt_handler_instr.append("1: csrwi {},0".format(hex(scratch)))
# Read back interrupt related privileged CSR
# The value of these CSR are checked by comparing with spike simulation result.
to_extend_interrupt_hanlder_instr = ["csrr x{}, {} # {};".format(cfg.gpr[0],
hex(status),
status.name),
@ -739,21 +969,30 @@ class riscv_asm_program_gen:
ip.name)]
interrupt_handler_instr.extend(to_extend_interrupt_hanlder_instr)
self.gen_plic_section(interrupt_handler_instr)
# Restore user mode GPR value from kernel stack before return
pkg_ins.pop_gpr_from_kernel_stack(status, scratch, cfg.mstatus_mprv,
cfg.sp, cfg.tp, interrupt_handler_instr)
interrupt_handler_instr.append("{}ret;".format(mode_prefix))
if rcs.SATP_MODE != satp_mode_t.BARE:
# The interrupt handler will use one 4KB page
self.instr_stream.append(".align 12")
else:
self.instr_stream.append(".align 2")
self.gen_section(pkg_ins.get_label("%0smode_intr_handler" %
(mode_prefix), hart), interrupt_handler_instr)
self.gen_section(pkg_ins.get_label("{}mode_intr_handler".format(mode_prefix), hart),
interrupt_handler_instr)
# ---------------------------------------------------------------------------------------
# Helper functions
# ---------------------------------------------------------------------------------------
# Format a code section, without generating it
def format_section(self, instr):
# TODO
pass
# Generate a code section
def gen_section(self, label, instr):
if label != "":
string = pkg_ins.format_string("{}:".format(label), pkg_ins.LABEL_STR_LEN)
@ -763,9 +1002,12 @@ class riscv_asm_program_gen:
self.instr_stream.append(string)
self.instr_stream.append("")
def dump_perf_stats(self):
# Dump performance CSRs if applicable
def dump_perf_stats(self, instr):
# TODO
pass
# Write the generated program to a file
def gen_test_file(self, test_name):
file = open(test_name, "w+")
for items in self.instr_stream:
@ -774,6 +1016,8 @@ class riscv_asm_program_gen:
file.close()
logging.info("{} is generated".format(test_name))
# Helper function to generate the proper sequence of handshake instructions
# to signal the testbench (see riscv_signature_pkg.sv)
def gen_signature_handshake(self, instr, signature_type,
core_status=core_status_t.INITIALIZED,
test_result=test_result_t.TEST_FAIL,
@ -828,6 +1072,10 @@ class riscv_asm_program_gen:
logging.critical("signature_type is not defined")
sys.exit(1)
# ---------------------------------------------------------------------------------------
# Inject directed instruction stream
# ---------------------------------------------------------------------------------------
def add_directed_instr_stream(self, name, ratio):
self.directed_instr_stream_ratio[name] = ratio
logging.info("Adding directed instruction stream:%0s ratio:%0d/1000", name, ratio)
@ -852,6 +1100,7 @@ class riscv_asm_program_gen:
stream_freq = cfg.args_dict[stream_freq_opts]
self.add_directed_instr_stream(stream_name, stream_freq)
# Generate directed instruction stream based on the ratio setting
def generate_directed_instr_stream(self, hart = 0, label = "", original_instr_cnt = 0,
min_insert_cnt = 0, kernel_mode = 0, instr_stream = []):
instr_insert_cnt = 0
@ -885,5 +1134,18 @@ class riscv_asm_program_gen:
idx += 1
random.shuffle(instr_stream)
# ----------------------------------------------------------------------------------
# Generate the debug ROM, and any related programs
# ----------------------------------------------------------------------------------
def gen_debug_rom(self, hart):
# TODO
pass
# ----------------------------------------------------------------------------------
# Vector extension generation
# ----------------------------------------------------------------------------------
def randomize_vec_gpr_and_csr(self):
# TODO
pass

View file

@ -14,16 +14,23 @@ import logging
import vsc
import random
from collections import defaultdict
from pygen_src.riscv_instr_pkg import pkg_ins, data_pattern_t
from pygen_src.riscv_instr_gen_config import cfg
from pygen_src.riscv_instr_pkg import pkg_ins, data_pattern_t
# -----------------------------------------------------------------------------------------
# RISC-V assmebly program data section generator
# There can be user mode and supervisor(kernel) mode data pages
# -----------------------------------------------------------------------------------------
@vsc.randobj
class riscv_data_page_gen:
def __init__(self):
self.data_page_str = []
self.mem_region_setting = defaultdict(list)
# The data section can be initialized with different data pattern:
# - Random value, incremental value, all zeros
@staticmethod
def gen_data(idx, pattern, num_of_bytes, data):
temp_data = 0
@ -36,10 +43,9 @@ class riscv_data_page_gen:
data[i] = (idx + i) % 256
return data
# Generate data pages for all memory regions
def gen_data_page(self, hart_id, pattern, is_kernel=0, amo=0):
tmp_str = ""
temp_data = []
page_size = 0
self.data_page_str.clear()
if is_kernel:
self.mem_region_setting = cfg.s_mem_region
@ -47,8 +53,6 @@ class riscv_data_page_gen:
self.mem_region_setting = cfg.amo_region
else:
self.mem_region_setting = cfg.mem_region
for i in range(len(self.mem_region_setting)):
logging.info("mem_region_setting {}".format(self.mem_region_setting[i]))
for i in range(len(self.mem_region_setting)):
logging.info("Generate data section: {} size:0x{} xwr:0x{}".format(
self.mem_region_setting[i].name,

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

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
@ -20,14 +19,13 @@ from enum import IntEnum, auto
from pygen_src.riscv_instr_stream import riscv_rand_instr_stream
from pygen_src.isa.riscv_instr import riscv_instr
from pygen_src.riscv_instr_gen_config import cfg
from pygen_src.riscv_instr_pkg import (riscv_reg_t,
riscv_pseudo_instr_name_t,
riscv_instr_name_t, pkg_ins,
mem_region_t)
from pygen_src.riscv_instr_pkg import (riscv_reg_t, riscv_pseudo_instr_name_t,
riscv_instr_name_t, mem_region_t, pkg_ins)
from pygen_src.riscv_pseudo_instr import riscv_pseudo_instr
rcs = import_module("pygen_src.target." + cfg.argv.target + ".riscv_core_setting")
# Base class for directed instruction stream
class riscv_directed_instr_stream(riscv_rand_instr_stream):
label = ""
@ -47,6 +45,7 @@ class riscv_directed_instr_stream(riscv_rand_instr_stream):
self.instr_list[0].has_label = 1
# Base class for memory access stream
@vsc.randobj
class riscv_mem_access_stream(riscv_directed_instr_stream):
def __init__(self):
@ -65,6 +64,7 @@ class riscv_mem_access_stream(riscv_directed_instr_stream):
self.data_page.extend(cfg.mem_region)
self.max_data_page_id = len(self.data_page)
# Use "la" instruction to initialize the base regiseter
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
@ -79,6 +79,7 @@ class riscv_mem_access_stream(riscv_directed_instr_stream):
cfg.mem_region[idx].name, base)
self.instr_list.insert(0, la_instr)
# Insert some other instructions to mix with mem_access instruction
def add_mixed_instr(self, instr_cnt):
self.setup_allowed_instr(1, 1)
for i in range(instr_cnt):
@ -87,6 +88,7 @@ class riscv_mem_access_stream(riscv_directed_instr_stream):
self.insert_instr(instr)
# Stress back to back jump instruction
@vsc.randobj
class riscv_jal_instr(riscv_rand_instr_stream):
def __init__(self):
@ -96,6 +98,7 @@ class riscv_jal_instr(riscv_rand_instr_stream):
self.jump_start = riscv_instr()
self.jump_end = riscv_instr()
self.num_of_jump_instr = vsc.rand_int_t()
self.jal = []
@vsc.constraint
def instr_c(self):
@ -115,6 +118,8 @@ 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)
# First instruction
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
@ -157,6 +162,7 @@ class int_numeric_e(IntEnum):
NegativeMax = auto()
# Strees the numeric corner cases of integer arithmetic operations
@vsc.randobj
class riscv_int_numeric_corner_stream(riscv_directed_instr_stream):
def __init__(self):
@ -185,6 +191,7 @@ class riscv_int_numeric_corner_stream(riscv_directed_instr_stream):
self.avail_regs[i] != riscv_reg_t.ZERO
def pre_randomize(self):
# TODO
pass
def post_randomize(self):
@ -212,7 +219,6 @@ class riscv_int_numeric_corner_stream(riscv_directed_instr_stream):
# Push Stack Instructions
class riscv_push_stack_instr(riscv_rand_instr_stream):
def __init__(self):
super().__init__()
self.stack_len = 0
@ -225,12 +231,13 @@ class riscv_push_stack_instr(riscv_rand_instr_stream):
self.push_start_label = ''
def init(self):
# Save RA, T0
self.reserved_rd = [cfg.ra]
self.saved_regs = [cfg.ra]
self.num_of_reg_to_save = len(self.saved_regs)
if self.num_of_reg_to_save * (rcs.XLEN / 8) > self.stack_len:
logging.error('stack len [%0d] is not enough to store %d regs',
self.stack_len, self.num_of_reg_to_save)
logging.error('stack len [{}] is not enough to store {} regs'
.format(self.stack_len, self.num_of_reg_to_save))
sys.exit(1)
self.num_of_redundant_instr = random.randrange(3, 10)
self.initialize_instr_list(self.num_of_redundant_instr)
@ -288,7 +295,6 @@ class riscv_push_stack_instr(riscv_rand_instr_stream):
# Pop stack instruction stream
class riscv_pop_stack_instr(riscv_rand_instr_stream):
def __init__(self):
super().__init__()
self.stack_len = 0
@ -301,8 +307,8 @@ class riscv_pop_stack_instr(riscv_rand_instr_stream):
self.reserved_rd = [cfg.ra]
self.num_of_reg_to_save = len(self.saved_regs)
if self.num_of_reg_to_save * 4 > self.stack_len:
logging.error('stack len [%0d] is not enough to store %d regs',
self.stack_len, self.num_of_reg_to_save)
logging.error('stack len [{}] is not enough to store {} regs'
.format(self.stack_len, self.num_of_reg_to_save))
sys.exit(1)
self.num_of_redundant_instr = random.randrange(3, 10)
self.initialize_instr_list(self.num_of_redundant_instr)

View file

@ -162,8 +162,8 @@ class riscv_illegal_instr:
@vsc.constraint
def b_extension_c(self):
if riscv_instr_group_t.RV32B in rcs.supported_isa:
with vsc.if_then(self.exception in [illegal_instr_type_e.kIllegalFunc3,
illegal_instr_type_e.kIllegalFunc7]):
with vsc.if_then(self.exception.inside(vsc.rangelist(illegal_instr_type_e.kIllegalFunc3,
illegal_instr_type_e.kIllegalFunc7))):
self.opcode.inside(vsc.rangelist([51, 19, 59]))
@vsc.constraint
@ -338,7 +338,7 @@ class riscv_illegal_instr:
def initialize(self):
if (riscv_instr_group_t.RV32F in rcs.supported_isa) or \
(riscv_instr_group_t.RV32D in rcs.supported_isa):
self.legal_opcode.extend(7, 39, 67, 71, 75, 79, 83)
self.legal_opcode.extend((7, 39, 67, 71, 75, 79, 83))
if riscv_instr_group_t.RV64I in rcs.supported_isa:
self.legal_opcode.append(27)
if riscv_instr_group_t.RV32A in rcs.supported_isa:
@ -347,8 +347,8 @@ class riscv_illegal_instr:
(riscv_instr_group_t.RV64M in rcs.supported_isa):
self.legal_opcode.append(59)
if riscv_instr_group_t.RV64I in rcs.supported_isa:
self.legal_c00_opcode.extend(3, 7)
self.legal_c10_opcode.extend(3, 7)
self.legal_c00_opcode.extend((3, 7))
self.legal_c10_opcode.extend((3, 7))
# TODO csr
def get_bin_str(self):

View file

@ -13,6 +13,7 @@ See the License for the specific language governing permissions and
limitations under the License.
"""
import traceback
from pygen_src.isa.riscv_cov_instr import *
@ -1381,6 +1382,195 @@ class riscv_instr_cover_group:
self.cp_align = vsc.cross([self.cp_imm_align, self.cp_rs1_align])
self.cp_ras = vsc.cross([self.cp_rs1_link, self.cp_rd_link])
'''MUL instructions'''
@vsc.covergroup
class mul_cg(object):
def __init__(self):
super().__init__()
self.instr = None
self.cp_rs1 = vsc.coverpoint(lambda: self.instr.rs1,
cp_t=vsc.enum_t(riscv_reg_t))
self.cp_rs2 = vsc.coverpoint(lambda: self.instr.rs2,
cp_t=vsc.enum_t(riscv_reg_t))
self.cp_rd = vsc.coverpoint(lambda: self.instr.rd,
cp_t=vsc.enum_t(riscv_reg_t))
self.cp_rs1_sign = vsc.coverpoint(lambda: self.instr.rs1_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_rs2_sign = vsc.coverpoint(lambda: self.instr.rs2_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_rd_sign = vsc.coverpoint(lambda: self.instr.rd_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_gpr_hazard = vsc.coverpoint(lambda: self.instr.gpr_hazard,
cp_t=vsc.enum_t(hazard_e))
self.cp_sign_cross = vsc.cross([self.cp_rs1_sign, self.cp_rs2_sign,
self.cp_rd_sign])
@vsc.covergroup
class mulh_cg(object):
def __init__(self):
super().__init__()
self.instr = None
self.cp_rs1 = vsc.coverpoint(lambda: self.instr.rs1,
cp_t=vsc.enum_t(riscv_reg_t))
self.cp_rs2 = vsc.coverpoint(lambda: self.instr.rs2,
cp_t=vsc.enum_t(riscv_reg_t))
self.cp_rd = vsc.coverpoint(lambda: self.instr.rd,
cp_t=vsc.enum_t(riscv_reg_t))
self.cp_rs1_sign = vsc.coverpoint(lambda: self.instr.rs1_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_rs2_sign = vsc.coverpoint(lambda: self.instr.rs2_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_rd_sign = vsc.coverpoint(lambda: self.instr.rd_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_gpr_hazard = vsc.coverpoint(lambda: self.instr.gpr_hazard,
cp_t=vsc.enum_t(hazard_e))
self.cp_sign_cross = vsc.cross([self.cp_rs1_sign, self.cp_rs2_sign,
self.cp_rd_sign])
@vsc.covergroup
class mulhsu_cg(object):
def __init__(self):
super().__init__()
self.instr = None
self.cp_rs1 = vsc.coverpoint(lambda: self.instr.rs1,
cp_t=vsc.enum_t(riscv_reg_t))
self.cp_rs2 = vsc.coverpoint(lambda: self.instr.rs2,
cp_t=vsc.enum_t(riscv_reg_t))
self.cp_rd = vsc.coverpoint(lambda: self.instr.rd,
cp_t=vsc.enum_t(riscv_reg_t))
self.cp_rs1_sign = vsc.coverpoint(lambda: self.instr.rs1_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_rs2_sign = vsc.coverpoint(lambda: self.instr.rs2_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_rd_sign = vsc.coverpoint(lambda: self.instr.rd_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_gpr_hazard = vsc.coverpoint(lambda: self.instr.gpr_hazard,
cp_t=vsc.enum_t(hazard_e))
self.cp_sign_cross = vsc.cross([self.cp_rs1_sign, self.cp_rs2_sign,
self.cp_rd_sign])
@vsc.covergroup
class mulhu_cg(object):
def __init__(self):
super().__init__()
self.instr = None
self.cp_rs1 = vsc.coverpoint(lambda: self.instr.rs1,
cp_t=vsc.enum_t(riscv_reg_t))
self.cp_rs2 = vsc.coverpoint(lambda: self.instr.rs2,
cp_t=vsc.enum_t(riscv_reg_t))
self.cp_rd = vsc.coverpoint(lambda: self.instr.rd,
cp_t=vsc.enum_t(riscv_reg_t))
self.cp_rs1_sign = vsc.coverpoint(lambda: self.instr.rs1_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_rs2_sign = vsc.coverpoint(lambda: self.instr.rs2_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_rd_sign = vsc.coverpoint(lambda: self.instr.rd_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_gpr_hazard = vsc.coverpoint(lambda: self.instr.gpr_hazard,
cp_t=vsc.enum_t(hazard_e))
self.cp_sign_cross = vsc.cross([self.cp_rs1_sign, self.cp_rs2_sign,
self.cp_rd_sign])
@vsc.covergroup
class div_cg(object):
def __init__(self):
super().__init__()
self.instr = None
self.cp_rs1 = vsc.coverpoint(lambda: self.instr.rs1,
cp_t=vsc.enum_t(riscv_reg_t))
self.cp_rs2 = vsc.coverpoint(lambda: self.instr.rs2,
cp_t=vsc.enum_t(riscv_reg_t))
self.cp_rd = vsc.coverpoint(lambda: self.instr.rd,
cp_t=vsc.enum_t(riscv_reg_t))
self.cp_rs1_sign = vsc.coverpoint(lambda: self.instr.rs1_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_rs2_sign = vsc.coverpoint(lambda: self.instr.rs2_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_rd_sign = vsc.coverpoint(lambda: self.instr.rd_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_gpr_hazard = vsc.coverpoint(lambda: self.instr.gpr_hazard,
cp_t=vsc.enum_t(hazard_e))
self.cp_sign_cross = vsc.cross([self.cp_rs1_sign, self.cp_rs2_sign,
self.cp_rd_sign])
self.cp_div_result = vsc.coverpoint(lambda: self.instr.div_result,
cp_t=vsc.enum_t(div_result_e))
@vsc.covergroup
class divu_cg(object):
def __init__(self):
super().__init__()
self.instr = None
self.cp_rs1 = vsc.coverpoint(lambda: self.instr.rs1,
cp_t=vsc.enum_t(riscv_reg_t))
self.cp_rs2 = vsc.coverpoint(lambda: self.instr.rs2,
cp_t=vsc.enum_t(riscv_reg_t))
self.cp_rd = vsc.coverpoint(lambda: self.instr.rd,
cp_t=vsc.enum_t(riscv_reg_t))
self.cp_rs1_sign = vsc.coverpoint(lambda: self.instr.rs1_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_rs2_sign = vsc.coverpoint(lambda: self.instr.rs2_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_rd_sign = vsc.coverpoint(lambda: self.instr.rd_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_gpr_hazard = vsc.coverpoint(lambda: self.instr.gpr_hazard,
cp_t=vsc.enum_t(hazard_e))
self.cp_sign_cross = vsc.cross([self.cp_rs1_sign, self.cp_rs2_sign,
self.cp_rd_sign])
self.cp_div_result = vsc.coverpoint(lambda: self.instr.div_result,
cp_t=vsc.enum_t(div_result_ex_overflow_e))
@vsc.covergroup
class rem_cg(object):
def __init__(self):
super().__init__()
self.instr = None
self.cp_rs1 = vsc.coverpoint(lambda: self.instr.rs1,
cp_t=vsc.enum_t(riscv_reg_t))
self.cp_rs2 = vsc.coverpoint(lambda: self.instr.rs2,
cp_t=vsc.enum_t(riscv_reg_t))
self.cp_rd = vsc.coverpoint(lambda: self.instr.rd,
cp_t=vsc.enum_t(riscv_reg_t))
self.cp_rs1_sign = vsc.coverpoint(lambda: self.instr.rs1_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_rs2_sign = vsc.coverpoint(lambda: self.instr.rs2_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_rd_sign = vsc.coverpoint(lambda: self.instr.rd_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_gpr_hazard = vsc.coverpoint(lambda: self.instr.gpr_hazard,
cp_t=vsc.enum_t(hazard_e))
self.cp_sign_cross = vsc.cross([self.cp_rs1_sign, self.cp_rs2_sign,
self.cp_rd_sign])
self.cp_div_result = vsc.coverpoint(lambda: self.instr.div_result,
cp_t=vsc.enum_t(div_result_e))
@vsc.covergroup
class remu_cg(object):
def __init__(self):
super().__init__()
self.instr = None
self.cp_rs1 = vsc.coverpoint(lambda: self.instr.rs1,
cp_t=vsc.enum_t(riscv_reg_t))
self.cp_rs2 = vsc.coverpoint(lambda: self.instr.rs2,
cp_t=vsc.enum_t(riscv_reg_t))
self.cp_rd = vsc.coverpoint(lambda: self.instr.rd,
cp_t=vsc.enum_t(riscv_reg_t))
self.cp_rs1_sign = vsc.coverpoint(lambda: self.instr.rs1_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_rs2_sign = vsc.coverpoint(lambda: self.instr.rs2_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_rd_sign = vsc.coverpoint(lambda: self.instr.rd_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_gpr_hazard = vsc.coverpoint(lambda: self.instr.gpr_hazard,
cp_t=vsc.enum_t(hazard_e))
self.cp_sign_cross = vsc.cross([self.cp_rs1_sign, self.cp_rs2_sign,
self.cp_rd_sign])
self.cp_div_result = vsc.coverpoint(lambda: self.instr.div_result,
cp_t=vsc.enum_t(div_result_ex_overflow_e))
'''CSR instructions'''
@vsc.covergroup
@ -1402,7 +1592,7 @@ class riscv_instr_cover_group:
super().__init__()
self.instr = None
self.cp_opcode = vsc.coverpoint(lambda: self.instr.binary[7:2],
self.cp_opcode = vsc.coverpoint(lambda: self.instr.binary[6:2],
bins={
"a": vsc.bin_array([], [0, 31])
}
@ -1430,11 +1620,430 @@ class riscv_instr_cover_group:
}
)
@vsc.covergroup
class hint_cg(object):
def __init__(self):
super().__init__()
self.instr = None
self.cp_hint0 = vsc.coverpoint(lambda: self.instr.binary[15:0],
bins=dict(addi=vsc.wildcard_bin_array([],
"0b0000_1xxx_x000_0001",
"0b0000_x1xx_x000_0001",
"0b0000_xx1x_x000_0001",
"0b0000_xxx1_x000_0001",
"0b0000_xxxx_1000_0001")))
self.cp_hint1 = vsc.coverpoint(lambda: self.instr.binary[15:0],
bins=dict(li=vsc.wildcard_bin(
"0b010x_0000_0xxx_xx01")))
self.cp_hint2 = vsc.coverpoint(lambda: self.instr.binary[15:0],
bins=dict(lui=vsc.wildcard_bin(
"0b011x_0000_0xxx_xx01")))
self.cp_hint3 = vsc.coverpoint(lambda: self.instr.binary[15:0],
bins=dict(srli64=vsc.wildcard_bin(
"0b1000_00xx_x000_0001")))
self.cp_hint4 = vsc.coverpoint(lambda: self.instr.binary[15:0],
bins=dict(srai64=vsc.wildcard_bin(
"0b1000_01xx_x000_0001")))
self.cp_hint5 = vsc.coverpoint(lambda: self.instr.binary[15:0],
bins=dict(slli=vsc.wildcard_bin(
"0b000x_0000_0xxx_xx10")))
self.cp_hint6 = vsc.coverpoint(lambda: self.instr.binary[15:0],
bins=dict(slli64=vsc.wildcard_bin(
"0b0000_xxxx_x000_0010")))
self.cp_hint7 = vsc.coverpoint(lambda: self.instr.binary[15:0],
bins=dict(mv=vsc.wildcard_bin_array([],
"0b1000_0000_01xx_xx10",
"0b1000_0000_0x1x_xx10",
"0b1000_0000_0xx1_xx10",
"0b1000_0000_0xxx_1x10",
"0b1000_0000_0xxx_x110")))
self.cp_hint8 = vsc.coverpoint(lambda: self.instr.binary[15:0],
bins=dict(add=vsc.wildcard_bin_array([],
"0b1001_0000_01xx_xx10",
"0b1001_0000_0x1x_xx10",
"0b1001_0000_0xx1_xx10",
"0b1001_0000_0xxx_1x10",
"0b1001_0000_0xxx_x110"
)))
@vsc.covergroup
class illegal_compressed_instr_cg(object):
def __init__(self):
super().__init__()
self.instr = None
self.cp_point0 = vsc.coverpoint(lambda: self.instr.binary[15:0],
bins = dict(c_illegal=vsc.wildcard_bin(
"0b0000_0000_0000_0000")))
self.cp_point1 = vsc.coverpoint(lambda: self.instr.binary[15:0],
bins = dict(c_addi4spn=vsc.wildcard_bin_array([],
"0b0000_0000_000x_x100",
"0b0000_0000_000x_1x00",
"0b0000_0000_0001_xx00")))
self.cp_point2 = vsc.coverpoint(lambda: self.instr.binary[15:0],
bins = dict(c_addiw=vsc.wildcard_bin(
"0b001x_0000_0xxx_xx01")))
self.cp_point3 = vsc.coverpoint(lambda: self.instr.binary[15:0],
bins = dict(c_addi16sp=vsc.wildcard_bin(
"0b0110_0001_0000_0001")))
self.cp_point4 = vsc.coverpoint(lambda: self.instr.binary[15:0],
bins = dict(c_lui=vsc.wildcard_bin_array([],
"0b0110_xxxx_1000_0001",
"0b0110_xx1x_x000_0001",
"0b0110_x1xx_x000_0001",
"0b0110_1xxx_x000_0001")))
self.cp_point5 = vsc.coverpoint(lambda: self.instr.binary[15:0],
bins = dict(c_reserv_0=vsc.wildcard_bin(
"0b1001_11xx_x10x_xx01")))
self.cp_point6 = vsc.coverpoint(lambda: self.instr.binary[15:0],
bins = dict(c_reserv_1=vsc.wildcard_bin(
"0b1001_11xx_x11x_xx01")))
self.cp_point7 = vsc.coverpoint(lambda: self.instr.binary[15:0],
bins = dict(c_jr=vsc.wildcard_bin(
"0b1000_0000_0000_0010")))
self.cp_point8 = vsc.coverpoint(lambda: self.instr.binary[15:0],
bins = dict(c_lwsp=vsc.wildcard_bin(
"0b010x_0000_0xxx_xx10")))
self.cp_point9 = vsc.coverpoint(lambda: self.instr.binary[15:0],
bins = dict(c_lqsp=vsc.wildcard_bin(
"0b001x_0000_0xxx_xx10")))
self.cp_point10 = vsc.coverpoint(lambda: self.instr.binary[15:0],
bins = dict(c_ldsp=vsc.wildcard_bin(
"0b011x_0000_0xxx_xx10")))
'''Compressed instructions'''
@vsc.covergroup
class compressed_opcode_cg(object):
# TODO issue with iff parameter
def __init__(self):
super().__init__()
self.instr = None
'''self.cp_opcode = vsc.coverpoint(lambda: self.instr.binary[15:0],
bins={
"a": vsc.bin_array([], [0, 31])
}
)'''
@vsc.covergroup
class c_lw_cg(object):
def __init__(self):
super().__init__()
self.instr = None
self.cp_rs1 = vsc.coverpoint(lambda: self.instr.rs1,
cp_t=vsc.enum_t(compressed_gpr))
self.cp_rd = vsc.coverpoint(lambda: self.instr.rd,
cp_t=vsc.enum_t(compressed_gpr))
self.cp_gpr_hazard = vsc.coverpoint(lambda: self.instr.gpr_hazard,
cp_t=vsc.enum_t(hazard_e))
self.cp_lsu_hazard = vsc.coverpoint(lambda: self.instr.lsu_hazard,
cp_t=vsc.enum_t(branch_hazard_e))
@vsc.covergroup
class c_lwsp_cg(object):
def __init__(self):
super().__init__()
self.instr = None
self.cp_rd = vsc.coverpoint(lambda: self.instr.rd,
cp_t=vsc.enum_t(compressed_gpr))
@vsc.covergroup
class c_sw_cg(object):
def __init__(self):
super().__init__()
self.instr = None
self.cp_rs1 = vsc.coverpoint(lambda: self.instr.rs1,
cp_t=vsc.enum_t(compressed_gpr))
self.cp_rs2 = vsc.coverpoint(lambda: self.instr.rs2,
cp_t=vsc.enum_t(compressed_gpr))
self.cp_gpr_hazard = vsc.coverpoint(lambda: self.instr.gpr_hazard,
cp_t=vsc.enum_t(branch_hazard_e))
self.cp_lsu_hazard = vsc.coverpoint(lambda: self.instr.lsu_hazard,
cp_t=vsc.enum_t(store_lsu_hazard_e))
@vsc.covergroup
class c_swsp_cg(object):
def __init__(self):
super().__init__()
self.instr = None
self.cp_rs2 = vsc.coverpoint(lambda: self.instr.rs2,
cp_t=vsc.enum_t(compressed_gpr))
@vsc.covergroup
class c_addi4spn_cg(object):
def __init__(self):
super().__init__()
self.instr = None
self.cp_rd = vsc.coverpoint(lambda: self.instr.rd,
cp_t=vsc.enum_t(compressed_gpr))
self.cp_gpr_hazard = vsc.coverpoint(lambda: self.instr.gpr_hazard,
cp_t=vsc.enum_t(store_lsu_hazard_e))
@vsc.covergroup
class c_addi_cg(object):
def __init__(self):
super().__init__()
self.instr = None
self.cp_rd = vsc.coverpoint(lambda: self.instr.rd,
cp_t=vsc.enum_t(riscv_reg_ex_zero_t))
self.cp_imm_sign = vsc.coverpoint(lambda: self.instr.imm_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_gpr_hazard = vsc.coverpoint(lambda: self.instr.gpr_hazard,
cp_t=vsc.enum_t(store_lsu_hazard_e))
@vsc.covergroup
class c_addi16sp_cg(object):
def __init__(self):
super().__init__()
self.instr = None
self.cp_imm_sign = vsc.coverpoint(lambda: self.instr.imm_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_gpr_hazard = vsc.coverpoint(lambda: self.instr.gpr_hazard,
cp_t=vsc.enum_t(store_lsu_hazard_e))
@vsc.covergroup
class c_li_cg(object):
def __init__(self):
super().__init__()
self.instr = None
self.cp_rd = vsc.coverpoint(lambda: self.instr.rd,
cp_t=vsc.enum_t(riscv_reg_ex_zero_t))
self.cp_imm_sign = vsc.coverpoint(lambda: self.instr.imm_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_gpr_hazard = vsc.coverpoint(lambda: self.instr.gpr_hazard,
cp_t=vsc.enum_t(store_lsu_hazard_e))
@vsc.covergroup
class c_lui_cg(object):
def __init__(self):
super().__init__()
self.instr = None
self.cp_rd = vsc.coverpoint(lambda: self.instr.rd,
cp_t=vsc.enum_t(riscv_reg_ex_zero_sp_t))
@vsc.covergroup
class c_sub_cg(object):
def __init__(self):
super().__init__()
self.instr = None
self.cp_rd = vsc.coverpoint(lambda: self.instr.rd,
cp_t=vsc.enum_t(compressed_gpr))
self.cp_rs2 = vsc.coverpoint(lambda: self.instr.rs2,
cp_t=vsc.enum_t(compressed_gpr))
self.cp_gpr_hazard = vsc.coverpoint(lambda: self.instr.gpr_hazard,
cp_t=vsc.enum_t(hazard_e))
@vsc.covergroup
class c_add_cg(object):
def __init__(self):
super().__init__()
self.instr = None
self.cp_rs2 = vsc.coverpoint(lambda: self.instr.rs2,
cp_t=vsc.enum_t(riscv_reg_ex_zero_t))
self.cp_rd = vsc.coverpoint(lambda: self.instr.rd,
cp_t=vsc.enum_t(riscv_reg_ex_zero_t))
self.cp_rs2_sign = vsc.coverpoint(lambda: self.instr.rs2_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_gpr_hazard = vsc.coverpoint(lambda: self.instr.gpr_hazard,
cp_t=vsc.enum_t(hazard_e))
@vsc.covergroup
class c_mv_cg(object):
def __init__(self):
super().__init__()
self.instr = None
self.cp_rs2 = vsc.coverpoint(lambda: self.instr.rs2,
cp_t=vsc.enum_t(riscv_reg_ex_zero_t))
self.cp_rd = vsc.coverpoint(lambda: self.instr.rd,
cp_t=vsc.enum_t(riscv_reg_ex_zero_t))
self.cp_rs2_sign = vsc.coverpoint(lambda: self.instr.rs2_sign,
cp_t=vsc.enum_t(operand_sign_e))
self.cp_gpr_hazard = vsc.coverpoint(lambda: self.instr.gpr_hazard,
cp_t=vsc.enum_t(hazard_e))
@vsc.covergroup
class c_andi_cg(object):
def __init__(self):
super().__init__()
self.instr = None
self.cp_rs1 = vsc.coverpoint(lambda: self.instr.rs1,
cp_t=vsc.enum_t(compressed_gpr))
self.cp_gpr_hazard = vsc.coverpoint(lambda: self.instr.gpr_hazard,
cp_t=vsc.enum_t(branch_hazard_e))
self.cp_imm_sign = vsc.coverpoint(lambda: self.instr.imm_sign,
cp_t=vsc.enum_t(operand_sign_e))
@vsc.covergroup
class c_xor_cg(object):
def __init__(self):
super().__init__()
self.instr = None
self.cp_rd = vsc.coverpoint(lambda: self.instr.rd,
cp_t=vsc.enum_t(compressed_gpr))
self.cp_rs2 = vsc.coverpoint(lambda: self.instr.rs2,
cp_t=vsc.enum_t(compressed_gpr))
self.cp_gpr_hazard = vsc.coverpoint(lambda: self.instr.gpr_hazard,
cp_t=vsc.enum_t(hazard_e))
@vsc.covergroup
class c_or_cg(object):
def __init__(self):
super().__init__()
self.instr = None
self.cp_rd = vsc.coverpoint(lambda: self.instr.rd,
cp_t=vsc.enum_t(compressed_gpr))
self.cp_rs2 = vsc.coverpoint(lambda: self.instr.rs2,
cp_t=vsc.enum_t(compressed_gpr))
self.cp_gpr_hazard = vsc.coverpoint(lambda: self.instr.gpr_hazard,
cp_t=vsc.enum_t(hazard_e))
@vsc.covergroup
class c_and_cg(object):
def __init__(self):
super().__init__()
self.instr = None
self.cp_rd = vsc.coverpoint(lambda: self.instr.rd,
cp_t=vsc.enum_t(compressed_gpr))
self.cp_rs2 = vsc.coverpoint(lambda: self.instr.rs2,
cp_t=vsc.enum_t(compressed_gpr))
self.cp_gpr_hazard = vsc.coverpoint(lambda: self.instr.gpr_hazard,
cp_t=vsc.enum_t(hazard_e))
@vsc.covergroup
class c_beqz_cg(object):
def __init__(self):
super().__init__()
self.instr = None
self.cp_rs1 = vsc.coverpoint(lambda: self.instr.rs1,
cp_t=vsc.enum_t(compressed_gpr))
self.cp_gpr_hazard = vsc.coverpoint(lambda: self.instr.gpr_hazard,
cp_t=vsc.enum_t(branch_hazard_e))
self.cp_imm_sign = vsc.coverpoint(lambda: self.instr.imm_sign,
cp_t=vsc.enum_t(operand_sign_e))
@vsc.covergroup
class c_bnez_cg(object):
def __init__(self):
super().__init__()
self.instr = None
self.cp_rs1 = vsc.coverpoint(lambda: self.instr.rs1,
cp_t=vsc.enum_t(compressed_gpr))
self.cp_gpr_hazard = vsc.coverpoint(lambda: self.instr.gpr_hazard,
cp_t=vsc.enum_t(branch_hazard_e))
self.cp_imm_sign = vsc.coverpoint(lambda: self.instr.imm_sign,
cp_t=vsc.enum_t(operand_sign_e))
@vsc.covergroup
class c_srli_cg(object):
def __init__(self):
super().__init__()
self.instr = None
self.cp_rs1 = vsc.coverpoint(lambda: self.instr.rs1,
cp_t=vsc.enum_t(compressed_gpr))
self.cp_gpr_hazard = vsc.coverpoint(lambda: self.instr.gpr_hazard,
cp_t=vsc.enum_t(branch_hazard_e))
@vsc.covergroup
class c_srai_cg(object):
def __init__(self):
super().__init__()
self.instr = None
self.cp_rs1 = vsc.coverpoint(lambda: self.instr.rs1,
cp_t=vsc.enum_t(compressed_gpr))
self.cp_gpr_hazard = vsc.coverpoint(lambda: self.instr.gpr_hazard,
cp_t=vsc.enum_t(branch_hazard_e))
@vsc.covergroup
class c_slli_cg(object):
def __init__(self):
super().__init__()
self.instr = None
self.cp_rd = vsc.coverpoint(lambda: self.instr.rd,
cp_t=vsc.enum_t(riscv_reg_ex_zero_t))
self.cp_gpr_hazard = vsc.coverpoint(lambda: self.instr.gpr_hazard,
cp_t=vsc.enum_t(branch_hazard_e))
@vsc.covergroup
class c_j_cg(object):
def __init__(self):
super().__init__()
self.instr = None
self.cp_imm_sign = vsc.coverpoint(lambda: self.instr.imm_sign,
cp_t=vsc.enum_t(operand_sign_e))
@vsc.covergroup
class c_jal_cg(object):
def __init__(self):
super().__init__()
self.instr = None
self.cp_imm_sign = vsc.coverpoint(lambda: self.instr.imm_sign,
cp_t=vsc.enum_t(operand_sign_e))
@vsc.covergroup
class c_jr_cg(object):
def __init__(self):
super().__init__()
self.instr = None
self.cp_rs1 = vsc.coverpoint(lambda: self.instr.rs1,
cp_t=vsc.enum_t(riscv_reg_ex_zero_t))
self.cp_rs1_align = vsc.coverpoint(lambda: self.instr.rs1_value[1:0],
bins={
"Zero" : vsc.bin(0),
"One" : vsc.bin(1),
"Two" : vsc.bin(2),
"Three": vsc.bin(3)
})
@vsc.covergroup
class c_jalr_cg(object):
def __init__(self):
super().__init__()
self.instr = None
self.cp_rs1 = vsc.coverpoint(lambda: self.instr.rs1,
cp_t=vsc.enum_t(riscv_reg_ex_zero_t))
self.cp_rs1_align = vsc.coverpoint(lambda: self.instr.rs1_value[1:0],
bins={
"Zero" : vsc.bin(0),
"One" : vsc.bin(1),
"Two" : vsc.bin(2),
"Three": vsc.bin(3)
})
self.cp_rd_align = vsc.coverpoint(lambda: self.instr.rd_value[1],
bins={
"Aligned" : vsc.bin(1),
"Not-aligned": vsc.bin(0)
})
def cg_instantiation(self):
self.opcode_cg_i = self.opcode_cg()
self.csrrw_cg_i = self.csrrw_cg()
self.rv32i_misc_cg_i = self.rv32i_misc_cg()
self.mepc_alignment_cg_i = self.mepc_alignment_cg()
# self.compressed_opcode_cg_i = self.compressed_opcode_cg()
self.beq_cg_i = self.beq_cg()
self.jal_cg_i = self.jal_cg()
self.lui_cg_i = self.lui_cg()
@ -1458,13 +2067,56 @@ class riscv_instr_cover_group:
self.srai_cg_i = self.srai_cg()
self.slt_cg_i = self.slt_cg()
self.slli_cg_i = self.slli_cg()
self.mul_cg_i = self.mul_cg()
self.mulh_cg_i = self.mulh_cg()
self.mulhsu_cg_i = self.mulhsu_cg()
self.mulhu_cg_i = self.mulhu_cg()
self.div_cg_i = self.div_cg()
self.divu_cg_i = self.divu_cg()
self.rem_cg_i = self.rem_cg()
self.remu_cg_i = self.remu_cg()
self.c_lw_cg_i = self.c_lw_cg()
self.c_lwsp_cg_i = self.c_lwsp_cg()
self.c_sw_cg_i = self.c_sw_cg()
self.c_swsp_cg_i = self.c_swsp_cg()
self.c_addi4spn_cg_i = self.c_addi4spn_cg()
self.c_addi_cg_i = self.c_addi_cg()
self.c_addi16sp_cg_i = self.c_addi16sp_cg()
self.c_li_cg_i = self.c_li_cg()
self.c_lui_cg_i = self.c_lui_cg()
self.c_sub_cg_i = self.c_sub_cg()
self.c_add_cg_i = self.c_add_cg()
self.c_mv_cg_i = self.c_mv_cg()
self.c_andi_cg_i = self.c_andi_cg()
self.c_xor_cg_i = self.c_xor_cg()
self.c_or_cg_i = self.c_or_cg()
self.c_and_cg_i = self.c_and_cg()
self.c_beqz_cg_i = self.c_beqz_cg()
self.c_bnez_cg_i = self.c_bnez_cg()
self.c_srli_cg_i = self.c_srli_cg()
self.c_srai_cg_i = self.c_srai_cg()
self.c_slli_cg_i = self.c_slli_cg()
self.c_j_cg_i = self.c_j_cg()
self.c_jal_cg_i = self.c_jal_cg()
self.c_jr_cg_i = self.c_jr_cg()
self.c_jalr_cg_i = self.c_jalr_cg()
self.hint_cg_i = self.hint_cg()
self.illegal_compressed_instr_cg_i = self.illegal_compressed_instr_cg()
def sample(self, instr):
self.instr_cnt += 1
if self.instr_cnt > 1:
instr.check_hazard_condition(self.pre_instr)
# TODO: sampling for hint, compressed, and illegal_compressed insts
if instr.binary[2:0] == 3:
# TODO: sampling for compressed_instr_cg
if ((instr.binary[1:0] != 3) and (riscv_instr_group_t.RV32C in rcs.supported_isa)):
# self.compressed_opcode_cg_i.instr = instr
# self.compressed_opcode_cg_i.sample()
self.hint_cg_i.instr = instr
self.hint_cg_i.sample()
self.illegal_compressed_instr_cg_i.instr = instr
self.illegal_compressed_instr_cg_i.sample()
if instr.binary[1:0] == 3:
self.opcode_cg_i.instr = instr
self.opcode_cg_i.sample()
try:
@ -1474,6 +2126,9 @@ class riscv_instr_cover_group:
except Exception:
logging.info("Covergroup for instr {} is not supported yet".format(
instr.instr.name))
# Trace the error if there is an Exception
logging.info("Traceback error log: {}".format(traceback.format_exc()))
if instr.group.name == "RV32I":
self.rv32i_misc_cg_i.instr = instr
self.rv32i_misc_cg_i.sample()

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
@ -9,7 +8,6 @@ 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
@ -22,19 +20,48 @@ 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_category_t, satp_mode_t,
mem_region_t)
mem_region_t, vreg_init_method_t)
# ----------------------------------------------------------------------------
# RISC-V assembly program generator configuration class
# ----------------------------------------------------------------------------
@vsc.randobj
class riscv_instr_gen_config:
def __init__(self):
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
# ---------------------------------------------------------------------------
# Random instruction generation settings
# ---------------------------------------------------------------------------
# Instruction count of the main program
self.main_program_instr_cnt = vsc.rand_int32_t()
# Instruction count of each sub-program
self.sub_program_instr_cnt = []
# Instruction count of the debug rom
self.debug_program_instr_cnt = 0
# Instruction count of debug sub-programs
self.debug_sub_program_instr_cnt = []
# Pattern of data section: RAND_DATA, ALL_ZERO, INCR_VAL
self.data_page_pattern = vsc.rand_enum_t(data_pattern_t)
# Initialization of the vregs
# SAME_VALUES_ALL_ELEMS - Using vmv.v.x to fill all the elements of the vreg with
# the same value as the one in the GPR selected
# RANDOM_VALUES_VMV - Using vmv.v.x + vslide1up.vx to randomize the contents
# of each vector element
# RANDOM_VALUES_LOAD - Using vle.v, same approach as RANDOM_VALUES_VMV but more
# efficient for big VLEN
self.vreg_init_method = vreg_init_method_t.RANDOM_VALUES_VMV
# Maximum directed instruction stream sequence count
self.max_directed_instr_stream_seq = 20
self.init_delegation()
self.argv = self.parse_args()
self.args_dict = vars(self.argv)
@ -42,12 +69,16 @@ class riscv_instr_gen_config:
global rcs
rcs = import_module("pygen_src.target." + self.argv.target + ".riscv_core_setting")
# Dict for delegation configuration for each exception and interrupt
# When the bit is 1, the corresponding delegation is enabled.
# TODO
self.m_mode_exception_delegation = {}
self.s_mode_exception_delegation = {}
self.m_mode_interrupt_delegation = {}
self.s_mode_interrupt_delegation = {}
# init_privileged_mode default to MACHINE_MODE
# TODO: remove defult machine_mode once all modes get supported
self.init_privileged_mode = privileged_mode_t.MACHINE_MODE
self.mstatus = vsc.rand_bit_t(rcs.XLEN - 1)
@ -57,6 +88,8 @@ class riscv_instr_gen_config:
self.ustatus = vsc.rand_bit_t(rcs.XLEN - 1)
self.uie = vsc.rand_bit_t(rcs.XLEN - 1)
# Key fields in xSTATUS
# Memory protection bits
self.mstatus_mprv = vsc.rand_bit_t(1)
self.mstatus_mxr = vsc.rand_bit_t(1)
self.mstatus_sum = vsc.rand_bit_t(1)
@ -65,25 +98,55 @@ class riscv_instr_gen_config:
self.mstatus_vs = vsc.rand_bit_t(2)
self.mtvec_mode = vsc.rand_enum_t(mtvec_mode_t)
self.tvec_alignment = vsc.rand_uint8_t(self.argv.tvec_alignment)
# TVEC alignment
# This value is the log_2 of the byte-alignment of TVEC.BASE field
# As per RISC-V privileged spec, default will be set to 2 (4-byte aligned)
self.tvec_alignment = vsc.rand_uint32_t(self.argv.tvec_alignment)
# Floating point rounding mode
self.fcsr_rm = vsc.rand_enum_t(f_rounding_mode_t)
# Enable sfence.vma instruction
self.enable_sfence = vsc.rand_bit_t(1)
# Reserved register
# Reserved for various hardcoded routines
self.gpr = vsc.rand_list_t(vsc.enum_t(riscv_reg_t), sz=4)
# Used by any DCSR operations inside of the debug rom.
# Also used by the PMP generation.
self.scratch_reg = vsc.rand_enum_t(riscv_reg_t)
# Reg used exclusively by the PMP exception handling routine.
# Can overlap with the other GPRs used in the random generation,
# as PMP exception handler is hardcoded and does not include any
# random instructions.
self.pmp_reg = vsc.rand_enum_t(riscv_reg_t)
# Use a random register for stack pointer/thread pointer
self.sp = vsc.rand_enum_t(riscv_reg_t)
self.tp = vsc.rand_enum_t(riscv_reg_t)
self.ra = vsc.rand_enum_t(riscv_reg_t)
# Options for privileged mode CSR checking
# Below checking can be made optional as the ISS implementation
# could be different with the processor.
self.check_misa_init_val = 0
self.check_xstatus = 1
self.virtual_addr_translation_on = 0
# Virtual address translation is on for this test
self.virtual_addr_translation_on = vsc.rand_bit_t(1)
# Commenting out for now
# vector_cfg = riscv_vector_cfg # TODO
# vector_cfg = riscv_vector_cfg # TODO
# pmp_cfg = riscv_pmp_cfg # TODO
# Stack section word length
self.stack_len = 5000
# -----------------------------------------------------------------------------
# User space memory region and stack setting
# -----------------------------------------------------------------------------
self.mem_region = vsc.list_t(mem_region_t())
self.amo_region = vsc.list_t(mem_region_t())
self.s_mem_region = vsc.list_t(mem_region_t())
@ -92,37 +155,52 @@ class riscv_instr_gen_config:
self.amo_region.extend([mem_region_t(name = "amo_0", size_in_bytes = 64, xwr = 8)])
self.s_mem_region.extend([mem_region_t(name = "s_region_0", size_in_bytes = 4096, xwr = 8),
mem_region_t(name = "s_region_1", size_in_bytes = 4096, xwr = 8)])
self.stack_len = 5000
# Kernel Stack section word length
self.kernel_stack_len = 4000
# Number of instructions for each kernel program
self.kernel_program_instr_cnt = 400
# list of main implemented CSRs
# List of all the main implemented CSRs that the boot privilege mode cannot access
# e.g. these CSRs are in higher privilege modes - access should raise an exception
self.invalid_priv_mode_csrs = []
# -----------------------------------------------------------------------------
# Command line options or control knobs
# -----------------------------------------------------------------------------
# Main options for RISC-V assembly program generation
# Number of sub-programs per test
self.num_of_sub_program = self.argv.num_of_sub_program
self.instr_cnt = self.argv.instr_cnt
self.num_of_tests = self.argv.num_of_tests
# For tests doesn't involve load/store, the data section generation could be skipped
self.no_data_page = self.argv.no_data_page
self.no_branch_jump = self.argv.no_branch_jump
self.no_load_store = self.argv.no_load_store
self.no_csr_instr = self.argv.no_csr_instr
self.no_ebreak = self.argv.no_ebreak
self.no_dret = self.argv.no_dret
self.no_fence = self.argv.no_fence
self.no_wfi = self.argv.no_wfi
# Options to turn off some specific types of instructions
self.no_branch_jump = self.argv.no_branch_jump # No branch/jump instruction
self.no_load_store = self.argv.no_load_store # No load/store instruction
self.no_csr_instr = self.argv.no_csr_instr # No csr instruction
self.no_ebreak = self.argv.no_ebreak # No ebreak instruction
self.no_dret = self.argv.no_dret # No dret instruction
self.no_fence = self.argv.no_fence # No fence instruction
self.no_wfi = self.argv.no_wfi # No WFI instruction
self.enable_unaligned_load_store = self.argv.enable_unaligned_load_store
self.illegal_instr_ratio = self.argv.illegal_instr_ratio
self.hint_instr_ratio = self.argv.hint_instr_ratio
# Number of harts to be simulated, must be <= NUM_HARTS
if self.argv.num_of_harts is None:
self.num_of_harts = rcs.NUM_HARTS
else:
self.num_of_harts = self.argv.num_of_harts
# Use SP as stack pointer
self.fix_sp = vsc.bit_t(1)
self.fix_sp = self.argv.fix_sp
# Use push/pop section for data pages
self.use_push_data_section = self.argv.use_push_data_section
# Directed boot privileged mode, u, m, s
self.boot_mode_opts = self.argv.boot_mode
# self.isa = self.argv.isa
if self.boot_mode_opts:
logging.info("Got boot mode option - %0s", self.boot_mode_opts)
logging.info("Got boot mode option - {}".format(self.boot_mode_opts))
if self.boot_mode_opts == "m":
self.init_privileged_mode = privileged_mode_t.MACHINE_MODE
elif self.boot_mode_opts == "s":
@ -130,50 +208,89 @@ class riscv_instr_gen_config:
elif self.boot_mode_opts == "u":
self.init_privileged_mode = privileged_mode_t.USER_MODE
else:
logging.error("Illegal boot mode option - %0s", self.boot_mode_opts)
logging.error("Illegal boot mode option - {}".format(self.boot_mode_opts))
self.enable_page_table_exception = self.argv.enable_page_table_exception
self.no_directed_instr = self.argv.no_directed_instr
self.asm_test_suffix = self.argv.asm_test_suffix
# Enable interrupt bit in MSTATUS (MIE, SIE, UIE)
self.enable_interrupt = self.argv.enable_interrupt
self.enable_nested_interrupt = self.argv.enable_nested_interrupt
# We need a separate control knob for enabling timer interrupts, as Spike
# throws an exception if xIE.xTIE is enabled
self.enable_timer_irq = self.argv.enable_timer_irq
# Generate a bare program without any init/exit/error handling/page table routines
# The generated program can be integrated with a larger program.
# Note that the bare mode program is not expected to run in standalone mode
self.bare_program_mode = self.argv.bare_program_mode
# Enable accessing illegal CSR instruction
# - Accessing non-existence CSR
# - Accessing CSR with wrong privileged mode
self.enable_illegal_csr_instruction = self.argv.enable_illegal_csr_instruction
# Enable accessing CSRs at an invalid privilege level
self.enable_access_invalid_csr_level = self.argv.enable_access_invalid_csr_level
# Enable misaligned instruction (caused by JALR instruction)
self.enable_misaligned_instr = self.argv.enable_misaligned_instr
# Enable some dummy writes to main system CSRs (xSTATUS/xIE) at beginning of test
# to check repeated writes
self.enable_dummy_csr_write = self.argv.enable_dummy_csr_write
self.randomize_csr = self.argv.randomize_csr
# sfence support
self.allow_sfence_exception = self.argv.allow_sfence_exception
# Interrupt/Exception Delegation
self.no_delegation = self.argv.no_delegation
self.force_m_delegation = self.argv.force_m_delegation
self.force_s_delegation = self.argv.force_s_delegation
self.support_supervisor_mode = 0
self.support_supervisor_mode = 0 # TODO
self.disable_compressed_instr = self.argv.disable_compressed_instr
self.require_signature_addr = self.argv.require_signature_addr
if self.require_signature_addr:
self.signature_addr = int(self.argv.signature_addr, 16)
else:
self.signature_addr = 0xdeadbeef
# Enable a full or empty debug_rom section.
# Full debug_rom will contain random instruction streams.
# Empty debug_rom will contain just dret instruction and will return immediately.
# Will be empty by default.
self.gen_debug_section = self.argv.gen_debug_section
# Enable generation of a directed sequence of instructions containing
# ebreak inside the debug_rom.
# Disabled by default.
self.enable_ebreak_in_debug_rom = self.argv.enable_ebreak_in_debug_rom
# Enable setting dcsr.ebreak(m/s/u)
self.set_dcsr_ebreak = self.argv.set_dcsr_ebreak
# Number of sub programs in the debug rom
self.num_debug_sub_program = self.argv.num_debug_sub_program
# Enable debug single stepping
self.enable_debug_single_step = self.argv.enable_debug_single_step
self.single_step_iterations = 0
# Number of single stepping iterations
self.single_step_iterations = vsc.rand_uint32_t()
# Enable mstatus.tw bit - causes u-mode WFI to raise illegal instruction exceptions
self.set_mstatus_tw = self.argv.set_mstatus_tw
# Enable users to set mstatus.mprv to enable privilege checks on memory accesses.
self.set_mstatus_mprv = vsc.bit_t(1)
self.set_mstatus_mprv = self.argv.set_mstatus_mprv
self.min_stack_len_per_program = 10 * (rcs.XLEN / 8)
self.max_stack_len_per_program = 16 * (rcs.XLEN / 8)
# Stack space allocated to each program, need to be enough to store necessary context
# Example: RA, SP, T0
self.min_stack_len_per_program = 10 * (rcs.XLEN // 8)
self.max_stack_len_per_program = 16 * (rcs.XLEN // 8)
# Maximum branch distance, avoid skipping large portion of the code
self.max_branch_step = 20
# Reserved registers
self.reserved_regs = vsc.list_t(vsc.enum_t(riscv_reg_t))
# Floating point support
self.enable_floating_point = vsc.bit_t(1)
self.enable_floating_point = self.argv.enable_floating_point
# Vector extension support
self.enable_vector_extension = self.argv.enable_vector_extension
# Only generate vector instructions
self. vector_instr_only = vsc.bit_t(1)
# Bit manipulation extension support
self.enable_b_extension = self.argv.enable_b_extension
self.enable_bitmanip_groups = self.argv.enable_bitmanip_groups
# -----------------------------------------------------------------------------
# Command line options for instruction distribution control
# -----------------------------------------------------------------------------
self.dist_control_mode = 0
self.category_dist = {}
self.march_isa = self.argv.march_isa
@ -198,35 +315,26 @@ class riscv_instr_gen_config:
@vsc.constraint
def default_c(self):
# TODO Add constraint related to sub_program
self.main_program_instr_cnt in vsc.rangelist(vsc.rng(10, self.instr_cnt))
@vsc.constraint
def sp_tp_c(self):
if self.fix_sp:
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))
self.tp.not_inside(vsc.rangelist(riscv_reg_t.GP,
riscv_reg_t.RA, riscv_reg_t.ZERO))
def debug_mode_c(self):
# TODO
pass
# Keep the number of single step iterations relatively small
@vsc.constraint
def gpr_c(self):
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)
def debug_single_step_c(self):
# TODO
pass
# Boot privileged mode distribution
@vsc.constraint
def ra_c(self):
self.ra != riscv_reg_t.SP
self.ra != riscv_reg_t.TP
self.ra != riscv_reg_t.ZERO
@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))
def boot_privileged_mode_dist_c(self):
# Boot to higher privileged mode more often
# TODO
pass
@vsc.constraint
def mtvec_c(self):
@ -234,15 +342,10 @@ class riscv_instr_gen_config:
with vsc.if_then(self.mtvec_mode == mtvec_mode_t.DIRECT):
vsc.soft(self.tvec_alignment == 2)
with vsc.else_then():
# Setting MODE = Vectored may impose an additional alignmentconstraint on BASE,
# requiring up to 4×XLEN-byte alignment
vsc.soft(self.tvec_alignment == self.tvec_ceil)
@vsc.constraint
def floating_point_c(self):
with vsc.if_then(self.enable_floating_point):
self.mstatus_fs == 1
with vsc.else_then():
self.mstatus_fs == 0
@vsc.constraint
def mstatus_c(self):
with vsc.if_then(self.set_mstatus_mprv == 1):
@ -254,6 +357,124 @@ class riscv_instr_gen_config:
self.mstatus_sum == 0
self.mstatus_tvm == 0
# Exception delegation setting
@vsc.constraint
def exception_delegation_c(self):
# Do not delegate instruction page fault to supervisor/user mode because this may introduce
# dead loop. All the subsequent instruction fetches may fail and program cannot recover.
# TODO
pass
# Spike only supports a subset of exception and interrupt delegation
# You can modify this constraint if your ISS support different set of delegations
@vsc.constraint
def delegation_c(self):
# TODO
pass
@vsc.constraint
def ra_c(self):
self.ra != riscv_reg_t.SP
self.ra != riscv_reg_t.TP
self.ra != riscv_reg_t.ZERO
@vsc.constraint
def sp_tp_c(self):
with vsc.if_then(self.fix_sp == 1):
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))
self.tp.not_inside(vsc.rangelist(riscv_reg_t.GP,
riscv_reg_t.RA, riscv_reg_t.ZERO))
# This reg is used in various places throughout the generator,
# so need more conservative constraints on it.
@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))
# This reg is only used inside PMP exception routine,
# so we can be a bit looser with constraints.
@vsc.constraint
def reserved_pmp_reg_c(self):
# TODO
pass
@vsc.constraint
def gpr_c(self):
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 addr_translation_rnd_order_c(self):
# TODO
pass
@vsc.constraint
def addr_translation_c(self):
with vsc.if_then((self.init_privil_mode != privileged_mode_t.MACHINE_MODE) &
(self.SATP_MODE != satp_mode_t.BARE)):
self.virtual_addr_translation_on == 1
with vsc.else_then():
self.virtual_addr_translation_on == 0
@vsc.constraint
def floating_point_c(self):
with vsc.if_then(self.enable_floating_point == 1):
self.mstatus_fs == 1
with vsc.else_then():
self.mstatus_fs == 0
@vsc.constraint
def mstatus_vs_c(self):
# TODO
pass
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 # Default ratio
logging.info("Set dist[{}] = {}".format(category, self.category_dist[category]))
category = next(category_iter)
if category != riscv_instr_category_t(0):
break
# Initialize the exception/interrupt delegation associate array, set all delegation default to 0
def init_delegation(self):
# TODO
pass
def pre_randomize(self):
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):
# Setup the list all reserved registers
self.reserved_regs.extend((self.tp, self.sp, self.scratch_reg))
# Need to save all loop registers, and RA/T0
self.min_stack_len_per_program = 2 * (rcs.XLEN // 8)
logging.info("min_stack_len_per_program value = {}"
.format(self.min_stack_len_per_program))
self.check_setting() # check if the setting is legal
# WFI is not supported in umode
if self.init_privileged_mode == privileged_mode_t.USER_MODE:
self.no_wfi = 1
def check_setting(self):
support_64b = 0
support_128b = 0
@ -296,47 +517,8 @@ class riscv_instr_gen_config:
.format(rcs.SATP_MODE.name))
sys.exit("Supported SATP mode is not provided")
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 pre_randomize(self):
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.append(self.tp)
self.reserved_regs.append(self.sp)
self.reserved_regs.append(self.scratch_reg)
self.min_stack_len_per_program = 2 * (rcs.XLEN / 8)
logging.info("min_stack_len_per_program value = {}"
.format(self.min_stack_len_per_program))
self.check_setting() # check if the setting is legal
if self.init_privileged_mode == privileged_mode_t.USER_MODE:
logging.info("mode = USER_MODE")
self.no_wfi = 1
# Populate invalid_priv_mode_csrs with the main implemented CSRs for each supported privilege
# mode
def get_invalid_priv_lvl_csr(self):
invalid_lvl = []
# Debug CSRs are inaccessible from all but Debug Mode
@ -416,7 +598,7 @@ class riscv_instr_gen_config:
help = 'illegal_instr_ratio', type = int, default = 0)
parse.add_argument('--hint_instr_ratio', help = 'hint_instr_ratio', type = int, default = 0)
parse.add_argument('--num_of_harts', help = 'num_of_harts',
type = int, default = 1)
type = int)
parse.add_argument('--enable_unaligned_load_store',
help = 'enable_unaligned_load_store', choices = [0, 1],
type = int, default = 0)
@ -486,7 +668,6 @@ class riscv_instr_gen_config:
if ($value$plusargs("tvec_alignment=%0d", tvec_alignment)) begin
tvec_alignment.rand_mode(0);
end
vector_cfg = riscv_vector_cfg::type_id::create("vector_cfg");
pmp_cfg = riscv_pmp_cfg::type_id::create("pmp_cfg");
pmp_cfg.rand_mode(pmp_cfg.pmp_randomize);
@ -495,7 +676,6 @@ class riscv_instr_gen_config:
get_invalid_priv_lvl_csr();
'''
args = parse.parse_args()
return args

File diff suppressed because it is too large Load diff

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
@ -9,53 +8,83 @@ 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 re
import logging
import random
import sys
import random
import logging
import vsc
from importlib import import_module
from collections import defaultdict
from pygen_src.riscv_instr_gen_config import cfg
from pygen_src.riscv_instr_stream import riscv_rand_instr_stream
from pygen_src.riscv_illegal_instr import riscv_illegal_instr, illegal_instr_type_e
from pygen_src.riscv_instr_gen_config import cfg
from pygen_src.riscv_directed_instr_lib import riscv_pop_stack_instr, riscv_push_stack_instr
from pygen_src.riscv_instr_pkg import (pkg_ins, riscv_instr_name_t, riscv_reg_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")
# -----------------------------------------------------------------------------------------
# RISC-V instruction sequence
# This class is used to generate a single instruction sequence for a RISC-V assembly program.
# It's used by riscv_asm_program_gen to generate the main program and all sub-programs. The
# flow is explained below:
# For main program:
# - Generate instruction sequence body.
# - Post-process the load/store/branch instructions.
# - Insert the jump instructions to its sub-programs (done by riscv_asm_program_gen).
# For sub program:
# - Generate the stack push instructions which are executed when entering this program.
# - Generate instruction sequence body.
# - Generate the stack pop instructions which are executed before exiting this program.
# - Post-process the load/store/branch instructions.
# - Insert the jump instructions to its sub-programs (done by riscv_asm_program_gen).
# - Generate a return instruction at the end of the program.
# -----------------------------------------------------------------------------------------
class riscv_instr_sequence:
def __init__(self):
self.instr_cnt = 0
self.instr_cnt = 0 # Instruction count of this sequence
self.instr_stream = riscv_rand_instr_stream()
self.is_main_program = 0
self.is_debug_program = 0
self.label_name = ""
self.is_main_program = 0 # Main instruction streams
self.is_debug_program = 0 # Indicates whether sequence is debug program
self.label_name = "" # Label of the sequence (program name)
self.instr_string_list = [] # Save the instruction list
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
self.branch_idx = [None] * 30
self.instr_stack_enter = riscv_push_stack_instr()
self.instr_stack_exit = riscv_pop_stack_instr()
self.illegal_instr = riscv_illegal_instr()
def gen_instr(self, is_main_program, no_branch = 1):
# Main function to generate the instruction stream
# The main random instruction stream is generated by instr_stream.gen_instr(), which generates
# each instruction one by one with a separate randomization call. It's not done by a single
# randomization call for the entire instruction stream because this solution won't scale if
# we have hundreds of thousands of instructions to generate. The constraint solver slows down
# considerably as the instruction stream becomes longer. The downside is we cannot specify
# constraints between instructions. The way to solve it is to have a dedicated directed
# instruction stream for such scenarios, like hazard sequence.
def gen_instr(self, is_main_program, no_branch = 0):
self.is_main_program = is_main_program
self.instr_stream.initialize_instr_list(self.instr_cnt)
logging.info("Start generating %d instruction" % len(self.instr_stream.instr_list))
logging.info("Start generating {} instruction".format(len(self.instr_stream.instr_list)))
# Do not generate load/store instruction here
# The load/store instruction will be inserted as directed instruction stream
self.instr_stream.gen_instr(no_branch = no_branch, no_load_store = 1,
is_debug_program = self.is_debug_program)
if not is_main_program:
self.gen_stack_enter_instr()
self.gen_stack_exit_instr()
logging.info("Finishing instruction generation")
# Generate the stack push operations for this program
# It pushes the necessary context to the stack like RA, T0,loop registers etc. The stack
# pointer(SP) is reduced by the amount the stack space allocated to this program.
def gen_stack_enter_instr(self):
allow_branch = 0 if (self.illegal_instr_pct > 0 or self.hint_instr_pct > 0) else 1
allow_branch &= not cfg.no_branch_jump
@ -63,6 +92,7 @@ class riscv_instr_sequence:
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))
# Keep stack len word aligned to avoid unaligned load/store
self.program_stack_len % (rcs.XLEN // 8) == 0
except Exception:
logging.critical("Cannot randomize program_stack_len")
@ -79,50 +109,44 @@ class riscv_instr_sequence:
self.instr_stack_exit.gen_pop_stack_instr(self.program_stack_len,
self.instr_stack_enter.saved_regs)
'''
----------------------------------------------------------------------------------------------
Instruction post-process
# ----------------------------------------------------------------------------------------------
# Instruction post-process
Post-process is required for branch instructions:
Need to assign a valid branch target. This is done by picking a random instruction label in
this sequence and assigning to the branch instruction. All the non-atomic instructions
will have a unique numeric label as the local branch target identifier.
The atomic instruction streams don't have labels except for the first instruction. This is
to avoid branching into an atomic instruction stream which breaks its atomicy. The
definition of an atomic instruction stream here is a sequence of instructions which must be
executed in-order.
In this sequence, only forward branch is handled. The backward branch target is implemented
in a dedicated loop instruction sequence. Randomly choosing a backward branch target could
lead to dead loops in the absence of proper loop exiting conditions.
----------------------------------------------------------------------------------------------
'''
# Post-process is required for branch instructions:
# Need to assign a valid branch target. This is done by picking a random instruction label in
# this sequence and assigning to the branch instruction. All the non-atomic instructions
# will have a unique numeric label as the local branch target identifier.
# The atomic instruction streams don't have labels except for the first instruction. This is
# to avoid branching into an atomic instruction stream which breaks its atomicy. The
# definition of an atomic instruction stream here is a sequence of instructions which must be
# executed in-order.
# In this sequence, only forward branch is handled. The backward branch target is implemented
# in a dedicated loop instruction sequence. Randomly choosing a backward branch target could
# lead to dead loops in the absence of proper loop exiting conditions.
# ----------------------------------------------------------------------------------------------
def post_process_instr(self):
label_idx = 0
branch_cnt = 0
branch_idx = [None] * 30
j = 0
branch_target = defaultdict(lambda: None)
# Insert directed instructions, it's randomly mixed with the random instruction stream.
for instr in self.directed_instr:
self.instr_stream.insert_instr_stream(instr.instr_list)
'''
Assign an index for all instructions, these indexes wont change
even a new instruction is injected in the post process.
'''
# Assign an index for all instructions, these indexes wont change
# even a new instruction is injected in the post process.
for i in range(len(self.instr_stream.instr_list)):
self.instr_stream.instr_list[i].idx = label_idx
if(self.instr_stream.instr_list[i].has_label and
not(self.instr_stream.instr_list[i].atomic)):
if((self.illegal_instr_pct > 0) and
(self.instr_stream.instr_list[i].insert_illegal_instr == 0)):
'''
The illegal instruction generator always increase PC by 4 when resume execution,
need to make sure PC + 4 is at the correct instruction boundary.
'''
if(self.instr_stream.instr_list[i].is_compressed):
# The illegal instruction generator always increase PC by 4 when resume
# execution, need to make sure PC + 4 is at the correct instruction boundary.
if self.instr_stream.instr_list[i].is_compressed:
if(i < (len(self.instr_stream.instr_list) - 1)):
if(self.instr_stream.instr_list[i + 1].is_compressed):
if self.instr_stream.instr_list[i + 1].is_compressed:
self.instr_stream.instr_list[i].is_illegal_instr = random.randrange(
0, min(100, self.illegal_instr_pct))
else:
@ -130,54 +154,54 @@ class riscv_instr_sequence:
0, min(100, self.illegal_instr_pct))
if(self.hint_instr_pct > 0 and
(self.instr_stream.instr_list[i].is_illegal_instr == 0)):
if(self.instr_stream.instr_list[i].is_compressed):
if self.instr_stream.instr_list[i].is_compressed:
self.instr_stream.instr_list[i].is_hint_instr = random.randrange(
0, min(100, self.hint_instr_pct))
self.instr_stream.instr_list[i].label = "{}".format(label_idx)
self.instr_stream.instr_list[i].is_local_numeric_label = 1
label_idx += 1
# Generate branch target
for i in range(len(self.branch_idx)):
self.branch_idx[i] = random.randint(1, cfg.max_branch_step)
for i in range(len(branch_idx)):
branch_idx[i] = random.randint(1, cfg.max_branch_step)
while(j < len(self.instr_stream.instr_list)):
while j < len(self.instr_stream.instr_list):
if((self.instr_stream.instr_list[j].category == riscv_instr_category_t.BRANCH) and
(not self.instr_stream.instr_list[j].branch_assigned) and
(not self.instr_stream.instr_list[j].is_illegal_instr)):
'''
Post process the branch instructions to give a valid local label
Here we only allow forward branch to avoid unexpected infinite loop
The loop structure will be inserted with a separate routine using
reserved loop registers
'''
# Post process the branch instructions to give a valid local label
# Here we only allow forward branch to avoid unexpected infinite loop
# The loop structure will be inserted with a separate routine using
# reserved loop registers
branch_target_label = 0
# branch_byte_offset = 0
branch_target_label = self.instr_stream.instr_list[j].idx + \
self.branch_idx[branch_cnt]
branch_idx[branch_cnt]
if(branch_target_label >= label_idx):
branch_target_label = label_idx - 1
branch_cnt += 1
if(branch_cnt == len(self.branch_idx)):
if(branch_cnt == len(branch_idx)):
branch_cnt = 0
random.shuffle(self.branch_idx)
random.shuffle(branch_idx)
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)
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
# Remove the local label which is not used as branch target
if(self.instr_stream.instr_list[j].has_label and
self.instr_stream.instr_list[j].is_local_numeric_label):
idx = int(self.instr_stream.instr_list[j].label)
if(not branch_target[idx]):
if not branch_target[idx]:
self.instr_stream.instr_list[j].has_label = 0
j += 1
logging.info("Finished post-processing instructions")
# Inject a jump instruction stream
# This function is called by riscv_asm_program_gen with the target program label
# The jump routine is implmented with an atomic instruction stream(riscv_jump_instr). Similar
# to load/store instructions, JALR/JAL instructions also need a proper base address and offset
# as the jump target.
def insert_jump_instr(self):
# TODO riscv_jump_instr class implementation
"""
@ -194,6 +218,9 @@ class riscv_instr_sequence:
"""
pass
# Convert the instruction stream to the string format.
# Label is attached to the instruction if available, otherwise attach proper space to make
# the code indent consistent.
def generate_instr_stream(self, no_label = 0):
prefix = ''
string = ''
@ -208,15 +235,15 @@ class riscv_instr_sequence:
self.label_name), length = pkg_ins.LABEL_STR_LEN)
self.instr_stream.instr_list[i].has_label = 1
else:
if(self.instr_stream.instr_list[i].has_label):
if self.instr_stream.instr_list[i].has_label:
prefix = pkg_ins.format_string(string = '{}:'.format(
self.instr_stream.instr_list[i].label), length = pkg_ins.LABEL_STR_LEN)
else:
prefix = pkg_ins.format_string(string = " ", length = pkg_ins.LABEL_STR_LEN)
string = prefix + self.instr_stream.instr_list[i].convert2asm()
self.instr_string_list.append(string)
if(rcs.support_pmp and not re.search("main", self.label_name)):
self.instr_string_list.insert(0, ".align 2")
if(rcs.support_pmp and not re.search("main", self.label_name)):
self.instr_string_list.insert(0, ".align 2")
self.insert_illegal_hint_instr()
prefix = pkg_ins.format_string(str(i), pkg_ins.LABEL_STR_LEN)
if not self.is_main_program:

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
@ -10,6 +9,7 @@ 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 random
import logging
import sys
@ -20,15 +20,12 @@ from pygen_src.isa.riscv_instr import riscv_instr
from pygen_src.riscv_instr_gen_config import cfg
# Base class for RISC-V instruction stream
# A instruction stream here is a queue of RISC-V basic instructions.
# This class also provides some functions to manipulate the instruction stream, like insert a new
# instruction, mix two instruction streams etc.
@vsc.randobj
class riscv_instr_stream:
'''
Base class for RISC-V instruction stream
A instruction stream here is a queue of RISC-V basic instructions.
This class also provides some functions to manipulate the instruction stream, like insert a new
instruction, mix two instruction streams etc.
'''
def __init__(self):
self.instr_list = []
self.instr_cnt = 0
@ -40,6 +37,7 @@ class riscv_instr_stream:
self.reserved_rd = vsc.list_t(vsc.enum_t(riscv_reg_t))
self.hart = 0
# Initialize the instruction stream, create each instruction instance
def initialize_instr_list(self, instr_cnt):
self.instr_list.clear()
self.instr_cnt = instr_cnt
@ -50,12 +48,11 @@ class riscv_instr_stream:
instr = riscv_instr()
self.instr_list.append(instr)
# Insert an instruction to the existing instruction stream at the given index
# When index is -1, the instruction is injected at a random location
def insert_instr(self, instr, idx = -1):
"""
Insert an instruction to the existing instruction stream at the given index
When index is -1, the instruction is injected at a random location
"""
current_instr_cnt = len(self.instr_list)
# TODO
if idx == -1:
idx = random.randint(0, current_instr_cnt - 1)
while self.instr_list[idx].atomic:
@ -64,16 +61,14 @@ class riscv_instr_stream:
self.instr_list.append(instr)
return
elif idx > current_instr_cnt or idx < 0:
logging.error("Cannot insert instr:%0s at idx %0d", instr.convert2asm(), idx)
logging.error("Cannot insert instr:{} at idx {}".format(instr.convert2asm(), idx))
sys.exit(1)
self.instr_list.insert(idx, instr)
# Insert an instruction to the existing instruction stream at the given index
# When index is -1, the instruction is injected at a random location
# When replace is 1, the original instruction at the inserted position will be replaced
def insert_instr_stream(self, new_instr, idx = -1, replace = 0):
"""
Insert an instruction to the existing instruction stream at the given index
When index is -1, the instruction is injected at a random location
When replace is 1, the original instruction at the inserted position will be replaced
"""
current_instr_cnt = len(self.instr_list)
if current_instr_cnt == 0:
@ -97,7 +92,7 @@ class riscv_instr_stream:
logging.critical("Cannot inject the instruction")
sys.exit(1)
elif idx > current_instr_cnt or idx < 0:
logging.error("Cannot insert instr stream at idx %0d", idx)
logging.error("Cannot insert instr stream at idx {}".format(idx))
sys.exit(1)
# When replace is 1, the original instruction at this index will be removed.
# The label of the original instruction will be copied to the head
@ -117,17 +112,15 @@ class riscv_instr_stream:
self.instr_list = self.instr_list[0:idx] + new_instr + \
self.instr_list[idx:current_instr_cnt]
# Mix the input instruction stream with the original instruction, the instruction order is
# preserved. When 'contained' is set, the original instruction stream will be inside the
# new instruction stream with the first and last instruction from the input instruction stream.
# new_instr is a list of riscv_instr
def mix_instr_stream(self, new_instr, contained = 0):
"""
Mix the input instruction stream with the original instruction, the instruction order is
preserved. When 'contained' is set, the original instruction stream will be inside the
new instruction stream with the first and last instruction from the input instruction
stream.
new_instr is a list of riscv_instr
"""
current_instr_cnt = len(self.instr_list)
new_instr_cnt = len(new_instr)
insert_instr_position = [0] * new_instr_cnt
# TODO
if len(insert_instr_position) > 0:
insert_instr_position.sort()
for i in range(new_instr_cnt):
@ -148,16 +141,13 @@ class riscv_instr_stream:
return s
# Generate a random instruction stream based on the configuration
# There are two ways to use this class to generate instruction stream
# 1. For short instruction stream, you can call randomize() directly.
# 2. For long instruction stream (>1K), randomize() all instructions together might take a
# long time for the constraint solver. In this case, you can call gen_instr to generate
# instructions one by one. The time only grows linearly with the instruction count
class riscv_rand_instr_stream(riscv_instr_stream):
"""
Generate a random instruction stream based on the configuration
There are two ways to use this class to generate instruction stream
1. For short instruction stream, you can call randomize() directly.
2. For long instruction stream (>1K), randomize() all instructions together might take a
long time for the constraint solver. In this case, you can call gen_instr to generate
instructions one by one. The time only grows linearly with the instruction count
"""
def __init__(self):
# calling super constructor
super().__init__()
@ -196,7 +186,7 @@ class riscv_rand_instr_stream(riscv_instr_stream):
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))
self.reserved_rd))
except Exception:
logging.critical("Cannot randomize avail_regs")
sys.exit(1)'''
@ -209,12 +199,14 @@ class riscv_rand_instr_stream(riscv_instr_stream):
if no_load_store:
self.category_dist[riscv_instr_category_t.LOAD.name] = 0
self.category_dist[riscv_instr_category_t.STORE.name] = 0
logging.info("setup_instruction_dist: %0d", len(self.category_dist))
logging.info("setup_instruction_dist: {}".format(len(self.category_dist)))
def gen_instr(self, no_branch = 0, no_load_store = 1, is_debug_program = 0):
self.setup_allowed_instr(no_branch, no_load_store)
for i in range(len(self.instr_list)):
self.instr_list[i] = self.randomize_instr(self.instr_list[i], is_debug_program)
# Do not allow branch instruction as the last instruction because there's no
# forward branch target
while self.instr_list[-1].category == riscv_instr_category_t.BRANCH:
self.instr_list.pop()
if len(self.instr_list) == 0:
@ -268,3 +260,11 @@ class riscv_rand_instr_stream(riscv_instr_stream):
instr.rs1 != cfg.reserved_regs[i]
# TODO: Add constraint for CSR, floating point register
return instr
def get_init_gpr_instr(self, gpr, val):
# TODO
pass
def add_init_vector_gpr_instr(self, gpr, val):
# TODO
pass

View file

@ -32,6 +32,7 @@ class locality_e(IntEnum):
SPARSE = auto()
# Base class for all load/store instruction stream
@vsc.randobj
class riscv_load_store_base_instr_stream(riscv_mem_access_stream):
def __init__(self):
@ -213,6 +214,7 @@ class riscv_load_store_base_instr_stream(riscv_mem_access_stream):
self.load_store_instr.append(instr)
# A single load/store instruction
@vsc.randobj
class riscv_single_load_store_instr_stream(riscv_load_store_base_instr_stream):
def __init__(self):
@ -224,6 +226,7 @@ class riscv_single_load_store_instr_stream(riscv_load_store_base_instr_stream):
self.num_mixed_instr < 5
# Back to back load/store instructions
@vsc.randobj
class riscv_load_store_stress_instr_stream(riscv_load_store_base_instr_stream):
def __init__(self):
@ -237,6 +240,19 @@ class riscv_load_store_stress_instr_stream(riscv_load_store_base_instr_stream):
self.num_mixed_instr == 0
# Back to back load/store instructions
@vsc.randobj
class riscv_load_store_shared_mem_stream(riscv_load_store_stress_instr_stream):
def __init__(self):
super().__init__()
def pre_randomize(self):
self.load_store_shared_memory = 1
super().pre_randomize()
# Random load/store sequence
# A random mix of load/store instructions and other instructions
@vsc.randobj
class riscv_load_store_rand_instr_stream(riscv_load_store_base_instr_stream):
def __init__(self):
@ -248,6 +264,7 @@ class riscv_load_store_rand_instr_stream(riscv_load_store_base_instr_stream):
self.num_mixed_instr.inside(vsc.rangelist(vsc.rng(10, 30)))
# Use a small set of GPR to create various WAW, RAW, WAR hazard scenario
@vsc.randobj
class riscv_load_store_hazard_instr_stream(riscv_load_store_base_instr_stream):
def __init__(self):

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
@ -30,7 +29,7 @@ class riscv_privil_reg(riscv_reg):
super().init_reg(reg_name)
# ---------------Machine mode register ----------------
# Machine status Register
if(reg_name == privileged_reg_t.MSTATUS):
if reg_name == privileged_reg_t.MSTATUS:
self.privil_level = privileged_level_t.M_LEVEL
self.add_field("UIE", 1, reg_field_access_t.WARL)
self.add_field("SIE", 1, reg_field_access_t.WARL)
@ -51,7 +50,7 @@ class riscv_privil_reg(riscv_reg):
self.add_field("TVM", 1, reg_field_access_t.WARL)
self.add_field("TW", 1, reg_field_access_t.WARL)
self.add_field("TSR", 1, reg_field_access_t.WARL)
if(rcs.XLEN == 32):
if rcs.XLEN == 32:
self.add_field("WPRI3", 8, reg_field_access_t.WPRI)
else:
self.add_field("WPRI3", 9, reg_field_access_t.WPRI)
@ -60,7 +59,7 @@ class riscv_privil_reg(riscv_reg):
self.add_field("WPRI4", rcs.XLEN - 37, reg_field_access_t.WPRI)
self.add_field("SD", 1, reg_field_access_t.WARL)
# Machine interrupt-enable register
elif(reg_name == privileged_reg_t.MIE):
elif reg_name == privileged_reg_t.MIE:
self.privil_level = privileged_level_t.M_LEVEL
self.add_field("USIE", 1, reg_field_access_t.WARL)
self.add_field("SSIE", 1, reg_field_access_t.WARL)
@ -75,5 +74,6 @@ class riscv_privil_reg(riscv_reg):
self.add_field("WPEI2", 1, reg_field_access_t.WPRI)
self.add_field("MEIE", 1, reg_field_access_t.WARL)
self.add_field("WPRI3", rcs.XLEN - 12, reg_field_access_t.WPRI)
# TODO add condition for rest of the modes
else:
logging.error("reg %0s is not supported yet", reg_name.name)

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
@ -9,7 +8,6 @@ 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 logging
@ -22,6 +20,7 @@ from pygen_src.riscv_privil_reg import riscv_privil_reg
rcs = import_module("pygen_src.target." + cfg.argv.target + ".riscv_core_setting")
# This class provides some common routines for privileged mode operations
@vsc.randobj
class riscv_privileged_common_seq():
def __init___(self):
@ -79,8 +78,8 @@ class riscv_privileged_common_seq():
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),
instrs.append("li x{}, {}".format(cfg.gpr[0], hex(regs[i].get_val())))
instrs.append("csrw {}, x{} # {}".format(hex(regs[i].reg_name),
cfg.gpr[0], regs[i].reg_name.name))
def setup_satp(self, instrs):

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
@ -9,7 +8,6 @@ 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
@ -36,11 +34,12 @@ class riscv_pseudo_instr(riscv_instr):
riscv_instr_category_t.LOAD, riscv_instr_group_t.RV32I)
'''
# 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)
# instr rd,imm
asm_str = "{}{}, {}".format(asm_str, self.rd.name, self.get_imm())
if(self.comment != ""):
if self.comment != "":
asm_str = "{} #{}".format(asm_str, self.comment)
return asm_str.lower()

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
@ -21,7 +20,10 @@ from pygen_src.riscv_instr_pkg import (
rcs = import_module("pygen_src.target." + cfg.argv.target + ".riscv_core_setting")
# -----------------------------------------------
# Light weight RISC-V register class library
# -----------------------------------------------
# Base class for RISC-V register field
@vsc.randobj
class riscv_reg_field:

View file

@ -12,9 +12,8 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
from enum import IntEnum, auto
# Will be the lowest 8 bits of the data word
class signature_type_t(IntEnum):
'''
Information sent to the core relating its current status.

View file

@ -26,6 +26,10 @@ from pygen_src.riscv_load_store_instr_lib import (riscv_load_store_rand_instr_st
riscv_single_load_store_instr_stream)
# ----------------------------------------------------------
# pyflow commmon utility helpers functions
# ----------------------------------------------------------
def factory(obj_of):
objs = {
"riscv_directed_instr_stream": riscv_directed_instr_stream,

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
@ -10,74 +9,109 @@ 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)
import math
from pygen_src.riscv_instr_pkg import (privileged_reg_t, satp_mode_t,
riscv_instr_group_t, mtvec_mode_t,
privileged_mode_t)
# -----------------------------------------------------------------------------
# Processor feature configuration
# -----------------------------------------------------------------------------
# XLEN
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]
# set to BARE if address translation is not supported
SATP_MODE = satp_mode_t.BARE
# Supported Privileged mode
supported_privileged_mode = [privileged_mode_t.MACHINE_MODE]
# Unsupported instructions
unsupported_instr = []
# ISA supported by the processor
supported_isa = [riscv_instr_group_t.RV32I, riscv_instr_group_t.RV32M,
riscv_instr_group_t.RV32C, riscv_instr_group_t.RV32A]
supported_privileged_mode = [privileged_mode_t.MACHINE_MODE]
# Interrupt mode support
supported_interrupt_mode = [mtvec_mode_t.DIRECT, mtvec_mode_t.VECTORED]
# The number of interrupt vectors to be generated, only used if VECTORED
# interrupt mode is supported
max_interrupt_vector_num = 16
support_debug_mode = 0
NUM_HARTS = 2
# Physical memory protection support
support_pmp = 0
unsupported_instr = []
# Debug mode support
support_debug_mode = 0
# Support delegate trap to user mode
support_umode_trap = 0
# Support sfence.vma instruction
support_sfence = 0
# Support unaligned load/store
support_unaligned_load_store = 1
# GPR Setting
NUM_FLOAT_GPR = 32
NUM_GPR = 32
NUM_VEC_GPR = 32
# -----------------------------------------------------------------------------
# Vector extension configuration
# -----------------------------------------------------------------------------
# Parameter for vector extension
VECTOR_EXTENSION_ENABLE = 0
VLEN = 512
# Maximum size of a single vector element
ELEN = 32
# Minimum size of a sub-element, which must be at most 8-bits.
SELEN = 8
#VELEN =
# Maximum size of a single vector element (encoded in vsew format)
VELEN = int(math.log(ELEN) // math.log(2)) - 3
MAX_MUL = 8
# Maxium LMUL supported by the core
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]
# -----------------------------------------------------------------------------
# Multi-harts configuration
# -----------------------------------------------------------------------------
# Number of harts
NUM_HARTS = 2
# -----------------------------------------------------------------------------
# Previleged CSR implementation
# -----------------------------------------------------------------------------
# Implemented previlieged CSR list
implemented_csr = [privileged_reg_t.MVENDORID, # Vendor ID
privileged_reg_t.MARCHID, # Architecture ID
privileged_reg_t.MIMPID, # Implementation ID
privileged_reg_t.MHARTID, # Hardware thread ID
privileged_reg_t.MSTATUS, # Machine status
privileged_reg_t.MISA, # ISA and extensions
privileged_reg_t.MIE, # Machine interrupt-enable register
privileged_reg_t.MTVEC, # Machine trap-handler base address
privileged_reg_t.MCOUNTEREN, # Machine counter enable
privileged_reg_t.MSCRATCH, # Scratch register for machine trap handlers
privileged_reg_t.MEPC, # Machine exception program counter
privileged_reg_t.MCAUSE, # Machine trap cause
privileged_reg_t.MTVAL, # Machine bad address or instruction
privileged_reg_t.MIP # Machine interrupt pending
]
# Implementation-specific custom CSRs
custom_csr = []

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
@ -10,37 +9,108 @@ 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
from pygen_src.riscv_instr_pkg import (privileged_reg_t, satp_mode_t,
riscv_instr_group_t, privileged_mode_t)
riscv_instr_group_t, mtvec_mode_t,
privileged_mode_t)
# -----------------------------------------------------------------------------
# Processor feature configuration
# -----------------------------------------------------------------------------
# XLEN
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]
# set to BARE if address translation is not supported
SATP_MODE = satp_mode_t.BARE
supported_isa = [riscv_instr_group_t.RV32I]
# Supported Privileged mode
supported_privileged_mode = [privileged_mode_t.MACHINE_MODE]
NUM_HARTS = 1
support_pmp = 0
support_debug_mode = 0
# Unsupported instructions
unsupported_instr = []
# ISA supported by the processor
supported_isa = [riscv_instr_group_t.RV32I]
# Interrupt mode support
supported_interrupt_mode = [mtvec_mode_t.DIRECT, mtvec_mode_t.VECTORED]
# The number of interrupt vectors to be generated, only used if VECTORED
# interrupt mode is supported
max_interrupt_vector_num = 16
# Physical memory protection support
support_pmp = 0
# Debug mode support
support_debug_mode = 0
# Support delegate trap to user mode
support_umode_trap = 0
# Support sfence.vma instruction
support_sfence = 0
# Support unaligned load/store
support_unaligned_load_store = 1
# GPR Setting
NUM_FLOAT_GPR = 32
NUM_GPR = 32
NUM_VEC_GPR = 32
max_interrupt_vector_num = 16
# -----------------------------------------------------------------------------
# Vector extension configuration
# -----------------------------------------------------------------------------
# Parameter for vector extension
VECTOR_EXTENSION_ENABLE = 0
VLEN = 512
# Maximum size of a single vector element
ELEN = 32
# Minimum size of a sub-element, which must be at most 8-bits.
SELEN = 8
# Maximum size of a single vector element (encoded in vsew format)
VELEN = int(math.log(ELEN) // math.log(2)) - 3
# Maxium LMUL supported by the core
MAX_LMUL = 8
# -----------------------------------------------------------------------------
# Multi-harts configuration
# -----------------------------------------------------------------------------
# Number of harts
NUM_HARTS = 1
# -----------------------------------------------------------------------------
# Previleged CSR implementation
# -----------------------------------------------------------------------------
# Implemented previlieged CSR list
implemented_csr = [privileged_reg_t.MVENDORID, # Vendor ID
privileged_reg_t.MARCHID, # Architecture ID
privileged_reg_t.MIMPID, # Implementation ID
privileged_reg_t.MHARTID, # Hardware thread ID
privileged_reg_t.MSTATUS, # Machine status
privileged_reg_t.MISA, # ISA and extensions
privileged_reg_t.MIE, # Machine interrupt-enable register
privileged_reg_t.MTVEC, # Machine trap-handler base address
privileged_reg_t.MCOUNTEREN, # Machine counter enable
privileged_reg_t.MSCRATCH, # Scratch register for machine trap handlers
privileged_reg_t.MEPC, # Machine exception program counter
privileged_reg_t.MCAUSE, # Machine trap cause
privileged_reg_t.MTVAL, # Machine bad address or instruction
privileged_reg_t.MIP # Machine interrupt pending
]
# Implementation-specific custom CSRs
custom_csr = []

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
@ -10,71 +9,111 @@ 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)
import math
from pygen_src.riscv_instr_pkg import (privileged_reg_t, satp_mode_t,
riscv_instr_group_t, mtvec_mode_t,
privileged_mode_t)
# -----------------------------------------------------------------------------
# Processor feature configuration
# -----------------------------------------------------------------------------
# XLEN
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]
# set to BARE if address translation is not supported
SATP_MODE = satp_mode_t.BARE
# Supported Privileged mode
supported_privileged_mode = [privileged_mode_t.MACHINE_MODE]
# Unsupported instructions
unsupported_instr = []
# ISA supported by the processor
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]
# Interrupt mode support
supported_interrupt_mode = [mtvec_mode_t.DIRECT, mtvec_mode_t.VECTORED]
# The number of interrupt vectors to be generated, only used if VECTORED
# interrupt mode is supported
max_interrupt_vector_num = 16
support_debug_mode = 0
NUM_HARTS = 1
# Physical memory protection support
support_pmp = 0
unsupported_instr = []
# Debug mode support
support_debug_mode = 0
# Support delegate trap to user mode
support_umode_trap = 0
# Support sfence.vma instruction
support_sfence = 0
# Support unaligned load/store
support_unaligned_load_store = 1
# GPR Setting
NUM_FLOAT_GPR = 32
NUM_GPR = 32
NUM_VEC_GPR = 32
# -----------------------------------------------------------------------------
# Vector extension configuration
# -----------------------------------------------------------------------------
# Parameter for vector extension
VECTOR_EXTENSION_ENABLE = 0
VLEN = 512
# Maximum size of a single vector element
ELEN = 32
SELEN = 0
# Minimum size of a sub-element, which must be at most 8-bits.
SELEN = 8
MAX_MUL = 8
# Maximum size of a single vector element (encoded in vsew format)
VELEN = int(math.log(ELEN) // math.log(2)) - 3
implemented_interrupt = [interrupt_cause_t.M_SOFTWARE_INTR,
interrupt_cause_t.M_TIMER_INTR,
interrupt_cause_t.M_EXTERNAL_INTR]
# Maxium LMUL supported by the core
MAX_LMUL = 8
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]
# -----------------------------------------------------------------------------
# Multi-harts configuration
# -----------------------------------------------------------------------------
# Number of harts
NUM_HARTS = 1
# -----------------------------------------------------------------------------
# Previleged CSR implementation
# -----------------------------------------------------------------------------
# Implemented previlieged CSR list
implemented_csr = [privileged_reg_t.MVENDORID, # Vendor ID
privileged_reg_t.MARCHID, # Architecture ID
privileged_reg_t.MIMPID, # Implementation ID
privileged_reg_t.MHARTID, # Hardware thread ID
privileged_reg_t.MSTATUS, # Machine status
privileged_reg_t.MISA, # ISA and extensions
privileged_reg_t.MIE, # Machine interrupt-enable register
privileged_reg_t.MTVEC, # Machine trap-handler base address
privileged_reg_t.MCOUNTEREN, # Machine counter enable
privileged_reg_t.MSCRATCH, # Scratch register for machine trap handlers
privileged_reg_t.MEPC, # Machine exception program counter
privileged_reg_t.MCAUSE, # Machine trap cause
privileged_reg_t.MTVAL, # Machine bad address or instruction
privileged_reg_t.MIP # Machine interrupt pending
]
# Implementation-specific custom CSRs
custom_csr = []

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
@ -10,44 +9,52 @@ 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)
import math
from pygen_src.riscv_instr_pkg import (privileged_reg_t, satp_mode_t,
riscv_instr_group_t, mtvec_mode_t,
privileged_mode_t)
# -----------------------------------------------------------------------------
# Processor feature configuration
# -----------------------------------------------------------------------------
# XLEN
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]
# set to BARE if address translation is not supported
SATP_MODE = satp_mode_t.BARE
supported_isa = [riscv_instr_group_t.RV32I, riscv_instr_group_t.RV32M,
riscv_instr_group_t.RV32C]
# Supported Privileged mode
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 instructions
unsupported_instr = []
# ISA supported by the processor
supported_isa = [riscv_instr_group_t.RV32I, riscv_instr_group_t.RV32M, riscv_instr_group_t.RV32C]
# Interrupt mode support
supported_interrupt_mode = [mtvec_mode_t.DIRECT, mtvec_mode_t.VECTORED]
# The number of interrupt vectors to be generated, only used if VECTORED
# interrupt mode is supported
max_interrupt_vector_num = 16
# Physical memory protection support
support_pmp = 0
# Debug mode support
support_debug_mode = 0
# Support delegate trap to user mode
support_umode_trap = 0
# Support sfence.vma instruction
support_sfence = 0
# Support unaligned load/store
support_unaligned_load_store = 1
# GPR Setting
@ -55,22 +62,55 @@ NUM_FLOAT_GPR = 32
NUM_GPR = 32
NUM_VEC_GPR = 32
# -----------------------------------------------------------------------------
# Vector extension configuration
# -----------------------------------------------------------------------------
# Parameter for vector extension
VECTOR_EXTENSION_ENABLE = 0
VLEN = 512
# Maximum size of a single vector element
ELEN = 32
SELEN = 0
# Minimum size of a sub-element, which must be at most 8-bits.
SELEN = 8
MAX_MUL = 8
# Maximum size of a single vector element (encoded in vsew format)
VELEN = int(math.log(ELEN) // math.log(2)) - 3
implemented_interrupt = [interrupt_cause_t.M_SOFTWARE_INTR,
interrupt_cause_t.M_TIMER_INTR,
interrupt_cause_t.M_EXTERNAL_INTR]
# Maxium LMUL supported by the core
MAX_LMUL = 8
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]
# -----------------------------------------------------------------------------
# Multi-harts configuration
# -----------------------------------------------------------------------------
# Number of harts
NUM_HARTS = 1
# -----------------------------------------------------------------------------
# Previleged CSR implementation
# -----------------------------------------------------------------------------
# Implemented previlieged CSR list
implemented_csr = [privileged_reg_t.MVENDORID, # Vendor ID
privileged_reg_t.MARCHID, # Architecture ID
privileged_reg_t.MIMPID, # Implementation ID
privileged_reg_t.MHARTID, # Hardware thread ID
privileged_reg_t.MSTATUS, # Machine status
privileged_reg_t.MISA, # ISA and extensions
privileged_reg_t.MIE, # Machine interrupt-enable register
privileged_reg_t.MTVEC, # Machine trap-handler base address
privileged_reg_t.MCOUNTEREN, # Machine counter enable
privileged_reg_t.MSCRATCH, # Scratch register for machine trap handlers
privileged_reg_t.MEPC, # Machine exception program counter
privileged_reg_t.MCAUSE, # Machine trap cause
privileged_reg_t.MTVAL, # Machine bad address or instruction
privileged_reg_t.MIP # Machine interrupt pending
]
# Implementation-specific custom CSRs
custom_csr = []

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
@ -10,45 +9,53 @@ 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)
import math
from pygen_src.riscv_instr_pkg import (privileged_reg_t, satp_mode_t,
riscv_instr_group_t, mtvec_mode_t,
privileged_mode_t)
# -----------------------------------------------------------------------------
# Processor feature configuration
# -----------------------------------------------------------------------------
# XLEN
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]
# set to BARE if address translation is not supported
SATP_MODE = satp_mode_t.BARE
# Supported Privileged mode
supported_privileged_mode = [privileged_mode_t.MACHINE_MODE]
# Unsupported instructions
unsupported_instr = []
# ISA supported by the processor
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]
# Interrupt mode support
supported_interrupt_mode = [mtvec_mode_t.DIRECT, mtvec_mode_t.VECTORED]
# The number of interrupt vectors to be generated, only used if VECTORED
# interrupt mode is supported
max_interrupt_vector_num = 16
support_debug_mode = 0
NUM_HARTS = 1
# Physical memory protection support
support_pmp = 0
unsupported_instr = []
# Debug mode support
support_debug_mode = 0
# Support delegate trap to user mode
support_umode_trap = 0
# Support sfence.vma instruction
support_sfence = 0
# Support unaligned load/store
support_unaligned_load_store = 1
# GPR Setting
@ -56,23 +63,55 @@ NUM_FLOAT_GPR = 32
NUM_GPR = 32
NUM_VEC_GPR = 32
# -----------------------------------------------------------------------------
# Vector extension configuration
# -----------------------------------------------------------------------------
# Parameter for vector extension
VECTOR_EXTENSION_ENABLE = 0
VLEN = 512
# Maximum size of a single vector element
ELEN = 32
# Minimum size of a sub-element, which must be at most 8-bits.
SELEN = 8
# Maximum size of a single vector element (encoded in vsew format)
VELEN = int(math.log(ELEN) // math.log(2)) - 3
# Maxium LMUL supported by the core
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]
# -----------------------------------------------------------------------------
# Multi-harts configuration
# -----------------------------------------------------------------------------
# Number of harts
NUM_HARTS = 1
# -----------------------------------------------------------------------------
# Previleged CSR implementation
# -----------------------------------------------------------------------------
# Implemented previlieged CSR list
implemented_csr = [privileged_reg_t.MVENDORID, # Vendor ID
privileged_reg_t.MARCHID, # Architecture ID
privileged_reg_t.MIMPID, # Implementation ID
privileged_reg_t.MHARTID, # Hardware thread ID
privileged_reg_t.MSTATUS, # Machine status
privileged_reg_t.MISA, # ISA and extensions
privileged_reg_t.MIE, # Machine interrupt-enable register
privileged_reg_t.MTVEC, # Machine trap-handler base address
privileged_reg_t.MCOUNTEREN, # Machine counter enable
privileged_reg_t.MSCRATCH, # Scratch register for machine trap handlers
privileged_reg_t.MEPC, # Machine exception program counter
privileged_reg_t.MCAUSE, # Machine trap cause
privileged_reg_t.MTVAL, # Machine bad address or instruction
privileged_reg_t.MIP # Machine interrupt pending
]
# Implementation-specific custom CSRs
custom_csr = []

View file

@ -24,6 +24,7 @@ from pygen_src.riscv_asm_program_gen import riscv_asm_program_gen # NOQA
from pygen_src.riscv_utils import gen_config_table
# Base test
class riscv_instr_base_test:
def __init__(self):
self.start_idx = cfg.argv.start_idx
@ -41,17 +42,23 @@ class riscv_instr_base_test:
if cfg.asm_test_suffix != "":
self.asm_file_name = "{}.{}".format(self.asm_file_name,
cfg.asm_test_suffix)
self.asm.get_directed_instr_stream()
test_name = "{}_{}.S".format(self.asm_file_name,
num + self.start_idx)
self.asm.get_directed_instr_stream()
self.apply_directed_instr()
logging.info("All directed instruction is applied")
self.asm.gen_program()
self.asm.gen_test_file(test_name)
logging.info("TEST GENERATION DONE")
def randomize_cfg(self):
cfg.randomize()
logging.info("riscv_instr_gen_config is randomized")
gen_config_table()
def apply_directed_instr(self):
pass
start_time = time.time()
riscv_base_test_ins = riscv_instr_base_test()

View file

@ -106,6 +106,11 @@ class riscv_instr_cov_test:
def get_coverage_report(self):
model = vsc.get_coverage_report_model()
cov_dir = cfg.argv.log_file_name.split("/")[0]
file = open('{}/CoverageGroups.txt'.format(cov_dir), 'w')
file.write("CoverGroups, CoverPoints and Bins Summary\n")
str_report = vsc.get_coverage_report(details=True)
file.write("{}\n".format(str_report))
file.close()
file = open('{}/CoverageReport.txt'.format(cov_dir), 'w')
file.write("Groups Coverage Summary\n")
file.write("Total groups in report: {}\n".format(
@ -125,18 +130,6 @@ class riscv_instr_cov_test:
pass
def sample(self):
binary = vsc.int_t(rcs.XLEN)
binary.set_val(get_val(self.trace["binary"], hexa=1))
# TODO: Currently handled using string formatting as part select
# isn't yet supported for global vsc variables
# width is rcs.XLEN+2 because of 0b in the beginning of binary_bin
binary_bin = format(binary.get_val(), '#0{}b'.format(rcs.XLEN + 2))
if binary_bin[-2:] != "11": # TODO: and RV32C in supported_isa
# TODO: sample compressed instruction
pass
if binary_bin[-2:] == "11":
# TODO: sampling
pass
processed_instr_name = self.process_instr_name(self.trace["instr"])
if processed_instr_name in riscv_instr_name_t.__members__:
instr_name = riscv_instr_name_t[processed_instr_name]
@ -145,9 +138,10 @@ class riscv_instr_cov_test:
# cov_instr is created, time to manually assign attributes
# TODO: This will get fixed later when we get an inst from template
instruction.assign_attributes()
if instruction.group.name in ["RV32I", "RV32M", "RV32C", "RV64I",
if (instruction.group.name in ["RV32I", "RV32M", "RV32C", "RV64I",
"RV64M", "RV64C", "RV32F", "RV64F",
"RV32D", "RV64D", "RV32B", "RV64B"]:
"RV32D", "RV64D", "RV32B", "RV64B"]) \
and (instruction.group in rcs.supported_isa):
self.assign_trace_info_to_instr(instruction)
instruction.pre_sample()
self.instr_cg.sample(instruction)
@ -178,7 +172,7 @@ class riscv_instr_cov_test:
def process_instr_name(self, instruction):
instruction = instruction.upper()
instruction.replace(".", "_")
instruction = instruction.replace(".", "_")
instruction = self.update_instr_name(instruction)
return instruction

View file

@ -31,13 +31,14 @@ class riscv_rand_instr_test(riscv_instr_base_test):
gen_config_table()
def apply_directed_instr(self):
# Mix below directed instruction streams with the random instructions
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_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_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)
# 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)
start_time = time.time()

View file

@ -380,11 +380,21 @@ def gen(test_list, argv, output_dir, cwd):
# Run the instruction generator
if not argv.co:
seed_gen = SeedGen(argv.start_seed, argv.seed, argv.seed_yaml)
if argv.simulator == 'pyflow':
"""Default timeout of Pyflow is 20 minutes, if the user
doesn't specified their own gen_timeout value from CMD
"""
if argv.gen_timeout == 360:
gen_timeout = 1200
else:
gen_timeout = argv.gen_timeout
else:
gen_timeout = argv.gen_timeout
do_simulate(sim_cmd, argv.simulator, test_list, cwd, argv.sim_opts,
seed_gen,
argv.csr_yaml, argv.isa, argv.end_signature_addr,
argv.lsf_cmd,
argv.gen_timeout, argv.log_suffix, argv.batch_size,
gen_timeout, argv.log_suffix, argv.batch_size,
output_dir,
argv.verbose, check_return_code, argv.debug, argv.target)

View file

@ -214,7 +214,6 @@ 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

@ -157,7 +157,7 @@ def run_parallel_cmd(cmd_list, timeout_s=999, exit_on_error=0,
stderr=subprocess.STDOUT)
children.append(ps)
for i in range(len(children)):
logging.info("Command progress: {}/{}".format(i, len(children)))
logging.info("Command progress: {}/{}".format(i + 1, len(children)))
logging.debug("Waiting for command: {}".format(cmd_list[i]))
try:
output = children[i].communicate(timeout=timeout_s)[0]

213
vendor/google_riscv-dv/src/isa/riscv_b_instr.sv vendored Executable file → Normal file
View file

@ -31,7 +31,7 @@ class riscv_b_instr extends riscv_instr;
has_rs3 = 1'b0;
case (format) inside
R_FORMAT: begin
if (instr_name inside {CLZW, CTZW, PCNTW, SEXT_B, SEXT_H, CLZ, CTZ, PCNT, BMATFLIP,
if (instr_name inside {BMATFLIP,
CRC32_B, CRC32_H, CRC32_W, CRC32C_B, CRC32C_H, CRC32C_W, CRC32_D,
CRC32C_D}) begin
has_rs2 = 1'b0;
@ -61,21 +61,12 @@ class riscv_b_instr extends riscv_instr;
if (format inside {I_FORMAT}) begin
if (category inside {SHIFT, LOGICAL}) begin
if (group == RV64B && !(instr_name inside {SLLIU_W})) begin
imm_len = $clog2(XLEN) - 1;
end else begin
imm_len = $clog2(XLEN);
end
imm_len = $clog2(XLEN);
end
// ARITHMETIC RV32B
if (instr_name inside {SHFLI, UNSHFLI}) begin
imm_len = $clog2(XLEN) - 1;
end
// ARITHMETIC RV64B
if (instr_name inside {ADDIWU}) begin
imm_len = 12;
end
end
imm_mask = imm_mask << imm_len;
@ -117,63 +108,38 @@ class riscv_b_instr extends riscv_instr;
function bit [6:0] get_opcode();
case (instr_name) inside
ANDN, ORN, XNOR, GORC, SLO, SRO, ROL, ROR, SBCLR, SBSET, SBINV, SBEXT,
GREV: get_opcode = 7'b0110011;
SLOI, SROI, RORI, SBCLRI, SBSETI, SBINVI, SBEXTI, GORCI, GREVI, CMIX, CMOV,
FSL: get_opcode = 7'b0010011;
FSR, FSRI, CLZ, CTZ, PCNT, BMATFLIP, SEXT_B, SEXT_H, CRC32_B, CRC32_H, CRC32_W, CRC32C_B,
CRC32C_H: get_opcode = 7'b0010011;
GORC, SLO, SRO, GREV, XPERM_N, XPERM_B, XPERM_H, XPERM_W: get_opcode = 7'b0110011;
GORCI, SLOI, SROI, GREVI, CMIX, CMOV, FSL: get_opcode = 7'b0010011;
FSR, FSRI, BMATFLIP, CRC32_B, CRC32_H, CRC32_W, CRC32C_B, CRC32C_H: get_opcode = 7'b0010011;
CRC32C_W, CRC32_D, CRC32C_D: get_opcode = 7'b0010011;
CLMUL, CLMULR, CLMULH, MIN, MAX, MINU, MAXU, SHFL, UNSHFL, BDEP, BEXT, PACK, PACKU, BMATOR,
BMATXOR, PACKH, BFP: get_opcode = 7'b0110011;
SHFL, UNSHFL, BCOMPRESS, BDECOMPRESS, PACK, PACKU, BMATOR, BMATXOR, PACKH, BFP: get_opcode
= 7'b0110011;
SHFLI, UNSHFLI: get_opcode = 7'b0010011;
ADDIWU, SLLIU_W: get_opcode = 7'b0011011;
ADDWU, SUBWU, ADDU_W, SUBU_W, SLOW, SROW, ROLW, RORW, SBCLRW, SBSETW, SBINVW, SBEXTW, GORCW,
GREVW: get_opcode = 7'b0111011;
SLOIW, SROIW, RORIW, SBCLRIW, SBSETIW, SBINVIW, GORCIW, GREVIW: get_opcode = 7'b0011011;
SLOW, SROW, GORCW, GREVW: get_opcode = 7'b0111011;
SLOIW, SROIW, GORCIW, GREVIW: get_opcode = 7'b0011011;
FSLW, FSRW: get_opcode = 7'b0111011;
FSRIW, CLZW, CTZW, PCNTW: get_opcode = 7'b0011011;
CLMULW, CLMULRW, CLMULHW, SHFLW, UNSHFLW, BDEPW, BEXTW, PACKW, PACKUW,
BFPW: get_opcode = 7'b0111011;
FSRIW: get_opcode = 7'b0011011;
SHFLW, UNSHFLW, BCOMPRESSW, BDECOMPRESSW, PACKW, PACKUW, BFPW: get_opcode = 7'b0111011;
default: get_opcode = super.get_opcode();
endcase
endfunction
virtual function bit [2:0] get_func3();
case (instr_name) inside
ANDN: get_func3 = 3'b111;
ORN: get_func3 = 3'b110;
XNOR: get_func3 = 3'b100;
GORC: get_func3 = 3'b101;
GORCI: get_func3 = 3'b101;
SLO: get_func3 = 3'b001;
SRO: get_func3 = 3'b101;
ROL: get_func3 = 3'b001;
ROR: get_func3 = 3'b101;
SBCLR: get_func3 = 3'b001;
SBSET: get_func3 = 3'b001;
SBINV: get_func3 = 3'b001;
SBEXT: get_func3 = 3'b101;
GREV: get_func3 = 3'b101;
SLOI: get_func3 = 3'b001;
SROI: get_func3 = 3'b101;
RORI: get_func3 = 3'b101;
SBCLRI: get_func3 = 3'b001;
SBSETI: get_func3 = 3'b001;
SBINVI: get_func3 = 3'b001;
SBEXTI: get_func3 = 3'b101;
GORCI: get_func3 = 3'b101;
GREV: get_func3 = 3'b101;
GREVI: get_func3 = 3'b101;
CMIX: get_func3 = 3'b001;
CMOV: get_func3 = 3'b101;
FSL: get_func3 = 3'b001;
FSR: get_func3 = 3'b101;
FSRI: get_func3 = 3'b101;
CLZ: get_func3 = 3'b001;
CTZ: get_func3 = 3'b001;
PCNT: get_func3 = 3'b001;
BMATFLIP: get_func3 = 3'b001;
SEXT_B: get_func3 = 3'b001;
SEXT_H: get_func3 = 3'b001;
CRC32_B: get_func3 = 3'b001;
CRC32_H: get_func3 = 3'b001;
CRC32_W: get_func3 = 3'b001;
@ -182,17 +148,10 @@ class riscv_b_instr extends riscv_instr;
CRC32C_W: get_func3 = 3'b001;
CRC32_D: get_func3 = 3'b001;
CRC32C_D: get_func3 = 3'b001;
CLMUL: get_func3 = 3'b001;
CLMULR: get_func3 = 3'b010;
CLMULH: get_func3 = 3'b011;
MIN: get_func3 = 3'b100;
MAX: get_func3 = 3'b101;
MINU: get_func3 = 3'b110;
MAXU: get_func3 = 3'b111;
SHFL: get_func3 = 3'b001;
UNSHFL: get_func3 = 3'b101;
BDEP: get_func3 = 3'b110;
BEXT: get_func3 = 3'b110;
BCOMPRESS: get_func3 = 3'b110;
BDECOMPRESS: get_func3 = 3'b110;
PACK: get_func3 = 3'b100;
PACKU: get_func3 = 3'b100;
BMATOR: get_func3 = 3'b011;
@ -201,46 +160,30 @@ class riscv_b_instr extends riscv_instr;
BFP: get_func3 = 3'b111;
SHFLI: get_func3 = 3'b001;
UNSHFLI: get_func3 = 3'b101;
ADDIWU: get_func3 = 3'b100;
SLLIU_W: get_func3 = 3'b001;
ADDWU: get_func3 = 3'b000;
SUBWU: get_func3 = 3'b000;
ADDU_W: get_func3 = 3'b000;
SUBU_W: get_func3 = 3'b000;
SLOW: get_func3 = 3'b001;
SROW: get_func3 = 3'b101;
ROLW: get_func3 = 3'b001;
RORW: get_func3 = 3'b101;
SBCLRW: get_func3 = 3'b001;
SBSETW: get_func3 = 3'b001;
SBINVW: get_func3 = 3'b001;
SBEXTW: get_func3 = 3'b101;
GORCW: get_func3 = 3'b101;
GREVW: get_func3 = 3'b101;
SLOIW: get_func3 = 3'b001;
SROIW: get_func3 = 3'b101;
RORIW: get_func3 = 3'b101;
SBCLRIW: get_func3 = 3'b001;
SBSETIW: get_func3 = 3'b001;
SBINVIW: get_func3 = 3'b001;
GORCIW: get_func3 = 3'b101;
GREVIW: get_func3 = 3'b101;
FSLW: get_func3 = 3'b001;
FSRW: get_func3 = 3'b101;
FSRIW: get_func3 = 3'b101;
CLZW: get_func3 = 3'b001;
CTZW: get_func3 = 3'b001;
PCNTW: get_func3 = 3'b001;
CLMULW: get_func3 = 3'b001;
CLMULRW: get_func3 = 3'b010;
CLMULHW: get_func3 = 3'b011;
SHFLW: get_func3 = 3'b001;
UNSHFLW: get_func3 = 3'b101;
BDEPW: get_func3 = 3'b110;
BEXTW: get_func3 = 3'b110;
BCOMPRESSW: get_func3 = 3'b110;
BDECOMPRESSW: get_func3 = 3'b110;
PACKW: get_func3 = 3'b100;
PACKUW: get_func3 = 3'b100;
BFPW: get_func3 = 3'b111;
XPERM_N: get_func3 = 3'b010;
XPERM_B: get_func3 = 3'b100;
XPERM_H: get_func3 = 3'b110;
XPERM_W: get_func3 = 3'b000;
default: get_func3 = super.get_func3();
endcase
;
@ -256,17 +199,8 @@ class riscv_b_instr extends riscv_instr;
SRO: get_func7 = 7'b0010000;
ROL: get_func7 = 7'b0110000;
ROR: get_func7 = 7'b0110000;
SBCLR: get_func7 = 7'b0100100;
SBSET: get_func7 = 7'b0010100;
SBINV: get_func7 = 7'b0110100;
SBEXT: get_func7 = 7'b0100100;
GREV: get_func7 = 7'b0110100;
CLZ: get_func7 = 7'b0110000;
CTZ: get_func7 = 7'b0110000;
PCNT: get_func7 = 7'b0110000;
BMATFLIP: get_func7 = 7'b0110000;
SEXT_B: get_func7 = 7'b0110000;
SEXT_H: get_func7 = 7'b0110000;
CRC32_B: get_func7 = 7'b0110000;
CRC32_H: get_func7 = 7'b0110000;
CRC32_W: get_func7 = 7'b0110000;
@ -275,58 +209,35 @@ class riscv_b_instr extends riscv_instr;
CRC32C_W: get_func7 = 7'b0110000;
CRC32_D: get_func7 = 7'b0110000;
CRC32C_D: get_func7 = 7'b0110000;
CLMUL: get_func7 = 7'b0000101;
CLMULR: get_func7 = 7'b0000101;
CLMULH: get_func7 = 7'b0000101;
MIN: get_func7 = 7'b0000101;
MAX: get_func7 = 7'b0000101;
MINU: get_func7 = 7'b0000101;
MAXU: get_func7 = 7'b0000101;
SHFL: get_func7 = 7'b0000100;
UNSHFL: get_func7 = 7'b0000100;
BDEP: get_func7 = 7'b0100100;
BEXT: get_func7 = 7'b0000100;
BCOMPRESS: get_func7 = 7'b0000100;
BDECOMPRESS: get_func7 = 7'b0100100;
PACK: get_func7 = 7'b0000100;
PACKU: get_func7 = 7'b0100100;
BMATOR: get_func7 = 7'b0000100;
BMATXOR: get_func7 = 7'b0100100;
PACKH: get_func7 = 7'b0000100;
BFP: get_func7 = 7'b0100100;
ADDWU: get_func7 = 7'b0000101;
SUBWU: get_func7 = 7'b0100101;
ADDU_W: get_func7 = 7'b0000100;
SUBU_W: get_func7 = 7'b0100100;
SLOW: get_func7 = 7'b0010000;
SROW: get_func7 = 7'b0010000;
ROLW: get_func7 = 7'b0110000;
RORW: get_func7 = 7'b0110000;
SBCLRW: get_func7 = 7'b0100100;
SBSETW: get_func7 = 7'b0010100;
SBINVW: get_func7 = 7'b0110100;
SBEXTW: get_func7 = 7'b0100100;
GORCW: get_func7 = 7'b0010100;
GORCIW: get_func7 = 7'b0010100;
GREVW: get_func7 = 7'b0110100;
GREVIW: get_func7 = 7'b0110100;
SLOIW: get_func7 = 7'b0010000;
SROIW: get_func7 = 7'b0010000;
RORIW: get_func7 = 7'b0110000;
SBCLRIW: get_func7 = 7'b0100100;
SBSETIW: get_func7 = 7'b0010100;
SBINVIW: get_func7 = 7'b0110100;
GORCIW: get_func7 = 7'b0010100;
GREVIW: get_func7 = 7'b0110100;
CLZW: get_func7 = 7'b0110000;
CTZW: get_func7 = 7'b0110000;
PCNTW: get_func7 = 7'b0110000;
CLMULW: get_func7 = 7'b0000101;
CLMULRW: get_func7 = 7'b0000101;
CLMULHW: get_func7 = 7'b0000101;
SHFLW: get_func7 = 7'b0000100;
UNSHFLW: get_func7 = 7'b0000100;
BDEPW: get_func7 = 7'b0100100;
BEXTW: get_func7 = 7'b0000100;
BCOMPRESSW: get_func7 = 7'b0000100;
BDECOMPRESSW: get_func7 = 7'b0100100;
PACKW: get_func7 = 7'b0000100;
PACKUW: get_func7 = 7'b0100100;
BFPW: get_func7 = 7'b0100100;
XPERM_N: get_func7 = 7'b0010100;
XPERM_B: get_func7 = 7'b0010100;
XPERM_H: get_func7 = 7'b0010100;
XPERM_W: get_func7 = 7'b0010100;
default: get_func7 = super.get_func7();
endcase
@ -337,17 +248,9 @@ class riscv_b_instr extends riscv_instr;
SLOI: get_func5 = 5'b00100;
SROI: get_func5 = 5'b00100;
RORI: get_func5 = 5'b01100;
SBCLRI: get_func5 = 5'b01001;
SBSETI: get_func5 = 5'b01001;
SBINVI: get_func5 = 5'b01101;
SBEXTI: get_func5 = 5'b01001;
GORCI: get_func5 = 5'b00101;
GREVI: get_func5 = 5'b01101;
CLZW: get_func5 = 5'b00000;
CTZW: get_func5 = 5'b00001;
PCNTW: get_func5 = 5'b00010;
CRC32_B: get_func5 = 5'b10000;
CRC32_H: get_func5 = 5'b10001;
CRC32_W: get_func5 = 5'b10010;
@ -357,12 +260,7 @@ class riscv_b_instr extends riscv_instr;
CRC32_D: get_func5 = 5'b10011;
CRC32C_D: get_func5 = 5'b11011;
CLZ: get_func5 = 5'b00000;
CTZ: get_func5 = 5'b00001;
PCNT: get_func5 = 5'b00010;
BMATFLIP: get_func5 = 5'b00011;
SEXT_B: get_func5 = 5'b00100;
SEXT_H: get_func5 = 5'b00101;
default: `uvm_fatal(`gfn, $sformatf("Unsupported instruction %0s", instr_name.name()))
endcase
endfunction
@ -385,23 +283,15 @@ class riscv_b_instr extends riscv_instr;
string binary = "";
case (format)
R_FORMAT: begin
if ((category inside {LOGICAL}) && (group == RV32B)) begin
if (instr_name inside {SEXT_B, SEXT_H}) begin
binary =
$sformatf("%8h", {get_func7(), get_func5(), rs1, get_func3(), rd, get_opcode()});
end
end
if ((category inside {ARITHMETIC}) && (group == RV32B)) begin
if (instr_name inside {CRC32_B, CRC32_H, CRC32_W, CRC32C_B, CRC32C_H, CRC32C_W, CLZ, CTZ,
PCNT}) begin
if (instr_name inside {CRC32_B, CRC32_H, CRC32_W, CRC32C_B, CRC32C_H, CRC32C_W}) begin
binary =
$sformatf("%8h", {get_func7(), get_func5(), rs1, get_func3(), rd, get_opcode()});
end
end
if ((category inside {ARITHMETIC}) && (group == RV64B)) begin
if (instr_name inside {CLZW, CTZW, PCNTW, CRC32_D, CRC32C_D, BMATFLIP}) begin
if (instr_name inside {CRC32_D, CRC32C_D, BMATFLIP}) begin
binary =
$sformatf("%8h", {get_func7(), get_func5(), rs1, get_func3(), rd, get_opcode()});
end
@ -413,8 +303,6 @@ class riscv_b_instr extends riscv_instr;
binary = $sformatf("%8h", {get_func5(), imm[6:0], rs1, get_func3(), rd, get_opcode()});
end else if ((category inside {SHIFT, LOGICAL}) && (group == RV64B)) begin
binary = $sformatf("%8h", {get_func7(), imm[4:0], rs1, get_func3(), rd, get_opcode()});
if (instr_name == SLLIU_W)
binary = $sformatf("%8h", {5'b0_0001, imm[6:0], rs1, get_func3(), rd, get_opcode()});
end
if (instr_name inside {FSRI}) begin
@ -450,37 +338,19 @@ class riscv_b_instr extends riscv_instr;
virtual function bit is_supported(riscv_instr_gen_config cfg);
return cfg.enable_b_extension && (
(ZBB inside {cfg.enable_bitmanip_groups} && instr_name inside {
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
}) ||
(ZBS inside {cfg.enable_bitmanip_groups} && instr_name inside {
SBSET, SBSETW, SBSETI, SBSETIW,
SBCLR, SBCLRW, SBCLRI, SBCLRIW,
SBINV, SBINVW, SBINVI, SBINVIW,
SBEXT, SBEXTW, SBEXTI
}) ||
(ZBP inside {cfg.enable_bitmanip_groups} && instr_name inside {
GREV, GREVW, GREVI, GREVIW,
GORC, GORCW, GORCI, GORCIW,
SHFL, SHFLW, UNSHFL, UNSHFLW, SHFLI, UNSHFLI
SHFL, SHFLW, UNSHFL, UNSHFLW, SHFLI, UNSHFLI,
XPERM_N, XPERM_B, XPERM_H, XPERM_W,
SLO, SLOW, SLOI, SLOIW,
SRO, SROW, SROI, SROIW
}) ||
(ZBE inside {cfg.enable_bitmanip_groups} && instr_name inside {
BEXT, BEXTW,
BDEP, BDEPW
BCOMPRESS, BCOMPRESSW,
BDECOMPRESS, BDECOMPRESSW
}) ||
(ZBF inside {cfg.enable_bitmanip_groups} && instr_name inside {BFP, BFPW}) ||
(ZBC inside {cfg.enable_bitmanip_groups} && instr_name inside {
CLMUL, CLMULW, CLMULH, CLMULHW, CLMULR, CLMULRW
}) ||
(ZBR inside {cfg.enable_bitmanip_groups} && instr_name inside {
CRC32_B, CRC32_H, CRC32_W, CRC32_D,
CRC32C_B, CRC32C_H, CRC32C_W, CRC32C_D
@ -490,10 +360,7 @@ class riscv_b_instr extends riscv_instr;
}) ||
(ZBT inside {cfg.enable_bitmanip_groups} && instr_name inside {
CMOV, CMIX,
FSL, FSLW, FSR, FSRW, FSRI, FSRIW}) ||
// TODO, spec 0.92 doesn't categorize these 2 instr, put them in ZB_TMP #572
(ZB_TMP inside {cfg.enable_bitmanip_groups} && instr_name inside {
SEXT_B, SEXT_H})
FSL, FSLW, FSR, FSRW, FSRI, FSRIW})
);
endfunction

View file

@ -318,11 +318,11 @@ class riscv_compressed_instr extends riscv_instr;
C_ADD:
binary = $sformatf("%4h", {get_func3(), 1'b1, rd, rs2, get_c_opcode()});
C_FSDSP, C_SDSP:
binary = $sformatf("%4h", {get_func3(), 1'b0, imm[5:3], imm[8:6], rs2, get_c_opcode()});
binary = $sformatf("%4h", {get_func3(), imm[5:3], imm[8:6], rs2, get_c_opcode()});
C_SQSP:
binary = $sformatf("%4h", {get_func3(), 1'b0, imm[5:4], imm[9:6], rs2, get_c_opcode()});
binary = $sformatf("%4h", {get_func3(), imm[5:4], imm[9:6], rs2, get_c_opcode()});
C_SWSP, C_FSWSP:
binary = $sformatf("%4h", {get_func3(), 1'b0, imm[5:2], imm[7:6], rs2, get_c_opcode()});
binary = $sformatf("%4h", {get_func3(), imm[5:2], imm[7:6], rs2, get_c_opcode()});
default : `uvm_fatal(`gfn, $sformatf("Unsupported instruction %0s", instr_name.name()))
endcase
return {prefix, binary};

View file

@ -248,7 +248,7 @@ class riscv_floating_point_instr extends riscv_instr;
if (group inside {RV32F, RV64F}) begin
fs1_sign = get_fp_operand_sign(fs1_value, 31);
fs2_sign = get_fp_operand_sign(fs2_value, 31);
fs3_sign = get_fp_operand_sign(fs2_value, 31);
fs3_sign = get_fp_operand_sign(fs3_value, 31);
fd_sign = get_fp_operand_sign(fd_value, 31);
end else if (instr_name == FCVT_S_D) begin
fs1_sign = get_fp_operand_sign(fs1_value, 63);
@ -259,7 +259,7 @@ class riscv_floating_point_instr extends riscv_instr;
end else begin
fs1_sign = get_fp_operand_sign(fs1_value, 63);
fs2_sign = get_fp_operand_sign(fs2_value, 63);
fs3_sign = get_fp_operand_sign(fs2_value, 63);
fs3_sign = get_fp_operand_sign(fs3_value, 63);
fd_sign = get_fp_operand_sign(fd_value, 63);
end
endfunction : pre_sample

View file

@ -344,7 +344,7 @@ class riscv_instr extends uvm_object;
if(imm_type == UIMM) begin
imm_len = 5;
end else begin
imm_len = 11;
imm_len = 12;
end
end
imm_mask = imm_mask << imm_len;
@ -580,7 +580,7 @@ class riscv_instr extends uvm_object;
if(instr_name inside {FENCE, FENCE_I})
binary = $sformatf("%8h", {17'b0, get_func3(), 5'b0, get_opcode()});
else if(category == CSR)
binary = $sformatf("%8h", {csr[10:0], imm[4:0], get_func3(), rd, get_opcode()});
binary = $sformatf("%8h", {csr[11:0], imm[4:0], get_func3(), rd, get_opcode()});
else if(instr_name == ECALL)
binary = $sformatf("%8h", {get_func7(), 18'b0, get_opcode()});
else if(instr_name inside {URET, SRET, MRET})
@ -604,7 +604,7 @@ class riscv_instr extends uvm_object;
end
R_FORMAT: begin
if(category == CSR)
binary = $sformatf("%8h", {csr[10:0], rs1, get_func3(), rd, get_opcode()});
binary = $sformatf("%8h", {csr[11:0], rs1, get_func3(), rd, get_opcode()});
else if(instr_name == SFENCE_VMA)
binary = $sformatf("%8h", {get_func7(), 18'b0, get_opcode()});
else

View file

@ -0,0 +1,99 @@
/*
* Copyright 2018 Google LLC
* Copyright 2021 Silicon Labs, 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class riscv_zba_instr extends riscv_instr;
`uvm_object_utils(riscv_zba_instr)
function new(string name = "");
super.new(name);
endfunction : new
function void pre_randomize();
super.pre_randomize();
endfunction
virtual function void set_imm_len();
if (!(instr_name inside {SLLI_UW})) begin
imm_len = $clog2(XLEN) - 1;
end else begin
imm_len = $clog2(XLEN);
end
imm_mask = imm_mask << imm_len;
endfunction : set_imm_len
function bit[6:0] get_opcode();
case (instr_name) inside
SH1ADD, SH2ADD, SH3ADD : get_opcode = 7'b0110011;
SH1ADD_UW, SH2ADD_UW, SH3ADD_UW : get_opcode = 7'b0111011;
SLLI_UW : get_opcode = 7'b0011011;
default : get_opcode = super.get_opcode();
endcase
endfunction : get_opcode
virtual function bit [2:0] get_func3();
case (instr_name) inside
ADD_UW : get_func3 = 3'b000;
SH1ADD : get_func3 = 3'b010;
SH2ADD : get_func3 = 3'b100;
SH3ADD : get_func3 = 3'b110;
SH1ADD_UW : get_func3 = 3'b010;
SH2ADD_UW : get_func3 = 3'b100;
SH3ADD_UW : get_func3 = 3'b110;
SLLI_UW : get_func3 = 3'b001;
default : get_func3 = super.get_func3();
endcase
endfunction : get_func3
function bit [6:0] get_func7();
case (instr_name) inside
ADD_UW : get_func7 = 7'b0000100;
SH1ADD : get_func7 = 7'b0010000;
SH2ADD : get_func7 = 7'b0010000;
SH3ADD : get_func7 = 7'b0010000;
SH1ADD_UW : get_func7 = 7'b0010000;
SH2ADD_UW : get_func7 = 7'b0010000;
SH3ADD_UW : get_func7 = 7'b0010000;
SLLI_UW : get_func7 = 7'b0010000;
default : get_func7 = super.get_func7();
endcase
endfunction : get_func7
virtual function string convert2bin(string prefix = "");
string binary = "";
if (instr_name inside {SLLI_UW}) begin
binary = $sformatf("%8h", {5'b0_0001, imm[6:0], rs1, get_func3(), rd, get_opcode()});
end
else begin
binary = super.convert2bin(prefix);
end
endfunction : convert2bin
virtual function bit is_supported(riscv_instr_gen_config cfg);
return (cfg.enable_zba_extension &&
(RV32ZBA inside { supported_isa } || RV64ZBA inside { supported_isa }) &&
instr_name inside {
ADD_UW,
SH1ADD, SH1ADD_UW,
SH2ADD, SH2ADD_UW,
SH3ADD, SH3ADD_UW,
SLLI_UW
});
endfunction : is_supported
endclass : riscv_zba_instr

View file

@ -0,0 +1,238 @@
/*
* Copyright 2018 Google LLC
* Copyright 2021 Silicon Labs, 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class riscv_zbb_instr extends riscv_instr;
`uvm_object_utils(riscv_zbb_instr)
function new(string name = "");
super.new(name);
endfunction : new
virtual function void set_rand_mode();
super.set_rand_mode();
case (format) inside
R_FORMAT: begin
if (instr_name inside { ZEXT_H }) begin
has_rs2 = 1'b0;
end
end
I_FORMAT: begin
if (instr_name inside { CLZ, CLZW, CTZ, CTZW, CPOP, CPOPW, ORC_B, SEXT_B, SEXT_H, REV8 }) begin
has_imm = 1'b0;
end
end
endcase
endfunction : set_rand_mode
function void pre_randomize();
super.pre_randomize();
endfunction
function bit is_rv64();
is_rv64 = (group == RV64B);
endfunction : is_rv64
virtual function void set_imm_len();
if (format inside {I_FORMAT}) begin
if (instr_name inside {RORI}) begin
imm_len = $clog2(XLEN);
end else begin
imm_len = 5;
end
end
imm_mask = imm_mask << imm_len;
endfunction : set_imm_len
virtual function string convert2asm(string prefix = "");
string asm_str_final;
string asm_str;
asm_str = format_string(get_instr_name(), MAX_INSTR_STR_LEN);
case (format)
I_FORMAT : begin // instr rd rs1
if (!has_imm) begin
asm_str_final = $sformatf("%0s%0s, %0s", asm_str, rd.name(), rs1.name());
end
end
R_FORMAT : begin // instr rd rs1
if (!has_rs2) begin
asm_str_final = $sformatf("%0s%0s, %0s", asm_str, rd.name(), rs1.name());
end
end
default: `uvm_info(`gfn, $sformatf("Unsupported format %0s", format.name()), UVM_LOW)
endcase
if (asm_str_final == "") begin
return super.convert2asm(prefix);
end
if (comment != "") begin
asm_str_final = { asm_str_final, " #", comment };
end
return asm_str_final.tolower();
endfunction : convert2asm
function bit[6:0] get_opcode();
case (instr_name) inside
ANDN, MAX, MAXU, MIN, MINU,
ORN, ROL, ROR, XNOR : get_opcode = 7'b011_0011;
ZEXT_H : get_opcode = 7'b011_0011 | (is_rv64() << 3);
ROLW, RORW : get_opcode = 7'b011_1011;
CLZ, CPOP, CTZ, ORC_B,
CLZW, CPOPW, CTZW, RORIW : get_opcode = 7'b001_1011;
REV8, RORI, SEXT_B, SEXT_H : get_opcode = 7'b001_0011;
default : get_opcode = super.get_opcode();
endcase
endfunction : get_opcode
virtual function bit [2:0] get_func3();
case (instr_name) inside
ANDN : get_func3 = 3'b111;
CLZ : get_func3 = 3'b001;
CLZW : get_func3 = 3'b001;
CPOP : get_func3 = 3'b001;
CPOPW : get_func3 = 3'b001;
CTZ : get_func3 = 3'b001;
CTZW : get_func3 = 3'b001;
MAX : get_func3 = 3'b110;
MAXU : get_func3 = 3'b111;
MIN : get_func3 = 3'b100;
MINU : get_func3 = 3'b101;
ORC_B : get_func3 = 3'b101;
ORN : get_func3 = 3'b110;
REV8 : get_func3 = 3'b101;
ROL : get_func3 = 3'b001;
ROLW : get_func3 = 3'b001;
ROR : get_func3 = 3'b101;
RORW : get_func3 = 3'b101;
RORI : get_func3 = 3'b101;
RORIW : get_func3 = 3'b101;
SEXT_B : get_func3 = 3'b001;
SEXT_H : get_func3 = 3'b001;
XNOR : get_func3 = 3'b100;
ZEXT_H : get_func3 = 3'b100;
default : get_func3 = super.get_func3();
endcase
endfunction : get_func3
virtual function bit [4:0] get_func5();
case (instr_name) inside
CLZ : get_func5 = 5'b0_0000;
CLZW : get_func5 = 5'b0_0000;
CPOP : get_func5 = 5'b0_0010;
CPOPW : get_func5 = 5'b0_0010;
CTZ : get_func5 = 5'b0_0001;
CTZW : get_func5 = 5'b0_0001;
ORC_B : get_func5 = 5'b0_0111;
REV8 : get_func5 = 5'b1_1000;
SEXT_B : get_func5 = 5'b0_0100;
SEXT_H : get_func5 = 5'b0_0101;
endcase
endfunction : get_func5
virtual function bit [6:0] get_func7();
case (instr_name) inside
ANDN : get_func7 = 7'b010_0000;
CLZ : get_func7 = 7'b011_0000;
CLZW : get_func7 = 7'b011_0000;
CPOP : get_func7 = 7'b011_0000;
CPOPW : get_func7 = 7'b011_0000;
CTZ : get_func7 = 7'b011_0000;
CTZW : get_func7 = 7'b011_0000;
MAX : get_func7 = 7'b000_0101;
MAXU : get_func7 = 7'b000_0101;
MIN : get_func7 = 7'b000_0101;
MINU : get_func7 = 7'b000_0101;
ORC_B : get_func7 = 7'b001_0100;
ORN : get_func7 = 7'b010_0000;
REV8 : get_func7 = 7'b011_0100 | is_rv64(); // 0110101 64 bit
ROL : get_func7 = 7'b011_0000;
ROLW : get_func7 = 7'b011_0000;
ROR : get_func7 = 7'b011_0000;
RORW : get_func7 = 7'b011_0000;
RORI : get_func7 = 7'b011_0000;
RORIW : get_func7 = 7'b011_0000;
SEXT_B : get_func7 = 7'b011_0000;
SEXT_H : get_func7 = 7'b011_0000;
XNOR : get_func7 = 7'b010_0000;
ZEXT_H : get_func7 = 7'b000_0100;
default : get_func7 = super.get_func7();
endcase
endfunction : get_func7
virtual function string convert2bin(string prefix = "");
string binary = "";
case (format)
R_FORMAT: begin
if (instr_name inside { ZEXT_H }) begin
binary = $sformatf("%8h", {get_func7(), get_func5(), rs1, get_func3(), rd, get_opcode()});
end
end
I_FORMAT: begin
case (instr_name) inside
CLZ, CLZW, CPOP, CPOPW, CTZ, CTZW, ORC_B, REV8, SEXT_B, SEXT_H: begin
binary = $sformatf("%8h", {get_func7(), get_func5(), rs1, get_func3(), rd, get_opcode()});
end
RORIW: begin
binary = $sformatf("%8h", {get_func7(), imm[5:0], rs1, get_func3(), rd, get_opcode()});
end
RORI: begin
// set bit 0 of funct7 only if rv64 and shamt[MSB] is set
binary = $sformatf("%8h", {(get_func7() | (is_rv64() && imm[5])), imm[4:0], rs1, get_func3(), rd, get_opcode()});
end
endcase
end
default: begin
if (binary == "") begin
binary = super.convert2bin(prefix);
end
end
endcase // case (format)
endfunction : convert2bin
virtual function bit is_supported(riscv_instr_gen_config cfg);
return (cfg.enable_zbb_extension &&
(RV32ZBB inside { supported_isa } || RV64ZBB inside { supported_isa }) &&
instr_name inside {
ANDN,
CLZ, CLZW,
CPOP, CPOPW,
CTZ, CTZW,
MAX, MAXU,
MIN, MINU,
ORC_B, ORN,
REV8,
ROL, ROLW,
ROR, RORW,
RORI, RORIW,
SEXT_B, SEXT_H,
XNOR,
ZEXT_H
});
endfunction : is_supported
endclass : riscv_zbb_instr

View file

@ -0,0 +1,73 @@
/*
* Copyright 2018 Google LLC
* Copyright 2021 Silicon Labs, 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class riscv_zbc_instr extends riscv_instr;
`uvm_object_utils(riscv_zbc_instr)
function new(string name = "");
super.new(name);
endfunction : new
function void pre_randomize();
super.pre_randomize();
endfunction : pre_randomize
function bit[6:0] get_opcode();
case (instr_name) inside
CLMUL,
CLMULH,
CLMULR : get_opcode = 7'b011_0011;
default : get_opcode = super.get_opcode();
endcase
endfunction : get_opcode
function bit [2:0] get_func3();
case (instr_name) inside
CLMUL : get_func3 = 3'b001;
CLMULH : get_func3 = 3'b011;
CLMULR : get_func3 = 3'b010;
default : get_func3 = super.get_func3();
endcase
endfunction : get_func3
function bit [6:0] get_func7();
case (instr_name) inside
CLMUL : get_func7 = 7'b000_0101;
CLMULH : get_func7 = 7'b000_0101;
CLMULR : get_func7 = 7'b000_0101;
default : get_func7 = super.get_func7();
endcase
endfunction : get_func7
virtual function string convert2bin(string prefix = "");
string binary = "";
if (instr_name inside {CLMUL, CLMULH, CLMULR}) begin
binary = $sformatf("%8h", {get_func7(), rs2, rs1, get_func3(), rd, get_opcode()});
end
else begin
binary = super.convert2bin(prefix);
end
endfunction : convert2bin
virtual function bit is_supported(riscv_instr_gen_config cfg);
return (cfg.enable_zbc_extension &&
(RV32ZBC inside { supported_isa } || RV64ZBC inside { supported_isa }) &&
instr_name inside {
CLMUL, CLMULH, CLMULR
});
endfunction : is_supported
endclass : riscv_zbc_instr

View file

@ -0,0 +1,107 @@
/*
* Copyright 2018 Google LLC
* Copyright 2021 Silicon Labs, 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class riscv_zbs_instr extends riscv_instr;
`uvm_object_utils(riscv_zbs_instr)
function new(string name = "");
super.new(name);
endfunction : new
function void pre_randomize();
super.pre_randomize();
endfunction : pre_randomize
function bit is_rv64();
is_rv64 = (group == RV64B);
endfunction : is_rv64
virtual function void set_imm_len();
if (format inside {I_FORMAT}) begin
if (instr_name inside { BCLRI, BEXTI, BINVI, BSETI }) begin
imm_len = $clog2(XLEN);
end
end
imm_mask = imm_mask << imm_len;
endfunction : set_imm_len
function bit [6:0] get_opcode();
case (instr_name) inside
BCLR, BEXT, BINV, BSET,
BCLRI, BEXTI, BINVI, BSETI : begin
get_opcode = 7'b0010011;
end
default : get_opcode = super.get_opcode();
endcase
endfunction : get_opcode
function bit [2:0] get_func3();
case (instr_name) inside
BCLR : get_func3 = 3'b001;
BCLRI : get_func3 = 3'b001;
BEXT : get_func3 = 3'b101;
BEXTI : get_func3 = 3'b101;
BINV : get_func3 = 3'b001;
BINVI : get_func3 = 3'b001;
BSET : get_func3 = 3'b001;
BSETI : get_func3 = 3'b001;
default : get_func3 = super.get_func3();
endcase
endfunction : get_func3
function bit [6:0] get_func7();
case (instr_name) inside
BCLR : get_func7 = 7'b0100100;
BCLRI : get_func7 = 7'b0100100;
BEXT : get_func7 = 7'b0100100;
BEXTI : get_func7 = 7'b0100100;
BINV : get_func7 = 7'b0110100;
BINVI : get_func7 = 7'b0110100;
BSET : get_func7 = 7'b0010100;
BSETI : get_func7 = 7'b0010100;
default : get_func7 = super.get_func7();
endcase
endfunction : get_func7
virtual function string convert2bin(string prefix = "");
string binary = "";
case (format) inside
I_FORMAT : begin
case (instr_name) inside
BCLRI, BEXTI, BINVI, BSETI : begin
binary = $sformatf("%8h", {(get_func7() | (is_rv64() && imm[5])), imm[4:0], rs1, get_func3(), rd, get_opcode()});
end
endcase
end
default : begin
if (binary == "") begin
return super.convert2bin(prefix);
end
end
endcase
endfunction : convert2bin
virtual function bit is_supported(riscv_instr_gen_config cfg);
return (cfg.enable_zbs_extension &&
(RV32ZBS inside { supported_isa } || RV64ZBS inside { supported_isa }) &&
instr_name inside {
BCLR, BEXT, BINV, BSET,
BCLRI, BEXTI, BINVI, BSETI
});
endfunction : is_supported
endclass : riscv_zbs_instr

View file

@ -15,62 +15,40 @@
* limitations under the License.
*/
// Remaining bitmanip instructions of draft v.0.93 not ratified in v.1.00 (Zba, Zbb, Zbc, Zbs).
// LOGICAL instructions
`DEFINE_B_INSTR(SEXT_B, R_FORMAT, LOGICAL, RV32B)
`DEFINE_B_INSTR(SEXT_H, R_FORMAT, LOGICAL, RV32B)
`DEFINE_B_INSTR(ANDN, R_FORMAT, LOGICAL, RV32B)
`DEFINE_B_INSTR(ORN , R_FORMAT, LOGICAL, RV32B)
`DEFINE_B_INSTR(XNOR, R_FORMAT, LOGICAL, RV32B)
`DEFINE_B_INSTR(GORC, R_FORMAT, LOGICAL, RV32B)
`DEFINE_B_INSTR(GORCI, I_FORMAT, LOGICAL, RV32B, UIMM)
`DEFINE_B_INSTR(CMIX, R4_FORMAT, LOGICAL, RV32B)
`DEFINE_B_INSTR(CMOV, R4_FORMAT, LOGICAL, RV32B)
`DEFINE_B_INSTR(PACK, R_FORMAT, LOGICAL, RV32B)
`DEFINE_B_INSTR(PACKU, R_FORMAT, LOGICAL, RV32B)
`DEFINE_B_INSTR(PACKH, R_FORMAT, LOGICAL, RV32B)
`DEFINE_B_INSTR(GORC, R_FORMAT, LOGICAL, RV32B)
`DEFINE_B_INSTR(GORCI, I_FORMAT, LOGICAL, RV32B, UIMM)
`DEFINE_B_INSTR(CMIX, R4_FORMAT, LOGICAL, RV32B)
`DEFINE_B_INSTR(CMOV, R4_FORMAT, LOGICAL, RV32B)
`DEFINE_B_INSTR(PACK, R_FORMAT, LOGICAL, RV32B)
`DEFINE_B_INSTR(PACKU, R_FORMAT, LOGICAL, RV32B)
`DEFINE_B_INSTR(PACKH, R_FORMAT, LOGICAL, RV32B)
`DEFINE_B_INSTR(XPERM_N, R_FORMAT, LOGICAL, RV32B)
`DEFINE_B_INSTR(XPERM_B, R_FORMAT, LOGICAL, RV32B)
`DEFINE_B_INSTR(XPERM_H, R_FORMAT, LOGICAL, RV32B)
// SHIFT intructions
`DEFINE_B_INSTR(SLO, R_FORMAT, SHIFT, RV32B)
`DEFINE_B_INSTR(SRO, R_FORMAT, SHIFT, RV32B)
`DEFINE_B_INSTR(ROL, R_FORMAT, SHIFT, RV32B)
`DEFINE_B_INSTR(ROR, R_FORMAT, SHIFT, RV32B)
`DEFINE_B_INSTR(SBCLR, R_FORMAT, SHIFT, RV32B)
`DEFINE_B_INSTR(SBSET, R_FORMAT, SHIFT, RV32B)
`DEFINE_B_INSTR(SBINV, R_FORMAT, SHIFT, RV32B)
`DEFINE_B_INSTR(SBEXT, R_FORMAT, SHIFT, RV32B)
`DEFINE_B_INSTR(GREV, R_FORMAT, SHIFT, RV32B)
`DEFINE_B_INSTR(GREVI, I_FORMAT, SHIFT, RV32B , UIMM)
`DEFINE_B_INSTR(SLOI , I_FORMAT, SHIFT, RV32B ,UIMM)
`DEFINE_B_INSTR(SROI , I_FORMAT, SHIFT, RV32B ,UIMM)
`DEFINE_B_INSTR(RORI , I_FORMAT, SHIFT, RV32B ,UIMM)
`DEFINE_B_INSTR(SBCLRI , I_FORMAT, SHIFT, RV32B ,UIMM)
`DEFINE_B_INSTR(SBSETI , I_FORMAT, SHIFT, RV32B ,UIMM)
`DEFINE_B_INSTR(SBINVI , I_FORMAT, SHIFT, RV32B ,UIMM)
`DEFINE_B_INSTR(SBEXTI , I_FORMAT, SHIFT, RV32B ,UIMM)
`DEFINE_B_INSTR(SLO, R_FORMAT, SHIFT, RV32B)
`DEFINE_B_INSTR(SRO, R_FORMAT, SHIFT, RV32B)
`DEFINE_B_INSTR(SLOI, I_FORMAT, SHIFT, RV32B, UIMM)
`DEFINE_B_INSTR(SROI, I_FORMAT, SHIFT, RV32B, UIMM)
`DEFINE_B_INSTR(GREV, R_FORMAT, SHIFT, RV32B)
`DEFINE_B_INSTR(GREVI, I_FORMAT, SHIFT, RV32B, UIMM)
`DEFINE_B_INSTR(FSL, R4_FORMAT, SHIFT, RV32B)
`DEFINE_B_INSTR(FSR, R4_FORMAT, SHIFT, RV32B)
`DEFINE_B_INSTR(FSRI, I_FORMAT, SHIFT, RV32B ,UIMM)
`DEFINE_B_INSTR(FSRI, I_FORMAT, SHIFT, RV32B, UIMM)
// ARITHMETIC intructions
`DEFINE_B_INSTR(CLZ, R_FORMAT, ARITHMETIC, RV32B)
`DEFINE_B_INSTR(CTZ, R_FORMAT, ARITHMETIC, RV32B)
`DEFINE_B_INSTR(PCNT, R_FORMAT, ARITHMETIC, RV32B)
`DEFINE_B_INSTR(CRC32_B, R_FORMAT, ARITHMETIC, RV32B)
`DEFINE_B_INSTR(CRC32_H, R_FORMAT, ARITHMETIC, RV32B)
`DEFINE_B_INSTR(CRC32_W, R_FORMAT, ARITHMETIC, RV32B)
`DEFINE_B_INSTR(CRC32C_B, R_FORMAT, ARITHMETIC, RV32B)
`DEFINE_B_INSTR(CRC32C_H, R_FORMAT, ARITHMETIC, RV32B)
`DEFINE_B_INSTR(CRC32C_W, R_FORMAT, ARITHMETIC, RV32B)
`DEFINE_B_INSTR(CLMUL, R_FORMAT, ARITHMETIC, RV32B)
`DEFINE_B_INSTR(CLMULR, R_FORMAT, ARITHMETIC, RV32B)
`DEFINE_B_INSTR(CLMULH, R_FORMAT, ARITHMETIC, RV32B)
`DEFINE_B_INSTR(MIN, R_FORMAT, ARITHMETIC, RV32B)
`DEFINE_B_INSTR(MAX, R_FORMAT, ARITHMETIC, RV32B)
`DEFINE_B_INSTR(MINU, R_FORMAT, ARITHMETIC, RV32B)
`DEFINE_B_INSTR(MAXU, R_FORMAT, ARITHMETIC, RV32B)
`DEFINE_B_INSTR(SHFL, R_FORMAT, ARITHMETIC, RV32B)
`DEFINE_B_INSTR(UNSHFL, R_FORMAT, ARITHMETIC, RV32B)
`DEFINE_B_INSTR(BDEP, R_FORMAT, ARITHMETIC, RV32B)
`DEFINE_B_INSTR(BEXT, R_FORMAT, ARITHMETIC, RV32B)
`DEFINE_B_INSTR(BFP, R_FORMAT, ARITHMETIC, RV32B)
`DEFINE_B_INSTR(SHFLI, I_FORMAT, ARITHMETIC, RV32B, UIMM)
`DEFINE_B_INSTR(UNSHFLI, I_FORMAT, ARITHMETIC, RV32B, UIMM)
`DEFINE_B_INSTR(CRC32_B, R_FORMAT, ARITHMETIC, RV32B)
`DEFINE_B_INSTR(CRC32_H, R_FORMAT, ARITHMETIC, RV32B)
`DEFINE_B_INSTR(CRC32_W, R_FORMAT, ARITHMETIC, RV32B)
`DEFINE_B_INSTR(CRC32C_B, R_FORMAT, ARITHMETIC, RV32B)
`DEFINE_B_INSTR(CRC32C_H, R_FORMAT, ARITHMETIC, RV32B)
`DEFINE_B_INSTR(CRC32C_W, R_FORMAT, ARITHMETIC, RV32B)
`DEFINE_B_INSTR(SHFL, R_FORMAT, ARITHMETIC, RV32B)
`DEFINE_B_INSTR(UNSHFL, R_FORMAT, ARITHMETIC, RV32B)
`DEFINE_B_INSTR(SHFLI, I_FORMAT, ARITHMETIC, RV32B, UIMM)
`DEFINE_B_INSTR(UNSHFLI, I_FORMAT, ARITHMETIC, RV32B, UIMM)
`DEFINE_B_INSTR(BCOMPRESS, R_FORMAT, ARITHMETIC, RV32B)
`DEFINE_B_INSTR(BDECOMPRESS, R_FORMAT, ARITHMETIC, RV32B)
`DEFINE_B_INSTR(BFP, R_FORMAT, ARITHMETIC, RV32B)

View file

@ -0,0 +1,20 @@
/*
* Copyright 2018 Google LLC
* Copyright 2021 Silicon Labs, 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
`DEFINE_ZBA_INSTR(SH1ADD, R_FORMAT, ARITHMETIC, RV32ZBA);
`DEFINE_ZBA_INSTR(SH2ADD, R_FORMAT, ARITHMETIC, RV32ZBA);
`DEFINE_ZBA_INSTR(SH3ADD, R_FORMAT, ARITHMETIC, RV32ZBA);

View file

@ -0,0 +1,35 @@
/*
* Copyright 2018 Google LLC
* Copyright 2021 Silicon Labs, 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
`DEFINE_ZBB_INSTR(ANDN, R_FORMAT, LOGICAL, RV32ZBB);
`DEFINE_ZBB_INSTR(CLZ, I_FORMAT, ARITHMETIC, RV32ZBB);
`DEFINE_ZBB_INSTR(CPOP, I_FORMAT, ARITHMETIC, RV32ZBB);
`DEFINE_ZBB_INSTR(CTZ, I_FORMAT, ARITHMETIC, RV32ZBB);
`DEFINE_ZBB_INSTR(MAX, R_FORMAT, ARITHMETIC, RV32ZBB);
`DEFINE_ZBB_INSTR(MAXU, R_FORMAT, ARITHMETIC, RV32ZBB);
`DEFINE_ZBB_INSTR(MIN, R_FORMAT, ARITHMETIC, RV32ZBB);
`DEFINE_ZBB_INSTR(MINU, R_FORMAT, ARITHMETIC, RV32ZBB);
`DEFINE_ZBB_INSTR(ORC_B, I_FORMAT, LOGICAL, RV32ZBB);
`DEFINE_ZBB_INSTR(ORN, R_FORMAT, LOGICAL, RV32ZBB);
`DEFINE_ZBB_INSTR(REV8, I_FORMAT, SHIFT, RV32ZBB);
`DEFINE_ZBB_INSTR(ROL, R_FORMAT, SHIFT, RV32ZBB);
`DEFINE_ZBB_INSTR(ROR, R_FORMAT, SHIFT, RV32ZBB);
`DEFINE_ZBB_INSTR(RORI, I_FORMAT, SHIFT, RV32ZBB, UIMM);
`DEFINE_ZBB_INSTR(SEXT_B, I_FORMAT, ARITHMETIC, RV32ZBB);
`DEFINE_ZBB_INSTR(SEXT_H, I_FORMAT, ARITHMETIC, RV32ZBB);
`DEFINE_ZBB_INSTR(XNOR, R_FORMAT, LOGICAL, RV32ZBB);
`DEFINE_ZBB_INSTR(ZEXT_H, R_FORMAT, ARITHMETIC, RV32ZBB);

View file

@ -0,0 +1,20 @@
/*
* Copyright 2018 Google LLC
* Copyright 2021 Silicon Labs, 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
`DEFINE_ZBC_INSTR(CLMUL, R_FORMAT, ARITHMETIC, RV32ZBC)
`DEFINE_ZBC_INSTR(CLMULH, R_FORMAT, ARITHMETIC, RV32ZBC)
`DEFINE_ZBC_INSTR(CLMULR, R_FORMAT, ARITHMETIC, RV32ZBC)

View file

@ -0,0 +1,25 @@
/*
* Copyright 2018 Google LLC
* Copyright 2021 Silicon Labs, 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
`DEFINE_ZBS_INSTR(BCLR, R_FORMAT, SHIFT, RV32ZBS)
`DEFINE_ZBS_INSTR(BCLRI, I_FORMAT, SHIFT, RV32ZBS, UIMM)
`DEFINE_ZBS_INSTR(BEXT, R_FORMAT, SHIFT, RV32ZBS)
`DEFINE_ZBS_INSTR(BEXTI, I_FORMAT, SHIFT, RV32ZBS, UIMM)
`DEFINE_ZBS_INSTR(BINV, R_FORMAT, SHIFT, RV32ZBS)
`DEFINE_ZBS_INSTR(BINVI, I_FORMAT, SHIFT, RV32ZBS, UIMM)
`DEFINE_ZBS_INSTR(BSET, R_FORMAT, SHIFT, RV32ZBS)
`DEFINE_ZBS_INSTR(BSETI, I_FORMAT, SHIFT, RV32ZBS, UIMM)

View file

@ -15,54 +15,32 @@
* limitations under the License.
*/
// ARITHMETIC intructions
`DEFINE_B_INSTR(BMATOR, R_FORMAT, ARITHMETIC, RV64B)
`DEFINE_B_INSTR(BMATXOR, R_FORMAT, ARITHMETIC, RV64B)
`DEFINE_B_INSTR(BMATFLIP, R_FORMAT, ARITHMETIC, RV64B)
`DEFINE_B_INSTR(CRC32_D, R_FORMAT, ARITHMETIC, RV64B)
`DEFINE_B_INSTR(CRC32C_D, R_FORMAT, ARITHMETIC, RV64B)
`DEFINE_B_INSTR(ADDIWU, I_FORMAT, ARITHMETIC, RV64B)
`DEFINE_B_INSTR(ADDWU, R_FORMAT, ARITHMETIC, RV64B)
`DEFINE_B_INSTR(SUBWU, R_FORMAT, ARITHMETIC, RV64B)
`DEFINE_B_INSTR(ADDU_W, R_FORMAT, ARITHMETIC, RV64B)
`DEFINE_B_INSTR(SUBU_W, R_FORMAT, ARITHMETIC, RV64B)
`DEFINE_B_INSTR(CLZW, R_FORMAT, ARITHMETIC, RV64B)
`DEFINE_B_INSTR(CTZW, R_FORMAT, ARITHMETIC, RV64B)
`DEFINE_B_INSTR(PCNTW, R_FORMAT, ARITHMETIC, RV64B)
`DEFINE_B_INSTR(CLMULW, R_FORMAT, ARITHMETIC, RV64B)
`DEFINE_B_INSTR(CLMULRW, R_FORMAT, ARITHMETIC, RV64B)
`DEFINE_B_INSTR(CLMULHW, R_FORMAT, ARITHMETIC, RV64B)
`DEFINE_B_INSTR(SHFLW, R_FORMAT, ARITHMETIC, RV64B)
`DEFINE_B_INSTR(UNSHFLW, R_FORMAT, ARITHMETIC, RV64B)
`DEFINE_B_INSTR(BDEPW, R_FORMAT, ARITHMETIC, RV64B)
`DEFINE_B_INSTR(BEXTW, R_FORMAT, ARITHMETIC, RV64B)
`DEFINE_B_INSTR(BFPW, R_FORMAT, ARITHMETIC, RV64B)
// Remaining bitmanip instructions of draft v.0.93 not ratified in v.1.00 (Zba, Zbb, Zbc, Zbs).
// ARITHMETIC intructions
`DEFINE_B_INSTR(BMATOR, R_FORMAT, ARITHMETIC, RV64B)
`DEFINE_B_INSTR(BMATXOR, R_FORMAT, ARITHMETIC, RV64B)
`DEFINE_B_INSTR(BMATFLIP, R_FORMAT, ARITHMETIC, RV64B)
`DEFINE_B_INSTR(CRC32_D, R_FORMAT, ARITHMETIC, RV64B)
`DEFINE_B_INSTR(CRC32C_D, R_FORMAT, ARITHMETIC, RV64B)
`DEFINE_B_INSTR(SHFLW, R_FORMAT, ARITHMETIC, RV64B)
`DEFINE_B_INSTR(UNSHFLW, R_FORMAT, ARITHMETIC, RV64B)
`DEFINE_B_INSTR(BCOMPRESSW, R_FORMAT, ARITHMETIC, RV64B)
`DEFINE_B_INSTR(BDECOMPRESSW, R_FORMAT, ARITHMETIC, RV64B)
`DEFINE_B_INSTR(BFPW, R_FORMAT, ARITHMETIC, RV64B)
// SHIFT intructions
`DEFINE_B_INSTR(SLLIU_W, I_FORMAT, SHIFT, RV64B, UIMM)
`DEFINE_B_INSTR(SLOW, R_FORMAT, SHIFT, RV64B)
`DEFINE_B_INSTR(SROW, R_FORMAT, SHIFT, RV64B)
`DEFINE_B_INSTR(ROLW, R_FORMAT, SHIFT, RV64B)
`DEFINE_B_INSTR(RORW, R_FORMAT, SHIFT, RV64B)
`DEFINE_B_INSTR(SBCLRW, R_FORMAT, SHIFT, RV64B)
`DEFINE_B_INSTR(SBSETW, R_FORMAT, SHIFT, RV64B)
`DEFINE_B_INSTR(SBINVW, R_FORMAT, SHIFT, RV64B)
`DEFINE_B_INSTR(SBEXTW, R_FORMAT, SHIFT, RV64B)
`DEFINE_B_INSTR(GREVW, R_FORMAT, SHIFT, RV64B)
`DEFINE_B_INSTR(SLOIW , I_FORMAT, SHIFT, RV64B, UIMM)
`DEFINE_B_INSTR(SROIW , I_FORMAT, SHIFT, RV64B, UIMM)
`DEFINE_B_INSTR(RORIW , I_FORMAT, SHIFT, RV64B, UIMM)
`DEFINE_B_INSTR(SBCLRIW , I_FORMAT, SHIFT, RV64B, UIMM)
`DEFINE_B_INSTR(SBSETIW , I_FORMAT, SHIFT, RV64B, UIMM)
`DEFINE_B_INSTR(SBINVIW , I_FORMAT, SHIFT, RV64B, UIMM)
`DEFINE_B_INSTR(GREVIW, I_FORMAT, SHIFT, RV64B, UIMM)
`DEFINE_B_INSTR(SLOIW, I_FORMAT, SHIFT, RV64B, UIMM)
`DEFINE_B_INSTR(SROIW, I_FORMAT, SHIFT, RV64B, UIMM)
`DEFINE_B_INSTR(GREVW, R_FORMAT, SHIFT, RV64B)
`DEFINE_B_INSTR(GREVIW, I_FORMAT, SHIFT, RV64B, UIMM)
`DEFINE_B_INSTR(FSLW, R4_FORMAT, SHIFT, RV64B)
`DEFINE_B_INSTR(FSRW, R4_FORMAT, SHIFT, RV64B)
`DEFINE_B_INSTR(FSRIW, I_FORMAT, SHIFT, RV64B, UIMM)
// LOGICAL instructions
`DEFINE_B_INSTR(GORCW, R_FORMAT, LOGICAL, RV64B)
`DEFINE_B_INSTR(GORCIW, I_FORMAT, LOGICAL, RV64B, UIMM)
`DEFINE_B_INSTR(PACKW, R_FORMAT, LOGICAL, RV64B)
`DEFINE_B_INSTR(PACKUW, R_FORMAT, LOGICAL, RV64B)
`DEFINE_B_INSTR(GORCW, R_FORMAT, LOGICAL, RV64B)
`DEFINE_B_INSTR(GORCIW, I_FORMAT, LOGICAL, RV64B, UIMM)
`DEFINE_B_INSTR(PACKW, R_FORMAT, LOGICAL, RV64B)
`DEFINE_B_INSTR(PACKUW, R_FORMAT, LOGICAL, RV64B)
`DEFINE_B_INSTR(XPERM_W, R_FORMAT, LOGICAL, RV64B)

View file

@ -0,0 +1,22 @@
/*
* Copyright 2018 Google LLC
* Copyright 2021 Silicon Labs, 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
`DEFINE_ZBA_INSTR(ADD_UW, R_FORMAT, ARITHMETIC, RV64ZBA);
`DEFINE_ZBA_INSTR(SH1ADD_UW, R_FORMAT, ARITHMETIC, RV64ZBA);
`DEFINE_ZBA_INSTR(SH2ADD_UW, R_FORMAT, ARITHMETIC, RV64ZBA);
`DEFINE_ZBA_INSTR(SH3ADD_UW, R_FORMAT, ARITHMETIC, RV64ZBA);
`DEFINE_ZBA_INSTR(SLLI_UW, I_FORMAT, SHIFT, RV64ZBA, UIMM);

View file

@ -0,0 +1,23 @@
/*
* Copyright 2018 Google LLC
* Copyright 2021 Silicon Labs, 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
`DEFINE_ZBB_INSTR(CLZW, I_FORMAT, ARITHMETIC, RV64ZBB);
`DEFINE_ZBB_INSTR(CPOPW, I_FORMAT, ARITHMETIC, RV64ZBB);
`DEFINE_ZBB_INSTR(CTZW, I_FORMAT, ARITHMETIC, RV64ZBB);
`DEFINE_ZBB_INSTR(ROLW, R_FORMAT, SHIFT, RV64ZBB);
`DEFINE_ZBB_INSTR(RORW, R_FORMAT, SHIFT, RV64ZBB);
`DEFINE_ZBB_INSTR(RORIW, I_FORMAT, SHIFT, RV64ZBB, UIMM);

View file

@ -452,6 +452,8 @@ class riscv_asm_program_gen extends uvm_object;
RV32D, RV64D, RV32DC : misa[MISA_EXT_D] = 1'b1;
RVV : misa[MISA_EXT_V] = 1'b1;
RV32X, RV64X : misa[MISA_EXT_X] = 1'b1;
RV32ZBA, RV32ZBB, RV32ZBC, RV32ZBS,
RV64ZBA, RV64ZBB, RV64ZBC, RV64ZBS : ; // No Misa bit for Zb* extensions
default : `uvm_fatal(`gfn, $sformatf("%0s is not yet supported",
supported_isa[i].name()))
endcase

View file

@ -105,3 +105,22 @@
class riscv_``instr_n``_instr extends riscv_b_instr; \
`INSTR_BODY(instr_n, instr_format, instr_category, instr_group, imm_tp)
//Zba-extension instruction
`define DEFINE_ZBA_INSTR(instr_n, instr_format, instr_category, instr_group, imm_tp = IMM) \
class riscv_``instr_n``_instr extends riscv_zba_instr; \
`INSTR_BODY(instr_n, instr_format, instr_category, instr_group, imm_tp)
//Zbb-extension instruction
`define DEFINE_ZBB_INSTR(instr_n, instr_format, instr_category, instr_group, imm_tp = IMM) \
class riscv_``instr_n``_instr extends riscv_zbb_instr; \
`INSTR_BODY(instr_n, instr_format, instr_category, instr_group, imm_tp)
//Zbc-extension instruction
`define DEFINE_ZBC_INSTR(instr_n, instr_format, instr_category, instr_group, imm_tp = IMM) \
class riscv_``instr_n``_instr extends riscv_zbc_instr; \
`INSTR_BODY(instr_n, instr_format, instr_category, instr_group, imm_tp)
//Zbs-extension instruction
`define DEFINE_ZBS_INSTR(instr_n, instr_format, instr_category, instr_group, imm_tp = IMM) \
class riscv_``instr_n``_instr extends riscv_zbs_instr; \
`INSTR_BODY(instr_n, instr_format, instr_category, instr_group, imm_tp)

View file

@ -181,6 +181,38 @@ class riscv_illegal_instr extends uvm_object;
}
}
constraint zba_extension_c {
if (RV32ZBA inside {supported_isa}) {
if (exception inside {kIllegalFunc3, kIllegalFunc7}) {
!(opcode inside {7'b0110011, 7'b0111011, 7'b0011011});
}
}
}
constraint zbb_extension_c {
if (RV32ZBB inside {supported_isa}) {
if (exception inside {kIllegalFunc3, kIllegalFunc7}) {
!(opcode inside {7'b0110011, 7'b0010011, 7'b0111011, 7'b0011011});
}
}
}
constraint zbc_extension_c {
if (RV32ZBB inside {supported_isa}) {
if (exception inside {kIllegalFunc3, kIllegalFunc7}) {
!(opcode inside {7'b0110011});
}
}
}
constraint zbs_extension_c {
if (RV32ZBS inside {supported_isa}) {
if (exception inside {kIllegalFunc3, kIllegalFunc7}) {
!(opcode inside {7'b0110011, 7'b0010011});
}
}
}
constraint illegal_compressed_op_c {
if (exception == kIllegalCompressedOpcode) {
c_op != 2'b01;

View file

@ -34,6 +34,10 @@
`define SAMPLE_F(cg, val) `SAMPLE_W_TYPE(cg, val, riscv_floating_point_instr)
`define SAMPLE_B(cg, val) `SAMPLE_W_TYPE(cg, val, riscv_b_instr)
`define SAMPLE_ZBA(cg, val) `SAMPLE_W_TYPE(cg, val, riscv_zba_instr)
`define SAMPLE_ZBB(cg, val) `SAMPLE_W_TYPE(cg, val, riscv_zbb_instr)
`define SAMPLE_ZBC(cg, val) `SAMPLE_W_TYPE(cg, val, riscv_zbc_instr)
`define SAMPLE_ZBS(cg, val) `SAMPLE_W_TYPE(cg, val, riscv_zbs_instr)
`define INSTR_CG_BEGIN(INSTR_NAME, INSTR_CLASS = riscv_instr) \
covergroup ``INSTR_NAME``_cg with function sample(INSTR_CLASS instr);
@ -377,6 +381,58 @@
`FP_SPECIAL_VALUES_CP(instr.fs1_value, fs1_value, PRECISION) \
`DV(cp_gpr_hazard : coverpoint instr.gpr_hazard;) \
`define ZBA_I_INSTR_CG_BEGIN(INSTR_NAME) \
`INSTR_CG_BEGIN(INSTR_NAME, riscv_zba_instr) \
cp_rs1 : coverpoint instr.rs1; \
cp_rd : coverpoint instr.rd; \
`DV(cp_gpr_hazard : coverpoint instr.gpr_hazard;)
`define ZBA_R_INSTR_CG_BEGIN(INSTR_NAME) \
`INSTR_CG_BEGIN(INSTR_NAME, riscv_zba_instr) \
cp_rs1 : coverpoint instr.rs1; \
cp_rs2 : coverpoint instr.rs2; \
cp_rd : coverpoint instr.rd; \
`DV(cp_gpr_hazard : coverpoint instr.gpr_hazard;) \
`define ZBB_I_INSTR_CG_BEGIN(INSTR_NAME) \
`INSTR_CG_BEGIN(INSTR_NAME, riscv_zbb_instr) \
cp_rs1 : coverpoint instr.rs1; \
cp_rd : coverpoint instr.rd; \
`DV(cp_gpr_hazard : coverpoint instr.gpr_hazard;)
`define ZBB_R_INSTR_CG_BEGIN(INSTR_NAME) \
`INSTR_CG_BEGIN(INSTR_NAME, riscv_zbb_instr) \
cp_rs1 : coverpoint instr.rs1; \
cp_rs2 : coverpoint instr.rs2; \
cp_rd : coverpoint instr.rd; \
`DV(cp_gpr_hazard : coverpoint instr.gpr_hazard;) \
`define ZBC_I_INSTR_CG_BEGIN(INSTR_NAME) \
`INSTR_CG_BEGIN(INSTR_NAME, riscv_zbc_instr) \
cp_rs1 : coverpoint instr.rs1; \
cp_rd : coverpoint instr.rd; \
`DV(cp_gpr_hazard : coverpoint instr.gpr_hazard;)
`define ZBC_R_INSTR_CG_BEGIN(INSTR_NAME) \
`INSTR_CG_BEGIN(INSTR_NAME, riscv_zbc_instr) \
cp_rs1 : coverpoint instr.rs1; \
cp_rs2 : coverpoint instr.rs2; \
cp_rd : coverpoint instr.rd; \
`DV(cp_gpr_hazard : coverpoint instr.gpr_hazard;) \
`define ZBS_I_INSTR_CG_BEGIN(INSTR_NAME) \
`INSTR_CG_BEGIN(INSTR_NAME, riscv_zbs_instr) \
cp_rs1 : coverpoint instr.rs1; \
cp_rd : coverpoint instr.rd; \
`DV(cp_gpr_hazard : coverpoint instr.gpr_hazard;)
`define ZBS_R_INSTR_CG_BEGIN(INSTR_NAME) \
`INSTR_CG_BEGIN(INSTR_NAME, riscv_zbs_instr) \
cp_rs1 : coverpoint instr.rs1; \
cp_rs2 : coverpoint instr.rs2; \
cp_rd : coverpoint instr.rd; \
`DV(cp_gpr_hazard : coverpoint instr.gpr_hazard;) \
`define B_I_INSTR_CG_BEGIN(INSTR_NAME) \
`INSTR_CG_BEGIN(INSTR_NAME, riscv_b_instr) \
cp_rs1 : coverpoint instr.rs1; \
@ -857,43 +913,177 @@ class riscv_instr_cover_group;
`FCLASS_INSTR_CG_BEGIN(fclass_d, D)
`CG_END
// B extension
// B extension instructions ratified in v.1.00 (Zba, Zbb, Zbc, Zbs).
`ZBA_R_INSTR_CG_BEGIN(sh1add)
`CG_END
`ZBA_R_INSTR_CG_BEGIN(sh2add)
`CG_END
`ZBA_R_INSTR_CG_BEGIN(sh3add)
`CG_END
`ZBA_R_INSTR_CG_BEGIN(sh1add_uw)
`CG_END
`ZBA_R_INSTR_CG_BEGIN(sh2add_uw)
`CG_END
`ZBA_R_INSTR_CG_BEGIN(sh3add_uw)
`CG_END
// Count Leading/Trailing Zeros (clz, ctz)
`B_R_INSTR_NO_RS2_CG_BEGIN(clz)
`ZBB_I_INSTR_CG_BEGIN(clz)
`CP_VALUE_RANGE(num_leading_zeros, instr.rd_value, 0, XLEN-1)
`CG_END
`B_R_INSTR_NO_RS2_CG_BEGIN(ctz)
`ZBB_I_INSTR_CG_BEGIN(ctz)
`CP_VALUE_RANGE(num_trailing_zeros, instr.rd_value, 0, XLEN-1)
`CG_END
`B_R_INSTR_NO_RS2_CG_BEGIN(clzw)
`CP_VALUE_RANGE(num_leading_zeros, instr.rd_value, 0, XLEN/2-1)
`ZBB_I_INSTR_CG_BEGIN(clzw)
`CP_VALUE_RANGE(num_leading_zeros, instr.rd_value, 0, XLEN-1)
`CG_END
`B_R_INSTR_NO_RS2_CG_BEGIN(ctzw)
`CP_VALUE_RANGE(num_trailing_zeros, instr.rd_value, 0, XLEN/2-1)
`ZBB_I_INSTR_CG_BEGIN(ctzw)
`CP_VALUE_RANGE(num_trailing_zeros, instr.rd_value, 0, XLEN-1)
`CG_END
// Count Bits Set (pcnt)
`B_R_INSTR_NO_RS2_CG_BEGIN(pcnt)
`ZBB_I_INSTR_CG_BEGIN(cpop)
`CP_VALUE_RANGE(num_set_bits, instr.rd_value, 0, XLEN-1)
`CG_END
`B_R_INSTR_NO_RS2_CG_BEGIN(pcntw)
`CP_VALUE_RANGE(num_set_bits, instr.rd_value, 0, XLEN/2-1)
`ZBB_I_INSTR_CG_BEGIN(cpopw)
`CP_VALUE_RANGE(num_set_bits, instr.rd_value, 0, XLEN-1)
`CG_END
// Logic-with-negate (andn, orn, xnor)
`B_R_INSTR_CG_BEGIN(andn)
`ZBB_R_INSTR_CG_BEGIN(andn)
`CG_END
`B_R_INSTR_CG_BEGIN(orn)
`ZBB_R_INSTR_CG_BEGIN(orn)
`CG_END
`B_R_INSTR_CG_BEGIN(xnor)
`ZBB_R_INSTR_CG_BEGIN(xnor)
`CG_END
// Or-combine
`ZBB_R_INSTR_CG_BEGIN(orc_b)
`CP_VALUE_RANGE(or_combine_mode, instr.imm, 0, XLEN-1)
`CG_END
// Min/max instructions (min, max, minu, maxu)
`ZBB_R_INSTR_CG_BEGIN(min)
cp_rs1_gt_rs2 : coverpoint (longint'(instr.rs1_value) > longint'(instr.rs2_value));
cp_rs1_eq_rs2 : coverpoint (instr.rs1_value == instr.rs2_value) {
bins equal = {1};
}
`CG_END
`ZBB_R_INSTR_CG_BEGIN(max)
cp_rs1_gt_rs2 : coverpoint (longint'(instr.rs1_value) > longint'(instr.rs2_value));
cp_rs1_eq_rs2 : coverpoint (instr.rs1_value == instr.rs2_value) {
bins equal = {1};
}
`CG_END
`ZBB_R_INSTR_CG_BEGIN(minu)
cp_rs1_gt_rs2 : coverpoint (instr.rs1_value > instr.rs2_value);
cp_rs1_eq_rs2 : coverpoint (instr.rs1_value == instr.rs2_value) {
bins equal = {1};
}
`CG_END
`ZBB_R_INSTR_CG_BEGIN(maxu)
cp_rs1_gt_rs2 : coverpoint (instr.rs1_value > instr.rs2_value);
cp_rs1_eq_rs2 : coverpoint (instr.rs1_value == instr.rs2_value) {
bins equal = {1};
}
`CG_END
// Sign-extend instructions (sext.b, sext.h)
`ZBB_I_INSTR_CG_BEGIN(sext_b)
`CG_END
`ZBB_I_INSTR_CG_BEGIN(sext_h)
`CG_END
`ZBB_I_INSTR_CG_BEGIN(zext_h)
`CG_END
// Rotate (Left/Right) (rol, ror, rori)
`ZBB_R_INSTR_CG_BEGIN(ror)
`CP_VALUE_RANGE(num_bit_rotate, instr.rs2_value, 0, XLEN-1)
`CG_END
`ZBB_R_INSTR_CG_BEGIN(rol)
`CP_VALUE_RANGE(num_bit_rotate, instr.rs2_value, 0, XLEN-1)
`CG_END
`ZBB_I_INSTR_CG_BEGIN(rori)
`CP_VALUE_RANGE(num_bit_rotate, instr.imm, 0, XLEN-1)
`CG_END
`ZBB_R_INSTR_CG_BEGIN(rorw)
`CP_VALUE_RANGE(num_bit_rotate, instr.rs2_value, 0, XLEN/2-1)
`CG_END
`ZBB_R_INSTR_CG_BEGIN(rolw)
`CP_VALUE_RANGE(num_bit_rotate, instr.rs2_value, 0, XLEN/2-1)
`CG_END
`ZBB_I_INSTR_CG_BEGIN(roriw)
`CP_VALUE_RANGE(num_bit_rotate, instr.imm, 0, XLEN/2-1)
`CG_END
`ZBB_R_INSTR_CG_BEGIN(rev8)
`CG_END
// Multiplication
`ZBC_R_INSTR_CG_BEGIN(clmul)
`CG_END
`ZBC_R_INSTR_CG_BEGIN(clmulh)
`CG_END
`ZBC_R_INSTR_CG_BEGIN(clmulr)
`CG_END
`ZBA_I_INSTR_CG_BEGIN(slli_uw)
`CP_VALUE_RANGE(num_shift, instr.imm, 0, XLEN-1)
`CG_END
`ZBA_R_INSTR_CG_BEGIN(add_uw)
`CG_END
`ZBS_R_INSTR_CG_BEGIN(bclr)
`CP_VALUE_RANGE(bit_location, instr.rs2_value, 0, XLEN-1)
`CG_END
`ZBS_I_INSTR_CG_BEGIN(bclri)
`CP_VALUE_RANGE(bit_location, instr.imm, 0, XLEN-1)
`CG_END
`ZBS_R_INSTR_CG_BEGIN(bext)
`CP_VALUE_RANGE(bit_location, instr.rs2_value, 0, XLEN-1)
`CG_END
`ZBS_I_INSTR_CG_BEGIN(bexti)
`CP_VALUE_RANGE(bit_location, instr.imm, 0, XLEN-1)
`CG_END
`ZBS_R_INSTR_CG_BEGIN(binv)
`CP_VALUE_RANGE(bit_location, instr.rs2_value, 0, XLEN-1)
`CG_END
`ZBS_I_INSTR_CG_BEGIN(binvi)
`CP_VALUE_RANGE(bit_location, instr.imm, 0, XLEN-1)
`CG_END
`ZBS_R_INSTR_CG_BEGIN(bset)
`CP_VALUE_RANGE(bit_location, instr.rs2_value, 0, XLEN-1)
`CG_END
`ZBS_I_INSTR_CG_BEGIN(bseti)
`CP_VALUE_RANGE(bit_location, instr.imm, 0, XLEN-1)
`CG_END
// Remaining bitmanip instructions of draft v.0.93 not ratified in v.1.00 (Zba, Zbb, Zbc, Zbs).
// Pack two words in one register (pack, packu, packh)
`B_R_INSTR_CG_BEGIN(pack)
`CG_END
@ -910,75 +1100,6 @@ class riscv_instr_cover_group;
`B_R_INSTR_CG_BEGIN(packuw)
`CG_END
// Min/max instructions (min, max, minu, maxu)
`B_R_INSTR_CG_BEGIN(min)
cp_rs1_gt_rs2 : coverpoint (longint'(instr.rs1_value) > longint'(instr.rs2_value));
cp_rs1_eq_rs2 : coverpoint (instr.rs1_value == instr.rs2_value) {
bins equal = {1};
}
`CG_END
`B_R_INSTR_CG_BEGIN(max)
cp_rs1_gt_rs2 : coverpoint (longint'(instr.rs1_value) > longint'(instr.rs2_value));
cp_rs1_eq_rs2 : coverpoint (instr.rs1_value == instr.rs2_value) {
bins equal = {1};
}
`CG_END
`B_R_INSTR_CG_BEGIN(minu)
cp_rs1_gt_rs2 : coverpoint (instr.rs1_value > instr.rs2_value);
cp_rs1_eq_rs2 : coverpoint (instr.rs1_value == instr.rs2_value) {
bins equal = {1};
}
`CG_END
`B_R_INSTR_CG_BEGIN(maxu)
cp_rs1_gt_rs2 : coverpoint (instr.rs1_value > instr.rs2_value);
cp_rs1_eq_rs2 : coverpoint (instr.rs1_value == instr.rs2_value) {
bins equal = {1};
}
`CG_END
// Sign-extend instructions (sext.b, sext.h)
`B_R_INSTR_NO_RS2_CG_BEGIN(sext_b)
`CG_END
`B_R_INSTR_NO_RS2_CG_BEGIN(sext_h)
`CG_END
// Single-bit instructions (sbset, sbclr, sbinv, sbext)
`B_R_INSTR_CG_BEGIN(sbset)
`CP_VALUE_RANGE(bit_location, instr.rs2_value, 0, XLEN-1)
`CG_END
`B_R_INSTR_CG_BEGIN(sbclr)
`CP_VALUE_RANGE(bit_location, instr.rs2_value, 0, XLEN-1)
`CG_END
`B_R_INSTR_CG_BEGIN(sbinv)
`CP_VALUE_RANGE(bit_location, instr.rs2_value, 0, XLEN-1)
`CG_END
`B_R_INSTR_CG_BEGIN(sbext)
`CP_VALUE_RANGE(bit_location, instr.rs2_value, 0, XLEN-1)
`CG_END
`B_I_INSTR_CG_BEGIN(sbseti)
`CP_VALUE_RANGE(bit_location, instr.imm, 0, XLEN-1)
`CG_END
`B_I_INSTR_CG_BEGIN(sbclri)
`CP_VALUE_RANGE(bit_location, instr.imm, 0, XLEN-1)
`CG_END
`B_I_INSTR_CG_BEGIN(sbinvi)
`CP_VALUE_RANGE(bit_location, instr.imm, 0, XLEN-1)
`CG_END
`B_I_INSTR_CG_BEGIN(sbexti)
`CP_VALUE_RANGE(bit_location, instr.imm, 0, XLEN-1)
`CG_END
// Shift Ones (Left/Right) (slo, sloi, sro, sroi)
`B_R_INSTR_CG_BEGIN(slo)
`CP_VALUE_RANGE(num_ones_shift, instr.rs2_value, 0, XLEN-1)
@ -1012,31 +1133,6 @@ class riscv_instr_cover_group;
`CP_VALUE_RANGE(num_ones_shift, instr.imm, 0, XLEN/2-1)
`CG_END
// Rotate (Left/Right) (rol, ror, rori)
`B_R_INSTR_CG_BEGIN(ror)
`CP_VALUE_RANGE(num_bit_rotate, instr.rs2_value, 0, XLEN-1)
`CG_END
`B_R_INSTR_CG_BEGIN(rol)
`CP_VALUE_RANGE(num_bit_rotate, instr.rs2_value, 0, XLEN-1)
`CG_END
`B_I_INSTR_CG_BEGIN(rori)
`CP_VALUE_RANGE(num_bit_rotate, instr.imm, 0, XLEN-1)
`CG_END
`B_R_INSTR_CG_BEGIN(rorw)
`CP_VALUE_RANGE(num_bit_rotate, instr.rs2_value, 0, XLEN/2-1)
`CG_END
`B_R_INSTR_CG_BEGIN(rolw)
`CP_VALUE_RANGE(num_bit_rotate, instr.rs2_value, 0, XLEN/2-1)
`CG_END
`B_I_INSTR_CG_BEGIN(roriw)
`CP_VALUE_RANGE(num_bit_rotate, instr.imm, 0, XLEN/2-1)
`CG_END
// Generalized Reverse (grev, grevi, rev)
`B_R_INSTR_CG_BEGIN(grev)
`CP_VALUE_RANGE(reverse_mode, instr.rs2_value, 0, XLEN-1)
@ -1135,34 +1231,16 @@ class riscv_instr_cover_group;
`CP_VALUE_RANGE(offset, instr.rs2_value[20:16], 0, XLEN/2-1)
`CG_END
`B_R_INSTR_CG_BEGIN(bext)
`B_R_INSTR_CG_BEGIN(bcompress)
`CG_END
`B_R_INSTR_CG_BEGIN(bextw)
`B_R_INSTR_CG_BEGIN(bcompressw)
`CG_END
`B_R_INSTR_CG_BEGIN(bdep)
`B_R_INSTR_CG_BEGIN(bdecompress)
`CG_END
`B_R_INSTR_CG_BEGIN(bdepw)
`CG_END
`B_R_INSTR_CG_BEGIN(clmul)
`CG_END
`B_R_INSTR_CG_BEGIN(clmulh)
`CG_END
`B_R_INSTR_CG_BEGIN(clmulr)
`CG_END
`B_R_INSTR_CG_BEGIN(clmulw)
`CG_END
`B_R_INSTR_CG_BEGIN(clmulhw)
`CG_END
`B_R_INSTR_CG_BEGIN(clmulrw)
`B_R_INSTR_CG_BEGIN(bdecompressw)
`CG_END
`B_R_INSTR_NO_RS2_CG_BEGIN(crc32_b)
@ -1230,25 +1308,6 @@ class riscv_instr_cover_group;
`CP_VALUE_RANGE(num_shift, instr.imm, 0, XLEN/2-1)
`CG_END
`B_R_INSTR_CG_BEGIN(addwu)
`CG_END
`B_R_INSTR_CG_BEGIN(subwu)
`CG_END
`B_I_INSTR_CG_BEGIN(addiwu)
`CG_END
`B_R_INSTR_CG_BEGIN(addu_w)
`CG_END
`B_R_INSTR_CG_BEGIN(subu_w)
`CG_END
`B_I_INSTR_CG_BEGIN(slliu_w)
`CP_VALUE_RANGE(num_shift, instr.imm, 0, XLEN-1)
`CG_END
// CSR instructions
`CSR_INSTR_CG_BEGIN(csrrw)
cp_rs1 : coverpoint instr.rs1;
@ -1971,103 +2030,120 @@ class riscv_instr_cover_group;
fcvt_d_lu_cg = new();
`CG_SELECTOR_END
`CG_SELECTOR_BEGIN(RV32ZBA)
sh1add_cg = new();
sh2add_cg = new();
sh3add_cg = new();
`CG_SELECTOR_END
`CG_SELECTOR_BEGIN(RV32ZBB)
andn_cg = new();
clz_cg = new();
cpop_cg = new();
ctz_cg = new();
max_cg = new();
maxu_cg = new();
min_cg = new();
minu_cg = new();
orc_b_cg = new();
orn_cg = new();
rev8_cg = new();
rol_cg = new();
ror_cg = new();
rori_cg = new();
sext_b_cg = new();
sext_h_cg = new();
xnor_cg = new();
zext_h_cg = new();
`CG_SELECTOR_END
`CG_SELECTOR_BEGIN(RV32ZBC)
clmul_cg = new();
clmulh_cg = new();
clmulr_cg = new();
`CG_SELECTOR_END
`CG_SELECTOR_BEGIN(RV32ZBS)
bclr_cg = new();
bclri_cg = new();
bext_cg = new();
bexti_cg = new();
binv_cg = new();
binvi_cg = new();
bset_cg = new();
bseti_cg = new();
`CG_SELECTOR_END
`CG_SELECTOR_BEGIN(RV32B)
clz_cg = new();
ctz_cg = new();
pcnt_cg = new();
andn_cg = new();
orn_cg = new();
xnor_cg = new();
pack_cg = new();
packh_cg = new();
min_cg = new();
max_cg = new();
minu_cg = new();
maxu_cg = new();
sext_b_cg = new();
sext_h_cg = new();
sbset_cg = new();
sbclr_cg = new();
sbinv_cg = new();
sbext_cg = new();
sbseti_cg = new();
sbclri_cg = new();
sbinvi_cg = new();
sbexti_cg = new();
slo_cg = new();
sro_cg = new();
sloi_cg = new();
sroi_cg = new();
ror_cg = new();
rol_cg = new();
rori_cg = new();
grev_cg = new();
grevi_cg = new();
shfli_cg = new();
unshfli_cg = new();
shfl_cg = new();
unshfl_cg = new();
gorc_cg = new();
gorci_cg = new();
bfp_cg = new();
bext_cg = new();
bdep_cg = new();
clmul_cg = new();
clmulh_cg = new();
clmulr_cg = new();
crc32_b_cg = new();
crc32_h_cg = new();
crc32_w_cg = new();
crc32c_b_cg = new();
crc32c_h_cg = new();
crc32c_w_cg = new();
cmix_cg = new();
cmov_cg = new();
fsl_cg = new();
fsr_cg = new();
fsri_cg = new();
pack_cg = new();
packh_cg = new();
slo_cg = new();
sro_cg = new();
sloi_cg = new();
sroi_cg = new();
grev_cg = new();
grevi_cg = new();
shfli_cg = new();
unshfli_cg = new();
shfl_cg = new();
unshfl_cg = new();
gorc_cg = new();
gorci_cg = new();
bfp_cg = new();
bcompress_cg = new();
bdecompress_cg = new();
crc32_b_cg = new();
crc32_h_cg = new();
crc32_w_cg = new();
crc32c_b_cg = new();
crc32c_h_cg = new();
crc32c_w_cg = new();
cmix_cg = new();
cmov_cg = new();
fsl_cg = new();
fsr_cg = new();
fsri_cg = new();
`CG_SELECTOR_END
`CG_SELECTOR_BEGIN(RV64ZBA)
add_uw_cg = new();
sh1add_uw_cg = new();
sh2add_uw_cg = new();
sh3add_uw_cg = new();
slli_uw_cg = new();
`CG_SELECTOR_END
`CG_SELECTOR_BEGIN(RV64ZBB)
clzw_cg = new();
cpopw_cg = new();
ctzw_cg = new();
rolw_cg = new();
rorw_cg = new();
roriw_cg = new();
`CG_SELECTOR_END
`CG_SELECTOR_BEGIN(RV64B)
clzw_cg = new();
ctzw_cg = new();
pcntw_cg = new();
packw_cg = new();
packuw_cg = new();
slow_cg = new();
srow_cg = new();
sloiw_cg = new();
sroiw_cg = new();
rorw_cg = new();
rolw_cg = new();
roriw_cg = new();
grevw_cg = new();
greviw_cg = new();
shflw_cg = new();
unshflw_cg = new();
gorcw_cg = new();
gorciw_cg = new();
bfpw_cg = new();
bextw_cg = new();
bdepw_cg = new();
clmulw_cg = new();
clmulhw_cg = new();
clmulrw_cg = new();
crc32_d_cg = new();
crc32c_d_cg = new();
bmator_cg = new();
bmatxor_cg = new();
bmatflip_cg = new();
fslw_cg = new();
fsrw_cg = new();
fsriw_cg = new();
addwu_cg = new();
subwu_cg = new();
addiwu_cg = new();
addu_w_cg = new();
subu_w_cg = new();
slliu_w_cg = new();
packw_cg = new();
packuw_cg = new();
slow_cg = new();
srow_cg = new();
sloiw_cg = new();
sroiw_cg = new();
grevw_cg = new();
greviw_cg = new();
shflw_cg = new();
unshflw_cg = new();
gorcw_cg = new();
gorciw_cg = new();
bfpw_cg = new();
bcompressw_cg = new();
bdecompressw_cg = new();
crc32_d_cg = new();
crc32c_d_cg = new();
bmator_cg = new();
bmatxor_cg = new();
bmatflip_cg = new();
fslw_cg = new();
fsrw_cg = new();
fsriw_cg = new();
`CG_SELECTOR_END
// Ignore the exception which cannot be covered when running with ISS
if (iss_mode) begin
int i;
@ -2284,36 +2360,49 @@ class riscv_instr_cover_group;
FLE_D : `SAMPLE_F(fle_d_cg, instr)
FCLASS_S : `SAMPLE_F(fclass_s_cg, instr)
FCLASS_D : `SAMPLE_F(fclass_d_cg, instr)
// RV32ZBA
SH1ADD : `SAMPLE_ZBA(sh1add_cg, instr)
SH2ADD : `SAMPLE_ZBA(sh2add_cg, instr)
SH3ADD : `SAMPLE_ZBA(sh3add_cg, instr)
// RV32ZBB
ANDN : `SAMPLE_ZBB(andn_cg, instr)
CLZ : `SAMPLE_ZBB(clz_cg, instr)
CPOP : `SAMPLE_ZBB(cpop_cg, instr)
CTZ : `SAMPLE_ZBB(ctz_cg, instr)
MAX : `SAMPLE_ZBB(max_cg, instr)
MAXU : `SAMPLE_ZBB(maxu_cg, instr)
MIN : `SAMPLE_ZBB(min_cg, instr)
MINU : `SAMPLE_ZBB(minu_cg, instr)
ORC_B : `SAMPLE_ZBB(orc_b_cg, instr)
ORN : `SAMPLE_ZBB(orn_cg, instr)
REV8 : `SAMPLE_ZBB(rev8_cg, instr)
ROL : `SAMPLE_ZBB(rol_cg, instr)
ROR : `SAMPLE_ZBB(ror_cg, instr)
RORI : `SAMPLE_ZBB(rori_cg, instr)
SEXT_B : `SAMPLE_ZBB(sext_b_cg, instr)
SEXT_H : `SAMPLE_ZBB(sext_h_cg, instr)
XNOR : `SAMPLE_ZBB(xnor_cg, instr)
ZEXT_H : `SAMPLE_ZBB(zext_h_cg, instr)
// RV32ZBC
CLMUL : `SAMPLE_ZBC(clmul_cg, instr)
CLMULH : `SAMPLE_ZBC(clmulh_cg, instr)
CLMULR : `SAMPLE_ZBC(clmulr_cg, instr)
// RV32ZBS
BCLR : `SAMPLE_ZBS(bclr_cg, instr)
BCLRI : `SAMPLE_ZBS(bclri_cg, instr)
BEXT : `SAMPLE_ZBS(bext_cg, instr)
BEXTI : `SAMPLE_ZBS(bexti_cg, instr)
BINV : `SAMPLE_ZBS(binv_cg, instr)
BINVI : `SAMPLE_ZBS(binvi_cg, instr)
BSET : `SAMPLE_ZBS(bset_cg, instr)
BSETI : `SAMPLE_ZBS(bseti_cg, instr)
// RV32B
CLZ : `SAMPLE_B(clz_cg, instr)
CTZ : `SAMPLE_B(ctz_cg, instr)
PCNT : `SAMPLE_B(pcnt_cg, instr)
ANDN : `SAMPLE_B(andn_cg, instr)
ORN : `SAMPLE_B(orn_cg, instr)
XNOR : `SAMPLE_B(xnor_cg, instr)
PACK : `SAMPLE_B(pack_cg, instr)
PACKH : `SAMPLE_B(packh_cg, instr)
MIN : `SAMPLE_B(min_cg, instr)
MAX : `SAMPLE_B(max_cg, instr)
MINU : `SAMPLE_B(minu_cg, instr)
MAXU : `SAMPLE_B(maxu_cg, instr)
SEXT_B : `SAMPLE_B(sext_b_cg, instr)
SEXT_H : `SAMPLE_B(sext_h_cg, instr)
SBSET : `SAMPLE_B(sbset_cg, instr)
SBCLR : `SAMPLE_B(sbclr_cg, instr)
SBINV : `SAMPLE_B(sbinv_cg, instr)
SBEXT : `SAMPLE_B(sbext_cg, instr)
SBSETI : `SAMPLE_B(sbseti_cg, instr)
SBCLRI : `SAMPLE_B(sbclri_cg, instr)
SBINVI : `SAMPLE_B(sbinvi_cg, instr)
SBEXTI : `SAMPLE_B(sbexti_cg, instr)
SLO : `SAMPLE_B(slo_cg, instr)
SRO : `SAMPLE_B(sro_cg, instr)
SLOI : `SAMPLE_B(sloi_cg, instr)
SROI : `SAMPLE_B(sroi_cg, instr)
ROR : `SAMPLE_B(ror_cg, instr)
ROL : `SAMPLE_B(rol_cg, instr)
RORI : `SAMPLE_B(rori_cg, instr)
GREV : `SAMPLE_B(grev_cg, instr)
GREVI : `SAMPLE_B(grevi_cg, instr)
SHFLI : `SAMPLE_B(shfli_cg, instr)
@ -2323,11 +2412,8 @@ class riscv_instr_cover_group;
GORC : `SAMPLE_B(gorc_cg, instr)
GORCI : `SAMPLE_B(gorci_cg, instr)
BFP : `SAMPLE_B(bfp_cg, instr)
BEXT : `SAMPLE_B(bext_cg, instr)
BDEP : `SAMPLE_B(bdep_cg, instr)
CLMUL : `SAMPLE_B(clmul_cg, instr)
CLMULH : `SAMPLE_B(clmulh_cg, instr)
CLMULR : `SAMPLE_B(clmulr_cg, instr)
BCOMPRESS : `SAMPLE_B(bcompress_cg, instr)
BDECOMPRESS: `SAMPLE_B(bdecompress_cg, instr)
CRC32_B : `SAMPLE_B(crc32_b_cg, instr)
CRC32_H : `SAMPLE_B(crc32_h_cg, instr)
CRC32_W : `SAMPLE_B(crc32_w_cg, instr)
@ -2339,45 +2425,43 @@ class riscv_instr_cover_group;
FSL : `SAMPLE_B(fsl_cg, instr)
FSR : `SAMPLE_B(fsr_cg, instr)
FSRI : `SAMPLE_B(fsri_cg, instr)
// RV64ZBA
ADD_UW : `SAMPLE_ZBA(add_uw_cg, instr)
SH1ADD_UW : `SAMPLE_ZBA(sh1add_uw_cg, instr)
SH2ADD_UW : `SAMPLE_ZBA(sh2add_uw_cg, instr)
SH3ADD_UW : `SAMPLE_ZBA(sh3add_uw_cg, instr)
SLLI_UW : `SAMPLE_ZBA(slli_uw_cg, instr)
// RV64ZBB
CLZW : `SAMPLE_ZBB(clzw_cg, instr)
CPOPW : `SAMPLE_ZBB(cpopw_cg, instr)
CTZW : `SAMPLE_ZBB(ctzw_cg, instr)
ROLW : `SAMPLE_ZBB(rolw_cg, instr)
RORW : `SAMPLE_ZBB(rorw_cg, instr)
RORIW : `SAMPLE_ZBB(roriw_cg, instr)
// RV64B
CLZW : `SAMPLE_B(clzw_cg, instr)
CTZW : `SAMPLE_B(ctzw_cg, instr)
PCNTW : `SAMPLE_B(pcntw_cg, instr)
PACKW : `SAMPLE_B(packw_cg, instr)
PACKUW : `SAMPLE_B(packuw_cg, instr)
SLOW : `SAMPLE_B(slow_cg, instr)
SROW : `SAMPLE_B(srow_cg, instr)
SLOIW : `SAMPLE_B(sloiw_cg, instr)
SROIW : `SAMPLE_B(sroiw_cg, instr)
RORW : `SAMPLE_B(rorw_cg, instr)
ROLW : `SAMPLE_B(rolw_cg, instr)
RORIW : `SAMPLE_B(roriw_cg, instr)
GREVW : `SAMPLE_B(grevw_cg, instr)
GREVIW : `SAMPLE_B(greviw_cg, instr)
SHFLW : `SAMPLE_B(shflw_cg, instr)
UNSHFLW : `SAMPLE_B(unshflw_cg, instr)
GORCW : `SAMPLE_B(gorcw_cg, instr)
GORCIW : `SAMPLE_B(gorciw_cg, instr)
BFPW : `SAMPLE_B(bfpw_cg, instr)
BEXTW : `SAMPLE_B(bextw_cg, instr)
BDEPW : `SAMPLE_B(bdepw_cg, instr)
CLMULW : `SAMPLE_B(clmulw_cg, instr)
CLMULHW : `SAMPLE_B(clmulhw_cg, instr)
CLMULRW : `SAMPLE_B(clmulrw_cg, instr)
CRC32_D : `SAMPLE_B(crc32_d_cg, instr)
CRC32C_D : `SAMPLE_B(crc32c_d_cg, instr)
BMATOR : `SAMPLE_B(bmator_cg, instr)
BMATXOR : `SAMPLE_B(bmatxor_cg, instr)
BMATFLIP : `SAMPLE_B(bmatflip_cg, instr)
FSLW : `SAMPLE_B(fslw_cg, instr)
FSRW : `SAMPLE_B(fsrw_cg, instr)
FSRIW : `SAMPLE_B(fsriw_cg, instr)
ADDWU : `SAMPLE_B(addwu_cg, instr)
SUBWU : `SAMPLE_B(subwu_cg, instr)
ADDIWU : `SAMPLE_B(addiwu_cg, instr)
ADDU_W : `SAMPLE_B(addu_w_cg, instr)
SUBU_W : `SAMPLE_B(subu_w_cg, instr)
SLLIU_W : `SAMPLE_B(slliu_w_cg, instr)
PACKW : `SAMPLE_B(packw_cg, instr)
PACKUW : `SAMPLE_B(packuw_cg, instr)
SLOW : `SAMPLE_B(slow_cg, instr)
SROW : `SAMPLE_B(srow_cg, instr)
SLOIW : `SAMPLE_B(sloiw_cg, instr)
SROIW : `SAMPLE_B(sroiw_cg, instr)
GREVW : `SAMPLE_B(grevw_cg, instr)
GREVIW : `SAMPLE_B(greviw_cg, instr)
SHFLW : `SAMPLE_B(shflw_cg, instr)
UNSHFLW : `SAMPLE_B(unshflw_cg, instr)
GORCW : `SAMPLE_B(gorcw_cg, instr)
GORCIW : `SAMPLE_B(gorciw_cg, instr)
BFPW : `SAMPLE_B(bfpw_cg, instr)
BCOMPRESSW : `SAMPLE_B(bcompressw_cg, instr)
BDECOMPRESSW : `SAMPLE_B(bdecompressw_cg, instr)
CRC32_D : `SAMPLE_B(crc32_d_cg, instr)
CRC32C_D : `SAMPLE_B(crc32c_d_cg, instr)
BMATOR : `SAMPLE_B(bmator_cg, instr)
BMATXOR : `SAMPLE_B(bmatxor_cg, instr)
BMATFLIP : `SAMPLE_B(bmatflip_cg, instr)
FSLW : `SAMPLE_B(fslw_cg, instr)
FSRW : `SAMPLE_B(fsrw_cg, instr)
FSRIW : `SAMPLE_B(fsriw_cg, instr)
`VECTOR_INCLUDE("riscv_instr_cover_group_inc_cg_sample.sv")
default: begin
if (instr.group == RV32I) begin
@ -2459,7 +2543,9 @@ class riscv_instr_cover_group;
instr = riscv_instr::create_instr(instr_name);
if ((instr.group inside {supported_isa}) &&
(instr.group inside {RV32I, RV32M, RV64M, RV64I, RV32C, RV64C,
RVV, RV64B, RV32B})) begin
RVV, RV64B, RV32B,
RV32ZBA, RV32ZBB, RV32ZBC, RV32ZBS,
RV64ZBA, RV64ZBB, RV64ZBC, RV64ZBS})) begin
if (((instr_name inside {URET}) && !support_umode_trap) ||
((instr_name inside {SRET, SFENCE_VMA}) &&
!(SUPERVISOR_MODE inside {supported_privileged_mode})) ||

View file

@ -252,6 +252,12 @@ class riscv_instr_gen_config extends uvm_object;
bit vector_instr_only;
// Bit manipulation extension support
bit enable_b_extension;
bit enable_zba_extension;
bit enable_zbb_extension;
bit enable_zbc_extension;
bit enable_zbs_extension;
b_ext_group_t enable_bitmanip_groups[] = {ZBB, ZBS, ZBP, ZBE, ZBF, ZBC, ZBR, ZBM, ZBT,
ZB_TMP};
@ -516,6 +522,10 @@ class riscv_instr_gen_config extends uvm_object;
`uvm_field_int(vector_instr_only, UVM_DEFAULT)
`uvm_field_int(enable_b_extension, UVM_DEFAULT)
`uvm_field_array_enum(b_ext_group_t, enable_bitmanip_groups, UVM_DEFAULT)
`uvm_field_int(enable_zba_extension, UVM_DEFAULT)
`uvm_field_int(enable_zbb_extension, UVM_DEFAULT)
`uvm_field_int(enable_zbc_extension, UVM_DEFAULT)
`uvm_field_int(enable_zbs_extension, UVM_DEFAULT)
`uvm_field_int(use_push_data_section, UVM_DEFAULT)
`uvm_object_utils_end
@ -575,6 +585,10 @@ class riscv_instr_gen_config extends uvm_object;
get_bool_arg_value("+enable_floating_point=", enable_floating_point);
get_bool_arg_value("+enable_vector_extension=", enable_vector_extension);
get_bool_arg_value("+enable_b_extension=", enable_b_extension);
get_bool_arg_value("+enable_zba_extension=", enable_zba_extension);
get_bool_arg_value("+enable_zbb_extension=", enable_zbb_extension);
get_bool_arg_value("+enable_zbc_extension=", enable_zbc_extension);
get_bool_arg_value("+enable_zbs_extension=", enable_zbs_extension);
cmdline_enum_processor #(b_ext_group_t)::get_array_values("+enable_bitmanip_groups=",
enable_bitmanip_groups);
if(inst.get_arg_value("+boot_mode=", boot_mode_opts)) begin
@ -600,6 +614,27 @@ class riscv_instr_gen_config extends uvm_object;
if (!(RV32C inside {supported_isa})) begin
disable_compressed_instr = 1;
end
if (!((RV32ZBA inside {supported_isa}) ||
(RV64ZBA inside {supported_isa}))) begin
enable_zba_extension = 0;
end
if (!((RV32ZBB inside {supported_isa}) ||
(RV64ZBB inside {supported_isa}))) begin
enable_zbb_extension = 0;
end
if (!((RV32ZBC inside {supported_isa}) ||
(RV64ZBC inside {supported_isa}))) begin
enable_zbc_extension = 0;
end
if (!((RV32ZBS inside {supported_isa}) ||
(RV64ZBS inside {supported_isa}))) begin
enable_zbs_extension = 0;
end
vector_cfg = riscv_vector_cfg::type_id::create("vector_cfg");
pmp_cfg = riscv_pmp_cfg::type_id::create("pmp_cfg");
pmp_cfg.rand_mode(pmp_cfg.pmp_randomize);

View file

@ -99,7 +99,15 @@ package riscv_instr_pkg;
RV128C,
RVV,
RV32B,
RV32ZBA,
RV32ZBB,
RV32ZBC,
RV32ZBS,
RV64B,
RV64ZBA,
RV64ZBB,
RV64ZBC,
RV64ZBS,
RV32X,
RV64X
} riscv_instr_group_t;
@ -154,108 +162,115 @@ package riscv_instr_pkg;
CSRRWI,
CSRRSI,
CSRRCI,
// RV32B instructions
// RV32ZBA instructions
SH1ADD,
SH2ADD,
SH3ADD,
// RV32ZBB instructions
ANDN,
CLZ,
CPOP,
CTZ,
MAX,
MAXU,
MIN,
MINU,
ORC_B,
ORN,
XNOR,
GORC,
SLO,
SRO,
REV8,
ROL,
ROR,
SBCLR,
SBSET,
SBINV,
SBEXT,
GREV,
SLOI,
SROI,
RORI,
SBCLRI,
SBSETI,
SBINVI,
SBEXTI,
SEXT_B,
SEXT_H,
XNOR,
ZEXT_H,
// RV32ZBC instructions
CLMUL,
CLMULH,
CLMULR,
// RV32ZBS instructions
BCLR,
BCLRI,
BEXT,
BEXTI,
BINV,
BINVI,
BSET,
BSETI,
// RV32B instructions
// Remaining bitmanip instructions of draft v.0.93 not ratified in v.1.00 (Zba, Zbb, Zbc, Zbs).
GORC,
GORCI,
GREVI,
CMIX,
CMOV,
PACK,
PACKU,
PACKH,
XPERM_N,
XPERM_B,
XPERM_H,
SLO,
SRO,
SLOI,
SROI,
GREV,
GREVI,
FSL,
FSR,
FSRI,
CLZ,
CTZ,
PCNT,
SEXT_B,
SEXT_H,
CRC32_B,
CRC32_H,
CRC32_W,
CRC32C_B,
CRC32C_H,
CRC32C_W,
CLMUL,
CLMULR,
CLMULH,
MIN,
MAX,
MINU,
MAXU,
SHFL,
UNSHFL,
BDEP,
BEXT,
PACK,
PACKU,
BMATOR,
BMATXOR,
PACKH,
BFP,
SHFLI,
UNSHFLI,
BCOMPRESS,
BDECOMPRESS,
BFP,
// RV64ZBA instructions
ADD_UW,
SH1ADD_UW,
SH2ADD_UW,
SH3ADD_UW,
SLLI_UW,
// RV64ZBB instructions
CLZW,
CPOPW,
CTZW,
ROLW,
RORW,
RORIW,
//RV64B instructions
ADDIWU,
SLLIU_W,
ADDWU,
SUBWU,
// Remaining bitmanip instructions of draft v.0.93 not ratified in v.1.00 (Zba, Zbb, Zbc, Zbs).
BMATOR,
BMATXOR,
BMATFLIP,
CRC32_D,
CRC32C_D,
ADDU_W,
SUBU_W,
SHFLW,
UNSHFLW,
BCOMPRESSW,
BDECOMPRESSW,
BFPW,
SLOW,
SROW,
ROLW,
RORW,
SBCLRW,
SBSETW,
SBINVW,
SBEXTW,
GORCW,
GREVW,
SLOIW,
SROIW,
RORIW,
SBCLRIW,
SBSETIW,
SBINVIW,
GORCIW,
GREVW,
GREVIW,
FSLW,
FSRW,
FSRIW,
CLZW,
CTZW,
PCNTW,
CLMULW,
CLMULRW,
CLMULHW,
SHFLW,
UNSHFLW,
BDEPW,
BEXTW,
GORCW,
GORCIW,
PACKW,
PACKUW,
BFPW,
XPERM_W,
// RV32M instructions
MUL,
MULH,
@ -1151,6 +1166,7 @@ package riscv_instr_pkg;
} vxrm_t;
typedef enum int {
ZBA,
ZBB,
ZBS,
ZBP,
@ -1178,7 +1194,7 @@ package riscv_instr_pkg;
parameter int DATA_WIDTH = 32;
// Parameters for output assembly program formatting
parameter int MAX_INSTR_STR_LEN = 11;
parameter int MAX_INSTR_STR_LEN = 13;
parameter int LABEL_STR_LEN = 18;
// Parameter for program generation
@ -1372,10 +1388,18 @@ package riscv_instr_pkg;
`include "riscv_vector_cfg.sv"
`include "riscv_pmp_cfg.sv"
typedef class riscv_instr;
typedef class riscv_zba_instr;
typedef class riscv_zbb_instr;
typedef class riscv_zbc_instr;
typedef class riscv_zbs_instr;
typedef class riscv_b_instr;
`include "riscv_instr_gen_config.sv"
`include "isa/riscv_instr.sv"
`include "isa/riscv_amo_instr.sv"
`include "isa/riscv_zba_instr.sv"
`include "isa/riscv_zbb_instr.sv"
`include "isa/riscv_zbc_instr.sv"
`include "isa/riscv_zbs_instr.sv"
`include "isa/riscv_b_instr.sv"
`include "isa/riscv_floating_point_instr.sv"
`include "isa/riscv_vector_instr.sv"
@ -1388,9 +1412,15 @@ package riscv_instr_pkg;
`include "isa/rv32f_instr.sv"
`include "isa/rv32i_instr.sv"
`include "isa/rv32b_instr.sv"
`include "isa/rv32zba_instr.sv"
`include "isa/rv32zbb_instr.sv"
`include "isa/rv32zbc_instr.sv"
`include "isa/rv32zbs_instr.sv"
`include "isa/rv32m_instr.sv"
`include "isa/rv64a_instr.sv"
`include "isa/rv64b_instr.sv"
`include "isa/rv64zba_instr.sv"
`include "isa/rv64zbb_instr.sv"
`include "isa/rv64c_instr.sv"
`include "isa/rv64d_instr.sv"
`include "isa/rv64f_instr.sv"

View file

@ -89,7 +89,8 @@ class riscv_privileged_common_seq extends uvm_sequence;
mstatus.set_field("SPP", 0);
// Enable interrupt
mstatus.set_field("MPIE", cfg.enable_interrupt);
mstatus.set_field("MIE", cfg.enable_interrupt);
// MIE is set when returning with mret, avoids trapping before returning
mstatus.set_field("MIE", 0);
mstatus.set_field("SPIE", cfg.enable_interrupt);
mstatus.set_field("SIE", cfg.enable_interrupt);
mstatus.set_field("UPIE", cfg.enable_interrupt);

View file

@ -34,24 +34,24 @@
description: >
Random test with all useful knobs
gen_opts: >
+instr_cnt=10000
+instr_cnt=100000
+num_of_sub_program=5
+illegal_instr_ratio=5
+hint_instr_ratio=5
+stream_name_0=riscv_load_store_rand_instr_stream
+stream_freq_0=4
+stream_freq_0=20
+stream_name_1=riscv_loop_instr
+stream_freq_1=4
+stream_freq_1=20
+stream_name_2=riscv_hazard_instr_stream
+stream_freq_2=4
+stream_freq_2=20
+stream_name_3=riscv_load_store_hazard_instr_stream
+stream_freq_3=4
+stream_freq_3=20
+stream_name_4=riscv_mem_region_stress_test
+stream_freq_4=4
+stream_freq_4=20
+stream_name_5=riscv_jal_instr
+stream_freq_5=4
+stream_freq_5=20
+stream_name_6=riscv_int_numeric_corner_stream
+stream_freq_6=4
+stream_freq_6=20
+dist_control_mode=1
+dist_shift=10
+dist_arithmetic=10