Commit e1a99df3 authored by aneels3's avatar aneels3 Committed by udinator
Browse files

Update pygen_src files


Signed-off-by: default avataraneels3 <b150023ec@nitsikkim.ac.in>
parent 59dcd8c8
......@@ -223,6 +223,6 @@ class riscv_compressed_instr(riscv_instr):
def get_c_opcode(self):
pass
# TOD0
# TODO
def get_func3(self):
pass
......@@ -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()
......
"""
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,19 @@ 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
# 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 +134,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
......
......@@ -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)
......
This diff is collapsed.
......@@ -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,
......
"""
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
......
"""
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)
......
This diff is collapsed.
This diff is collapsed.
"""
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:
......
"""
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
<