Skip to content

Commit

Permalink
Add support for sub_programs
Browse files Browse the repository at this point in the history
Signed-off-by: aneels3 <[email protected]>
  • Loading branch information
aneels3 committed Jan 4, 2022
1 parent 96c1ee6 commit 0638306
Show file tree
Hide file tree
Showing 5 changed files with 259 additions and 58 deletions.
82 changes: 64 additions & 18 deletions pygen/pygen_src/riscv_asm_program_gen.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""
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
Expand All @@ -17,6 +18,7 @@
import vsc
from importlib import import_module
from pygen_src.riscv_instr_sequence import riscv_instr_sequence
from pygen_src.riscv_callstack_gen import riscv_callstack_gen
from pygen_src.riscv_instr_pkg import (pkg_ins, privileged_reg_t,
privileged_mode_t, mtvec_mode_t,
misa_ext_t, riscv_instr_group_t,
Expand Down Expand Up @@ -49,7 +51,7 @@ def __init__(self):
self.hart = 0
self.page_table_list = []
self.main_program = []
self.sub_program = []
self.sub_program = [0] * rcs.NUM_HARTS
self.data_page_gen = None
self.spf_val = vsc.rand_bit_t(32)
self.dpf_val = vsc.rand_bit_t(64)
Expand All @@ -64,9 +66,7 @@ def gen_program(self):
# 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 = []
sub_program_name = []
self.instr_stream.append(f"h{int(hart)}_start:")
if not cfg.bare_program_mode:
self.setup_misa()
Expand All @@ -93,7 +93,8 @@ def gen_program(self):
if hart == 0:
self.gen_test_done()
# Generate sub program
# TODO gen_sub_program()
self.gen_sub_program(hart, self.sub_program[hart],
sub_program_name, cfg.num_of_sub_program)
# Generate main program
gt_lbl_str = pkg_ins.get_label("main", hart)
label_name = gt_lbl_str
Expand All @@ -110,7 +111,8 @@ def gen_program(self):
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.gen_callstack(self.main_program[hart], self.sub_program[hart],
sub_program_name, cfg.num_of_sub_program)
self.main_program[hart].post_process_instr()
logging.info("Post-processing main program...done")
self.main_program[hart].generate_instr_stream()
Expand All @@ -128,7 +130,7 @@ def gen_program(self):
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()
self.insert_sub_program(self.sub_program[hart], self.instr_stream)
logging.info("Main/sub program generation...done")
# program end
self.gen_program_end(hart)
Expand Down Expand Up @@ -202,17 +204,57 @@ def gen_kernel_program(self, hart, seq):
def gen_sub_program(self, hart, sub_program,
sub_program_name, num_sub_program,
is_debug = 0, prefix = "sub"):
# TODO
pass
if num_sub_program > 0:
self.sub_program = [0] * num_sub_program
for i in range(len(self.sub_program)):
gt_label_str = pkg_ins.get_label("{}_{}".format(prefix, i + 1), hart)
label_name = gt_label_str
gt_label_str = riscv_instr_sequence()
self.sub_program[i] = gt_label_str
if(is_debug):
self.sub_program[i].instr_cnt = cfg.debug_sub_program_instr_cnt[i]
else:
self.sub_program[i].instr_cnt = cfg.sub_program_instr_cnt[i]
self.generate_directed_instr_stream(hart=hart,
label=label_name,
original_instr_cnt=
self.sub_program[i].instr_cnt,
min_insert_cnt=0,
instr_stream=self.sub_program[i].directed_instr)
self.sub_program[i].label_name = label_name
self.sub_program[i].gen_instr(is_main_program=0, no_branch=cfg.no_branch_jump)
sub_program_name.append(self.sub_program[i].label_name)

def gen_callstack(self, main_program, sub_program,
sub_program_name, num_sub_program):
# TODO
pass
if num_sub_program != 0:
callstack_gen = riscv_callstack_gen()
self.callstack_gen.init(num_sub_program + 1)
if callstack_gen.randomize():
idx = 0
# Insert the jump instruction based on the call stack
for i in range(len(callstack_gen.program_h)):
for j in range(len(callstack_gen.program_h.sub_program_id)):
idx += 1
pid = callstack_gen.program_id[i].sub_program_id[j] - 1
logging.info("Gen jump instr %0s -> sub[%0d] %0d", i, j, pid + 1)
if(i == 0):
self.main_program[i].insert_jump_instr(sub_program_name[pid], idx)
else:
self.sub_program[i - 1].insert_jump_instr(sub_program_name[pid], idx)
else:
logging.critical("Failed to generate callstack")
sys.exit(1)
logging.info("Randomizing call stack..done")

def insert_sub_program(self, sub_program, instr_list):
# TODO
pass
if cfg.num_of_sub_program != 0:
random.shuffle(self.sub_program)
for i in range(len(self.sub_program)):
self.sub_program[i].post_process_instr()
self.sub_program[i].generate_instr_stream()
instr_list.extend((self.sub_program[i].instr_string_list))

# ----------------------------------------------------------------------------------
# Major sections - init, stack, data, test_done etc.
# ----------------------------------------------------------------------------------
Expand Down Expand Up @@ -455,16 +497,20 @@ def get_randselect(self, addr_range1, addr_range2, flag):
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
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
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
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
with vsc.randomize_with(self.dpf_val):
self.dpf_val[val0:val1] == 0

def get_rand_spf_value(self):
vsc.randselect([
Expand Down Expand Up @@ -493,7 +539,7 @@ def get_rand_dpf_value(self):
# 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)),
(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
Expand Down
149 changes: 149 additions & 0 deletions pygen/pygen_src/riscv_callstack_gen.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
"""
Copyright 2020 Google LLC
Copyright 2020 PerfectVIPs Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""

import logging
import random
import vsc


@vsc.randobj
class riscv_program:
def __init__(self):
self.program_id = vsc.rand_bit_t(16)
self.call_stack_level = vsc.rand_uint32_t()
self.sub_program_id = vsc.rand_list_t(vsc.bit_t(16))

@vsc.constraint
def legel_c(self):
vsc.unique(self.sub_program_id)
with vsc.foreach(self.sub_program_id, idx = True) as i:
self.sub_program_id[i] != self.program_id

def convert2string(self):
string = "PID[{}] Lv[{}] :".format(self.program_id, self.call_stack_level)
for i in range(len(self.sub_program_id)):
string = "{} {}".format(string, self.sub_program_id[i])
return string

# -----------------------------------------------------------------------------------------
# RISC-V assembly program call stack generator
#
# The call stack is generated as a tree structure to avoid dead call loop.
# Level 0: P0
# / | \
# Level 1: P1 P2 P3
# | \/ \
# Level 2: P4 P5 P6
# |
# Level 3: P7
#
# Rules: A program can only call the program in the next level.
# A program can be called many times by other upper level programs.
# A program can call the same lower level programs multiple times.
# -----------------------------------------------------------------------------------------


@vsc.randobj
class riscv_callstack_gen:
def __init__(self):
# Number of programs in the call stack
self.program_cnt = vsc.int_t(10)
# Handles of all programs
self.program_h = []
# Maximum call stack level
self.max_stack_level = vsc.int_t(50)
# Call stack level of each program
self.stack_level = vsc.randsz_list_t(vsc.bit_t(11))

@vsc.constraint
def program_stack_level_c(self):
# The stack level is assigned in ascending order to avoid call loop
self.stack_level.size == self.program_cnt
self.stack_level[0] == 0
with vsc.foreach(self.stack_level, idx=True) as i:
with vsc.if_then(i > 0):
self.stack_level[i] in vsc.rangelist(vsc.rng(1, self.program_cnt - 1))
self.stack_level[i] >= self.stack_level[i - 1]
self.stack_level[i] <= self.stack_level[i - 1] + 1
self.stack_level[i] <= self.max_stack_level

# Init all program instances before randomization
def init(self, program_cnt):
self.program_cnt = program_cnt
self.program_h = [0] * program_cnt
for i in range(len(self.program_h)):
self.program_h[i] = riscv_program("program_{}".format(i))

# In the randomiation stage, only the stack level of each program is specified. The call stack
# generation process is to build the call relationship between different programs. This is
# implemented with post randomize rather than constraints for performance considerations.
# Solving a complex call stack with SV constraint could take considerable time for the solver.

def post_randomize(self):
last_level = 0
last_level = self.stack_level[self.program_cnt - 1]
for i in range(len(self.program_h)):
self.program_h[i].program_id = i
self.program_h[i].call_stack_level = self.stack_level[i]
# Top-down generate the entire call stack.
# A program can only call the programs in the next level.
for i in range(last_level):
program_list = []
next_program_list = []
sub_program_id_pool = vsc.randlist_t()
sub_program_cnt = []
idx = 0
for j in range(self.program_cnt):
if self.stack_level[j] == i:
program_list.append(j)
if self.stack_level[j] == i + 1:
next_program_list.append(j)
# Randmly duplicate some sub programs in the pool to create a case that
# one sub program is called by multiple caller. Also it's possible to call
# the same sub program in one program multiple times.
total_sub_program_cnt = random.randrange(len(next_program_list),
len(next_program_list) + 1)
sub_program_id_pool = [0] * total_sub_program_cnt
for i in range(len(sub_program_id_pool)):
with sub_program_id_pool[i].randomize_with():
with vsc.if_then(sub_program_id_pool[i]):
sub_program_id_pool[i] == next_program_list[i]
with vsc.else_then():
sub_program_id_pool[i].inside(vsc.rangelist(next_program_list))
random.shuffle(sub_program_id_pool)
sub_program_cnt = [0] * len(program_list)
logging.info("{} programs @Lv{}-> {} programs at next level".format(
len(program_list), i, len(sub_program_id_pool)))
# Distribute the programs of the next level among the programs of current level
# Make sure all program has a caller so that no program is obsolete.

for j in range(len(sub_program_id_pool)):
caller_id = random.randrange(0, len(sub_program_cnt) - 1)
sub_program_cnt[caller_id] += 1

for j in range(len(program_list)):
id = program_list[j]
self.program_h[id].sub_program_id = [0] * sub_program_cnt[j]
logging.info("{} sub programs are assigned to program[{}]".format(
sub_program_cnt[j], id))
for k in range(len(self.program_h[id].sub_program_id)):
self.program_h[id].sub_program_id[k] = sub_program_id_pool[idx]
idx += 1

def print_call_stack(self, program_id_t, i, string_str):
if len(self.program_h[i].sub_program_id) == 0:
logging.info("{}", string_str)
else:
for j in range(len(self.program_h[i].sub_program_id)):
self.print_call_stack(self.program_h[i].sub_program_id[j], "{} -> {}".format(
string_str, self.program_h[i].sub_program_id[j]))
Loading

0 comments on commit 0638306

Please sign in to comment.