You are on page 1of 47

Indian Institute of Technology

Guwahati

Computer Science and Engineering

Bachelor of Technology

Equivalence Checking between


C and RTL

Author: Supervisor:

Rakesh Reddy Dr. Chandan Karfa

April 26, 2021


Equivalence Checking between C and
RTL

Thesis Submitted

in Partial Fulfillment of the Requirements

for the Degree of

BACHELOR OF TECHNOLOGY

By

RAKESH REDDY THEEGALA

Under the Supervision of Dr. CHANDAN KARFA

Computer Science and Engineering

Indian Institute of Technology


Guwahati
April, 2021
Declaration

This is to certify that the thesis entitled “Equivalence Checking between C and RTL”,
submitted by me to the Indian Institute of Technology Guwahati, for the award of the degree
of Bachelor of Technology, is a bonafide work carried out by me under the supervision of
Dr. Chandan Karfa. The content of this thesis, in full or in parts, have not been submitted
to any other University or Institute for the award of any degree or diploma. I also wish to
state that to the best of my knowledge and understanding nothing in this report amounts
to plagiarism.

................................
Rakesh Reddy Theegala
Computer Science and Engineering,
Indian Institute of Technology Guwahati,
Guwahati-781039, Assam, India.

April 18, 2020


............................

1
Certificate

This is to certify that the thesis entitled “Equivalence Checking between C and RTL”,
by Rakesh Reddy Theegala (170101071), a undergraduate student in the Computer Science
and Engineering, Indian Institute of Technology Guwahati, for the award of the degree of
Bachelor of Technology, is a record of an original research work carried out by him under my
supervision and guidance. The thesis has fulfilled all requirements as per the regulations
of the institute and in my opinion has reached the standard needed for submission. The
results embodied in this thesis have not been submitted to any other University or Institute
for the award of any degree or diploma.

................................
Dr. Chandan Karfa
Computer Science and Engineering,
Indian Institute of Technology Guwahati,
Guwahati-781039, Assam, India.

Date
18-04-2020

2
Abstract

The current work proposes a formal method for checking equivalence between a given
behavioural specification in C and the Register transfer level (RTL) behaviour produced by
the High-level synthesis (HLS). High level synthesis contains multiple optimization phases.
So input behaviour is modified several ways to finally mapped to RTLs. So there might be
chance of introducing error which differs output behaviour from input behaviour. HLS is
widely used in industry, so it is necessary to have a verification method to check HLS tool’s
correctness. Our work proposes a novel framework to check the correctness of HLS tool i.e.
equivalence between input behaviour and output behaviour generated by HLS tool. A C
code is reverse engineered from the RTL first. This is possible because the RTLs produced
by HLS tool has a separable controller FSM. Both behaviours are represented in C code
in my work. The main component of the work is to check the equivalence between two C
codes. Specifically, two codes are given, and an input file is given where some variables
have defined which are input to both these C codes and an output file where some variables
have defined on which we have check equivalence. Our method identifies the traces in the
C code, identifies the correspondence of traces between two behaviours using a data driven
approach and then formally prove the equivalence using a well known SMT solver. We
then propose a path based equivalence checking to improve the scalability of our method
further. The proposed approaches are tested on the results of Vivado HLS tool.

3
Acknowledgement

In the first place, I would like to take this opportunity to express my sincere gratitude
and regards to my thesis supervisor Dr. Chandan Karfa, Department of Computer Science
and Engineering, IIT Guwahati for his valuable guidance, support and encouragement. His
excellent advice and efforts helped me to learn valuable and useful lessons, which encouraged
me a lot in this project work and also would help me in my future vocation.
Also, I would like to thank my parents and all my friends for their immense support
and co-operation. They taught me great lessons and were the most significant support in
my life. Finally, I would like to thank once again Chandan Sir without whom this project
would have been just a distant reality.

4
Contents

Abstract 3

Acknowledgement 4

List of Figures 7

1 Introduction 1
1.1 Motivation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.2 Problem Statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.3 Contributions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.4 Chapter Organizations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4

2 Literature Survey 5
2.1 Formal Verification of HLS . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2.1.1 Phase-wise Verification of HLS . . . . . . . . . . . . . . . . . . . . . 5
2.1.2 Simulation based Verification of HLS . . . . . . . . . . . . . . . . . 7
2.2 End-to-End Verifcation of HLS . . . . . . . . . . . . . . . . . . . . . . . . 8
2.3 Limitations of Existing Methods . . . . . . . . . . . . . . . . . . . . . . . . 9

3 Basic Equivalence checking algorithm 10


3.1 Basic Algorithm . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
3.2 Algorithm 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12

5
3.3 Equivalent Paths and Outputs . . . . . . . . . . . . . . . . . . . . . . . . . 12
3.4 Results . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
3.5 Drawbacks of Algorithm-1 . . . . . . . . . . . . . . . . . . . . . . . . . . . 17

4 Data-driven Cutpoint based Equivalence Checking 18


4.1 Basic Idea . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
4.2 Invarient Finding . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
4.3 Equivalence checking at cutpoint . . . . . . . . . . . . . . . . . . . . . . . 23
4.4 Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27

5 Results, Observations and Future works 28


5.1 Results . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
5.2 Observations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
5.3 Conclusion and Future works . . . . . . . . . . . . . . . . . . . . . . . . . 34

Bibliography 37

References 37

6
List of Figures

1.1 High-level Synthesis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2

3.1 Overall idea . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10

7
Chapter 1

Introduction

High-level synthesis (HLS) is the process of generating the register-transfer-level (RTL)


design from the behavioural description. It is a very popular technique because one can
generate hardware directly by writing code in a high-level programming language like C,
C++, etc. Also, writing the source code into a higher abstraction language gives an efficient
and easy way for someone to experiment with different micro-architectures which can be
generated by changes in design in the source code or applying various optimizations of the
HLS tool.
Input to HLS is some algorithm or program or section of the program like function. HLS
process is a very complicated task and divided into phases like pre-processing, scheduling
phase, allocation and binding phase, datapath and controller generation phase. Figure 1.1
shows the flow of HLS. A brief discussion about working in each phase is described below.

1. Pre-processing step involves breaking the code into three address format, specifying
the no of the input port to use, deciding the basic blocks for the final version of
code and forming the intermediate representation (CDFG). This step also includes
analysing data dependency, performing live analysis and applying compiler optimisa-
tions.

2. The next step is the scheduling phase is operations are assigned with different time-

1
Fig. 1.1 High-level Synthesis

steps, which decide the way operations must be scheduled. Algorithms like ASAP,
ALAP, list scheduling, etc. are used for scheduling purpose and are categorized based
on resource and timing constraints

3. The allocation and binding phase allocates registers for variables and function units
(FUs) for the operations in each of the control steps. The goal is to optimize re-
sources in a way that register and FU sharing is maximum and without hampering
the functionality of existing operations..

4. In the datapath and controller generation, the datapath is generated by providing


a proper interconnection path from the source registers to the destination registers
via FUs for each register transfer (RT) operation. The main aim of this step is to
maximize the sharing of interconnection among the RT operations and also to ensure
conflict-free data transfers among RT operations. The second task is to generate the
controller finite state machine (FSM) by identifying the control signals required in
each of the states.

2
1.1 Motivation

As described in the above phases, input behaviour is modified in several ways to finally
mapped to RTLs. Moreover, many optimizations are applied in each phase, like minimiza-
tion of time steps to schedule the operations, apply code motions during scheduling, etc.
So there is no one to one correspondence between output and input of HLS. Because of
multiple phases and changes, there might be a chance of error introduced. So we need to
find a verification method for the HLS tools correctness. There are many tools in industry
as well as academia that can be used for high-level synthesis. Some of the examples are
Spark, Legup, Bambu, Vivado HLS, etc. As these tools are widely used, it is very important
to check the correctness of these tools, i.e. the equivalence of output and input, which is a
C code and RTL code. There are some methods to check equivalence between C, and RTL
one of them is simulation. But obviously, we can’t try to simulate every input test cases
and check the direct value output equivalent. Another method is actually verifying using
formal methods [5]. [4] proposes equivalence checking in datapath and controller generation
phase whereas [3] deals with register sharing verification. All the methods mentioned above
deal with different phases of equivalence checking. But there is no end-to-end method for
checking equivalence. So our motivation is to give a complete end-to-end method for the
equivalence checking of c and RTL for verification of the HLS tool.

1.2 Problem Statement

Given a C code and its corresponding RTL generated using an HLS tool, we want to check
whether the two codes are equivalent or not.

1.3 Contributions

The contributions of this works are as follows:

3
• We proposed a basic equivalence checking algorithm in which we find all the traces
in both input and output behaviour. After finding traces, we showed trace level
equivalence using SMT solver, i.e. which shows trace equivalence between traces of
input, output behaviour. To reduce the time complexity, we introduced a data-driven
approach.

• We come up with a new framework to reduce the time complexity, Data-driven cut-
point based equivalence checking. In this framework, we break the behaviour in
between. Specifically, we introduced cutpoints in each behaviour, and we showed
equivalence of paths between cutpoints instead of traces of the complete program.
Since output behaviour is an RTL code of input behaviour, there exists a correla-
tion between variables in input behaviour and register in output behaviour. But we
don’t know the correlations, so we used invariant generator Daikon to identify the
correlation between register and variables, which is a data-driven method. Once we
know relations at each cutpoint, equivalence checking is done by the SMT solver, thus
performing path level equivalence at cutpoints.

• We tested both frameworks on a commercial HLS tool, Vivado HLS from Xilinx. We
collected some standard benchmarks and generated corresponding RTL using Vivado
HLS. We checked the output equivalence between source C code and generated RTL.
Thus our frameworks work for real-world HLS tool.

1.4 Chapter Organizations

The rest of the thesis is organized as follows: Chapter 2 contains literature. Chapter 3
contains Basic algorithm for equivalence checking. Chapter 4 contains new data driven cut
point based equivalency checking with implementation details. Finally chapter 5 contains
results and my future work plans.

4
Chapter 2

Literature Survey

There has been a lot of research in the field of equivalence checking of two programs.
Considering the equivalence of RTL code generated from C like behavioural code, the task
of equivalence checking is a little tricky. There are mainly two approaches to equivalence
checking: a phase-wise equivalence checking, i.e. testing equivalence after different phases
of HLS and the other being an end-to-end equivalence checking.

2.1 Formal Verification of HLS

In phase-wise equivalence checking, the main idea is to show the equivalence for the input
and output FSMDs for each of the HLS phases like scheduling, allocation and binding, dat-
apath and control path generation phase, etc. On the contrary, the end to end equivalence
is done using SMT based approach, data-driven and simulation-based approaches, which
may or may not require any information from the tool.

2.1.1 Phase-wise Verification of HLS

Several works of literature have focused on the equivalence checking of various phases of
HLS. The work mentioned in the verification of datapath and controller generation
phase HLS [4] have proposed a method to generate the FSMD using the controller and

5
datapath interaction. Another FSMD produced after the allocation and binding phase
is also considered. The equivalence between both the FSM is then verified to check the
correctness of the controller. The main focus of this literature is the generation of FSMD
using the datapath interaction and controller. To check the flow of data, the control
assertion pattern generated by the controller needs to be feed in the circuit, which executes a
set of micro-operations to complete the corresponding register transfer operation. The task
deduces to identifying micro-operations for a given assertion pattern. This is achieved using
a rewriting algorithm that takes an RT operation as input and generates corresponding
micro-operations as the output. Using the combination of micro-operation generated as
a part of the datapath and the controller, the FSM can be realized. Finally, a state-
based equivalence algorithm is used to verify the correctness of the generated controller
with respect to the FSM of the previous phase using a state by state equivalence checking
algorithm. Another work proposed in [3] verifies the register sharing using a formal method.
Their main aim is to show the equivalence of allocation and binding phase. The two
behaviours before and after the datapath synthesis are modelled as FSMDs. A mapping
is formulated between the variables and the registers before and after the allocation and
binding phase, respectively. The equivalence is shown for the mapping by comparing the
computations for their FSMDs. Finally, the verification is done by using path covers and
cut-point based equivalence checking. For that, the state-wise equivalence of all the paths
forming the path covers is proved.
The cutpoints based methods, as explained in [8] is also somewhat similar to one men-
tioned in in [5], which focuses on equivalence checking of scheduling phase of HLS
. In this work, the behaviour that is given input to the scheduler is represented as FSMD
M0, and the behaviour that is recorded as the output of the scheduler is represented as
FSMD M1. The path traces of M0 is checked for equivalence with M1, and the same is
repeated by exchanging both the FSMD. A recent work related to scheduling phase verifica-
tion is proposed in [1]. This work extends the path based equivalence checking (PBEC) to

6
overcome the limitation of split and merge type of constructs for which other PBEC based
equivalence methods fails. It uses value propagation (VP) based verification of scheduling
which can handle code motion and control structure based modification over loops. It
outperforms the existing state of the art approaches.

2.1.2 Simulation based Verification of HLS

An approach for an end to end equivalence checking is simulation-based verification. A


work [2] does simulation-based equivalence checking between SystemC models at different
abstraction levels. The literature focuses on equivalence checking of ESL design flows using
simulation between two SystemC models using a client-server framework developed by
them. Their framework first analyzes the variables which will be used for comparisons, and
after that, the input models are converted using their library into a client with a networking
facility. Finally, the server which contains the equivalence checker checks the models using
simulation by using the fed data and checking whether the models show the same behaviour.
They have reduced the time which is spent in setting up the verification environment and
which is generally set up the time needed for hardware and software co-simulation. A
recent work [7] translates the RTL to behavioural (C) description with an aim to develop
explorable constructs. The method is based on making graph-based transformations using
the rule-based classification method and applying a graph pattern matching algorithm.
The generated C code is made up of array and loop structures to which different design
space explorations(DSE) can be performed. Similar work is presented in [6], which focuses
on accelerating the simulations using behavioural templates. The input to their algorithm,
which produces the accelerated templates, are the accelerators in C/SystemC or RTL code.
In case it is RTL code, the method mentioned in [7] is used first to convert it into a C code.
After that, the data-dependency code is identified, and that part is not accelerated because
their latency is not constant and depends on DD constructs(break, continue, return, exit).
Finally, for the remaining code, which is not data-dependent, a synthesizable C code is

7
generated for the behavioural template. The behavioural templates generated, unlike our
proposed method, does not represent the original RTL completely. Similarly is the case
with [2] or the works mentioned in [7]. Verilator simulation tool [9] generates a generic
C++ executable from Verilog RTL but does not produce a synthesizable C program that
can be directly used for High-level synthesis.

2.2 End-to-End Verifcation of HLS

Considering end to end equivalence checking, a work Data-Driven Equivalence check-


ing [8] focuses on equivalence checking of two loops using the data-driven approach. They
have developed a sound algorithm and implemented the same in a tool called DDEC (Data-
Driven Equivalence Checker). The concept of cut points is used to perform the equivalence
checking. First of all, the cut points are identified, and then the flow of both the program
is checked using data from different test runs. The sense of equivalence is achieved using
observations that the execution jumps from one cut point to another in a similar fashion in
both the code fragments and the invariant conditions at these cut points hold. Verification
conditions corresponding to code paths and proof obligations concerning missing paths are
also added. Using existing theorem provers, they form queries to check the invariants and
verification conditions are satisfying or not. Finally, the equivalence is constituted by us-
ing these queries as inductive proof of equivalence. Another work mentioned in [2] SMT
based equivalence checking extends the data-driven approach to form a template called
sketch and fills it with the help of solvers to generate invariants from counterexample. This
method is called invariant sketching. There is some work that follows the static approaches
to equivalence checking by constructing the equivalence relation through static analysis; for
example, one uses the guess-and-test strategy, which mostly suffers from scalability issues
for complex invariants.

8
2.3 Limitations of Existing Methods

The phase-wise equivalence checking performs good, but with the condition that we require
some information from the tool and some intermediate results to show the equivalence, and
which is not always available. For an end to end equivalence checking, the limitations are
different and depend on the approach. For example, for data-driven equivalence, checking
a lot of data covering all the path flows of the program is required. Some work for an end to
end verification of HLS is error-prone and unable to identify the exact sub-task where the
error occurs. Some of them require exponential time in some cases to check equivalence.
The simulation-based approaches have targeted accelerating the simulation using various
methods. However, their only aim is to accelerate the design, but the design flow of RTL is
not preserved for obtaining the results. Some other simulation-based methods are targeting
different results like design space exploration, optimizations, etc., and their primary focus
is not actually speeding up the simulation process. All these works do not provide support
for RTL generated from Xilinx Vivado, and some have constraints like support for single-
module RTL designs with no components or interfaces.

9
Chapter 3

Basic Equivalence checking algorithm

3.1 Basic Algorithm

The basic idea is to check whether the c and RTL code is equivalent. That is, they give
the same output in every possible input. To do this, we first convert the RTL to a C code
using the method given in [KSM10]. This part is already implemented, and we assume that
RTL to c conversion is correct without any error. we got a c code that is equivalent to the
RTL code, so the problem statement reduces to check whether two c codes are equivalent
or not. (refer to Figure 3.1)

Fig. 3.1 Overall idea

10
We want to get the correspondence formula of two c codes in smt-lib format, and we
use z3 to check whether both are equivalent or not. z3 is an SMT solver developed by
Microsoft. When we get two c codes in Bool formula, let’s say formula1 and formula2, we
pass the following forumla and check if it has a solution.

f ormula1! = f ormula2 (3.1)

If yes, then we can say that two c codes are not equivalent and z3 also give a solution
to the formula, so we also have proof, i.e. test case whether the output of two c codes is
different. If the equation has no solution, then we can say that two c codes are equivalent.
BUT equation (1) is SAT which is undecidable problem. Even though Z3 has some good
heuristics, in the worst case, z3 takes exponential time, which is costly and not affordable.
So we have to keep formula size as less as possible. So instead of passing the whole code
in a formula, we have to give a formula corresponding to each trace. This will work faster
than direct comparison as a whole.

We can further break down the formula to make it smaller and hence increase the chances
of Z3 finishing the equivalence checking in time. That idea is also discussed in the next
chapters.

To break down the formula we are using KLEE. KLEE is a dynamic symbolic execution
engine built on top of the LLVM compiler infrastructure. Klee gives the traces for given c
file as input. Specifically,We provide klee with a input c file and a set of input variables
for the c file and a set of output variable for the c file then klee gives traces and for each
trace, for each output variable klee print its value in terms of input variables if we follow
the trace. We will use this traces expression for equivalence checking in trace level.

For implementing the given idea, we also need to do some changes in Klee’s source code.
The changes are in the function managing klee print expression call from Klee. We just

11
change the function to print the path constraint and the output expression both in smtlib
format instead of printing only the output expression in kquery format. While printing, we
also try to print the expressions and path constraints in a way which would make crawling
easier. This is because we finally want to automate the processor and we will need to
differentiate between path constraints and output expressions.

3.2 Algorithm 1

We mentioned in last section that the idea is to compare the C codes trace-wise instead
of comparing them as a whole. But for that we actually need to know which trace in first
code maps to which trace in the second code

One naive way to do that is to check all paths in the input C with all traces in the
second program. But that takes more time. So we propose algorithm-1 for efficient way to
identifying correspondence of traces. But first, we need to do some pre-processing in traces
corresponding to one C code itself. We actually try to merge traces which have the same
outputs. So we have less no of equally potential no of traces for one trace in the source
program.

3.3 Equivalent Paths and Outputs

Let’s assume C1, C2 be the set of conditions in source code and generated code respec-
tively after merging. Let Out1, Out2 be set of outputs in source code and generated code
respectively. Now we assume that there can be more than one output variables in a code
and hence N represents number of output variables

12
For most of the cases, for one path in source program there exist exactly one equivalent
path in generated program. But due to composite output functions we might not able to
merge some paths. Then there is possible set of paths in source combined to equivalent to
a set of paths in generated paths For example set of paths in source program be

C1n = {C11 , ..., C1n } where C1k ∈ C1, k = 1..n

and set of paths in generated program be

C2m = {C21 , ..., C2m } where C2k ∈ C2, k = 1..m

C1n equivalent to C2m if

(C11 or C12 or ... or C1n ) == (C21 or C22 or .... or C2m ) and

C1i ! = C2j ∀ 0 < i <= n, ∀ 0 < j <= m

Because of this potential many to many equivalent paths.We divide equivalence checking
into two parts.In first part, we check the paths that has exactly one potential path and
equivalence check between their outputs .In Second part, We need to do equivalence check
between remaining paths

For the first part, we find potential one to one equivalent paths using tracing. KLEE
gives trace input for each path. Consider path C1x and let Trace test case following this
path is T. We run generated code 2 with T and find path C2y satisfying T. if C1x exactly
equivalent to C2y then we use OutMatch function to check Whether outputs are same for
corresponding path C1x ,C2y . If outputs are not equivalent, we can stop algo and return
saying that both programs are not equivalent. This computation takes care all potential
one to one equivalent paths

13
For second part, we are left with set paths in each programs.For a path C1x in source
program it is enough and sufficient to consider paths in C2y if

C1x ∩ C2y ! = ∅

For paths that have intersection not null, we check whether outputs are equal or not.
For each path in source paths if outputs are equal with outputs of intersected paths in
generated paths, we can conclude both programs are equivalent

14
Algorithm 1: C to RTL EqCheck (C, RTL-C)
Input: Input-C, RTL-C
Result: Equivalent, May not equivalent
T0 = findTrace(C); T1 = findTrace(RTL-C);
T0 = mergeTrace (T0 ); T1 = mergeTrace (T1 );
copyT0 = T0 ; copyT1 = T1 ; flag = 0;
while T0 6= φ do
τ0 = select a trace from T0 ;
TC = getTestcase(τ0 );
τ1 = getCorrespondingTrace(T1 , TC);
// let C1x = condition for trace τ0
// let C2y = condition for trace τ1
if (CondM atch(C1x , C2y )) then
if (OutM atch(C1x , C2y , Out1x , Out2y )) then
//τ0 and τ1 are equivalent
removeTrace (τ0 , copyT0 );
removeTrace (τ1 , copyT1 );
end
else
//τ0 and τ1 may not equivalent
Report “May not equivalent” and Exit;
end
end
else
flag = 1;
end
endif
removeTrace (τ0 , T0 );
end
endwhile
if (flag = 1) then
foreach τ0 ∈ copyT0 do
foreach τ1 ∈ copyT1 do
// let C1x = condition for trace τ0
// let C2y = condition for trace τ1
if isIntersectiontrue(C1x , C2y ) then
if (!(OutM atch(C1x , C2y , Out1x , Out2y ))) then
Report “May not equivalent” and Exit;
end
end
Report Equivalent;

15
3.4 Results

Implementation Detail: The end-to-end equivalent checking framework of HLS is imple-


mented in Python and is tested on a set of HLS benchmarks.We used Vivado HLS tool to
generate Verilog RTL for the benchmarks written in C.We used klee to get all paths and
output expression in smtlib format.klee also gives traces for paths. The benchmarks used
in our implementations areparker,findMin ofeight numbers, matrix addition, sum of an ar-
ray, motion, waka,auto regressive lattice filter(arf) and floating point addition dfadd.The
experiment results of our benchmarks are shown in Table 3.1.For each benchmark, the
2nd (#in) and 3rd (#out) show the number of inputs and outputs for each benchmark,
respectively. We have recorded the number of code lines (#line) and variables (#var) of
the input C in 4th and 5th columns, respectively. The 6th and 7th columns represents the
number of lines (#line) and registers (#regs) in Verilog RTL code generated by Vivado
HLS, respectively. The 8th and 9th columns show the number of lines (#line) and the num-
ber of variables (#var) in generated RTL-C code, respectively. The number of lines in the
RTL-C code is high as compared to the RTL since each register is copied in a temporary
variable at the start of each state to maintain the concurrent execution of operations of
hardware in C. The 10th , 11th and 12th columns are the number of traces of the original
C code (#C), the generated C code (#GenC) and merged traces (#merged), respectively.
Equivalence checking results in terms of the total time spent by our equivalent checking
framework are given in the 13th . As shown, our tool successfully established the equiv-
alence. We then created some non-equivalent scenarios from the RTL-C by by swapping
if-else condition, changing operation type or adding/deleting some operation. We then run
our tool to check the equivalence. In all cases, these errors are correctly identified by our
proposed method as shown at the 15th (time) and 16th (result) columns. Our framework
can prove the equivalence of all eight benchmarks successfully within two seconds except
for findMin8 and Dfadd. For findMin8, merging of compatible traces is taking almost 15
seconds. For Dfadd, the number of traces after merging are not equivalent. As a result,

16
equivalence checking takes more time.

Table 3.1 Experimental Results for different high-level synthesis bench-


marks
#in #out C code RTL code GenC Traces Equivalent Not Equivalent
Bench
#line #var #line #regs #line #var #C #RTLC #merged time (s) result time (s) result
(1) (2) (3) (4) (5) (6) (7) (8) (9) (10) (11) (12) (13) (14) (15) (16)
Waka 20 3 33 32 270 12 382 126 3 4 (3, 3) 1.709 Eq 0.669s MNE
arf 11 4 53 43 351 19 607 158 4 4 (3, 3) 1.890 Eq 0.949 MNE
parker 6 1 62 14 196 10 275 100 12 23 (2, 2) 1.614 Eq 0.976 MNE
findMin8 8 1 40 15 175 11 780 243 128 128 (8, 8) 22.246 Eq 17.141 MNE
matrixAdd 2 1 48 7 734 44 2595 241 1 1 (1, 1) 1.684 Eq 0.749 MNE
sumArray 1 1 19 4 263 15 541 100 1 1 (1, 1) 0.754 Eq 0.706 MNE
Motion 10 3 52 43 413 29 881 235 1 1 (1, 1) 0.681 Eq 0.663 MNE
Dfadd 2 1 719 70 1975 113 9353 1041 67 68 (21,42) 1016.052 Eq 960.238 MNE

3.5 Drawbacks of Algorithm-1

• If the formulas are too big, Z3 might not stop and hence we may not get any output.

• As we are using Klee, we cannot deal with loops having the variable length as these
loops can’t be unfolded.

So, to deal with these two problems, we propose the new algorithm, which we call a data-
driven cutpoint based algorithm.

17
Chapter 4

Data-driven Cutpoint based


Equivalence Checking

4.1 Basic Idea

As mentioned in the previous chapter, breaking down the code into traces is not enough.
Source C code and generated C code are similar in Functionality. They do the same
execution on input variables.This infers that there will be an indirect equivalence between
the variables in both programs, i.e., if the value of one expression is stored in one variable
then most probably that expression will be calculated and stored in some register while
doing HLS synthesis, i.e. in corresponding RTL C code, there will be a variable in which the
expression is evaluated and stored in it. So if we are able to find the equivalence between
the variables of two programs, then simply checking the relation between output variables
of two program will be enough. But directly finding the relation between variables of two
programs at the end of variables is not possible. So we break the code into chunks, i.e.
we introduce some breakpoints in both programs which we call as cutpoints. We say that
cut point c1x in program 1 is equivalent to c2x in program 2 if the program1 before c1x is
computed by program2 before c2x. For example, if there is a loop in program1 then in the

18
generated program also there will be a corresponding loop. So the point of starting a loop
in both programs are equivalent i.e. they are dong similar execution on input variables till
that point. So most probably variables calculated in program1 before cut point c1x will
be calculated by some variables in program2. We will find this relation between these live
variables and use this to find the relation at next pair of equivalence cut point, and we will
do this till we reach the last cut points (end of the program is considered as one cut point
which is last cut point). Cut-points are chosen such that there is more no of an equivalence
relation. Our goal is to show equivalency of the last pair of cut point (end of programs
are considered as one cut point). To find the relation which we call invariant, we use a
data-driven model described in [8]. Basically, to find the relation at the cut point pair, we
will simulate the program before cut points and find the values of variables and based on
the value of variables, we will find the relation. But because of this less number of test case
we might get false invariant, i.e. there is a test case where this invariant is failing but we
are not inserted that in the test case for simulation. So we have to prove the invariant and
find the true invariant and discard the false invariant. To do this, we use Klee and z3 in
the same way algorithm 1 used but in this algorithm instead making input variables equal
as input condition, here we make true invariant before cut point as input condition and
program between the cut point as a new program and instead of checking output variable
equal we check invariant obtained through data-driven model and find the true invariants.

Since I am only using the program between the cut point, the size of the path formulas
will be less, which is taking care of the first drawback of Algorithm I. Also, in [8] data-
driven model is given to check the equivalency of loops. We use the same model to solve
the second drawback of the algorithm 1.

To write in mathematical way, let us say we insert n cut point pairs


<c11, c21>,<c12, c22>,...,<c1n, c2n> in both programs and line numbers in both pro-
grams corresponding to cutpoint pair <c1x, c2x> be <l1x, l2x>. We find the relation

19
between live variables at l1x in program1 to live variables at l2x, this relation is called at
invariant. Our final goal is to find the invariant at <c1n, c2n>(program endpoints). We
will do that inductively.

Let us define adjacent cut points before going to the inductive method. <c1x, c1y> will
be adjacent cut points pair if there is a path from c1x to c1y without reaching another
cut point in between. We will calculate for adjacent cutpoint of each cutpoint using by
simulation of source and generated program. c1y is called the child of c1x, or adjacent
cutpoint of c1y and c1x is called as parent cutpoint of c1y

Inductive method: We will calculate invariant at each adjacent cutpoint of the initial
cutpoint starting from the initial cut point using the code corresponding to the path for
adjacent point, Klee and smt we find all true invariants (the invariant that mathematically)
removing false invariants. This preprocessing for the initial cutpoint make at least one other
cutpoint whose parents preprocessing is completed. Once we are done with this preprocess
for the initial cutpoint, we will do it for cutpoints whose parents preprocessing is finished.
We will do this till this preprocessing is finished for each cutpoint and finally check whether
the invariant at the last cut point has output variables equal invariant or not.

To deal with the loops, cut point are chosen in such a way that it will decompose
the program into loop-free segments using three cutpoints, i.e., cutpoint 1 before for loop
condition cut point2 just after loop condition and cut point3 at the end of the loop. Detailed
explanation is given in [8].

For my current work, I am assuming cut point are given and their corresponding, adjacent
cutpoints in the script.txt file in order of induction method and code corresponding for paths
between adjacents cutpoints. Inductively, I have to find and prove the invariant at each
cut point till the last cut point

20
Algorithm 2: Induction method
while each adjacent pair <c1x,c1y>,<c2x,c2y> in script.txt do
// run klee on code for path from c1x->c1y, c2x->c2y assuming Ix
is true
CC,VAR EXPR = run klee(ix,c1x,c1y,c2x,c2y);
// algorithm 3
Invarient check at y(CC,VAR EXPR,Iy);
end
for each Out1x,Out2x in Output variables do
if Out1x == Out2x ∈ / In then
Report “May not equivalent” and Exit;
end
end
Report equivalent;

4.2 Invarient Finding

I mentioned that to prove equivalency at a cut point, and we need invariants at that cut
point. I used the Daikon invariant detector for this purpose. Daikon reports likely program
invariants. Daikon basically gives a relation between the variables in one program, but
we need the relation between the variables of two programs. To implement this thing, I
combined both codes in one file invarient combine code.c in the following way:-
Combine program to find invariant between two programs1, 2

1 int var1 ; \\for each var in program1


2 .......
3 .......
4 int var2 ; \\for each var in program2
5 .......
6 .......
7 void fun1(){
8 int var = var1 \\for each var in program1
9 ........

21
10 line; \\ for each line in l11 to l1x
11 ........
12 ........
13 var1 = var \\ for each var in program1
14 ......
15 }
16

17 void fun2(){
18 int var = var2 \\for each var in program1
19 ........
20 ........
21 line \\ for each line in l21 to l2x
22 ........
23 ........
24 var2 = var \\ for each var in program1
25 ........
26 ........
27 }
28 void combine(){
29 fun1();
30 fun2();
31 \\ INVARIANT POINT
32 }
33 int main(){
34 for i = 0 t0 no_test_cases:
35 for var in input_variables:
36 scanf("%d",var1);
37 var2 = var1
38 }

While combining both codes, I need to make a difference between variables in code1 and
code2 so for each variable in program1 concatenated “1” at the end and similarly “2” in pro-

22
gram2. Daikon gives invariant at each function start and endpoints i.e. at fun1:::ENTER ,
fun1:::EXIT, fun2:::ENTER , fun2:::EXIT ,combine:::ENTER combine:::EXIT , main:::ENTER
, main:::EXIT.

We are interested in comine:::EXIT point where both programs executed, and this com-
bine function will be executed no test cases times. So daikon sees the values of variables
exist at combine:::EXIT, i.e. var1 and var2 no test cases times. Since we are pasting code
from l11 to l1x and l21 to l2x, invariants obtained will be Ix. Based on these values Daikon
given the relation between variables which is invariant. But Daikon gave invariants based
on the test cases ran, i.e. these invariants will be true only for the given test cases, there
might be a test case where the invariant will fail. So the next step is to find out the true
invariants and discard falsified invariant that occur due to lack of sufficient test cases.

4.3 Equivalence checking at cutpoint

Above section explains how to find Invariant Ix at cutpoint cx . This section explains how
to use the Ix to find the equivalency at cx. Since we are proving using induction algorithm,
we also know previous invariants at c1x’s ancestors, which are always true. We use Klee
and z3 to find the invariant which are true for every possible test case and discard some
falsified invariant. Following combine code is used for the implementation:-
Combine program to get output expression for each variables of programs 1, 2

2 int var1 ; \\for each var in program1


3 .......
4 .......
5

6 int var2 ; \\for each var in program2


7 .......
8 .......

23
9

10 void fun1(){
11 int var = var1 \\for each var in program1
12 ........
13

14 code; \\ code for path from parent of c1x to c1x


15 ........
16 ........
17

18 var1 = var \\ for each var in program1


19 ......
20 }
21

22 void fun2(){
23 int var = var2 \\for each var in program1
24 ........
25 ........
26

27 code \\ code for path from parent of c2x to c2x


28 ........
29 ........
30

31 var2 = var \\ for each var in program1


32 ........
33 ........
34 }
35

36 void combine(){
37 fun1();
38 fun2();
39 \\ INVARIANT POINT
40 }

24
41 int main(){
42 klee_make_symbolic(&var1,sizeof(var1), var1 ); // for each var in program1
43 ...........
44 ...........
45

46 klee_make_symbolic(&var2,sizeof(var2), var2 ); // for each var in program2


47 ...........
48 ...........
49

50 for each relation in Ix-1:


51 klee_assume(relation)
52

53 combine();
54 klee_print_expr( var21 := ,var1) //for each var in program1
55 ............
56 ............
57

58 klee_print_expr( var22 := ,var2) //for each var in program2


59 .............
60 .............
61 }
62 // each var in the program means only live variables exits till that points because
considering all variables are not useful since they don’t involve in invariants

Proving equivalence between cut point is enough to show equivalency for the whole
program using the induction method. Klee will give the expression for each variables in
terms of input variables for each path. For each invariant and path using the expression we
will pass that formula to z3 which gives a test case if the invariant is false. is true function
implementation is explained in algorithm 1.

25
Algorithm 3: Invariant Finding Algorithm
invariant flag = True;
failed inv = ””;
fail invs = [];
idx = 0;
while invariant flag is false do
Ix = run daikon.sh x; // run daikon for new invariant for new
testcase set
invariant flag = true;
// failed inv still present in Ix,do the extra computation
if failed inv ∈ Ix then
fail invs.append(failed inv);
idx = idx+1;
end
bf idx = idx;
for each i in Ix[ bf idx+1: ] do
flag = true;
for each c in CC do
cur flag,test case = is true(i,c,VAR EXPR);
if cur flag is False then
invariant flag = false;
insert testcase(test case);
break;
end
end
if invariant flag is false then
break;
end
idx = idx + 1;
end
end
// Extra computation to solve invariants in fail inv.txt
correct inv = [];
for each i in fail invs do
inv flag = algorithm1(i,l1x,l2x);
if inv flag then
correct inv.append(i);
end
end
Ix.extend(correct inv);

26
Let’s assume that Ix is a set of invariant at cut point x and var21, var22 and CC be set of
paths in the file. For each I,c, we will pass these through is true function with VAR EXPR,
which is output expression of variables that are involved in invariant i, this is true with
the help of Z3 gives cur flag and test case. cur flag will be false if the invariant i is false
for a test case if c path is followed and that test case on which i fails will be returned
in test case else test case will be null. When invariant flag becomes false, we break the
loop and run the daikon again to find new invariants generated by the new test case. But
we found a loophole because of insufficient invariants at parent cutpoint, i.e. c path may
not have enough precondition. Hence, smt might say that given invariants is not always
true and gives a test case on which is false, but actually, it may be true invariant and
running Daikon on that test case still produce i. So to solve this issue, we push all this
type of invariants in the fail invs list and leaving i, we continue the execution of remaining
invariants. After the above process, fail invs have some invariants that need to be proved
or discarded. To do this, we use algorithm 1 but only considering part of the program
instead of considering the whole program, i.e. program till the cutpoint. Algorithm 1 may
take time, but it produces correct results. Through this, we discard falsified invariants and
only leave Ix with invariants proven mathematically.

4.4 Conclusion

In this chapter, we went through why we shifted to the cut point algorithm, how it is
solving the drawback of Algorithm 1 using induction method in Algorithm 2, how to find
invariants at a cutpoint. After finding the invariants, we explained Algorithm 3 to prove
the correctness of invariants using SMT solver.

27
Chapter 5

Results, Observations and Future


works

5.1 Results

In this semester, I continued working on Algorithm 2. I describe a basic example to show


how my algorithm is working.

28
Listing 5.1 program 1
Listing 5.2 program 2
1
38 int main(){
2 int main(){
39 int in1, in2, in3, in4, in7, in8,
3
in9, in10, in14, in12, in15,
4 int in1, in2, in3, in4, in7, in8,
in17, in19, in20, in22, in24,
in9, in10, in14, in12, in15,
in27, in28, in29, in32, out13,
in17, in19, in20, in22, in24,
out30, out31;
in27, in28, in29, in32, out13,
40 //cut 0
out30, out31;
41 int t5, t6, t11, t16, t18, t21,
5 //cut 0
t23, t25, t26;
6 int t5, t6, t11, t16, t18, t21,
42 int return_port;
t23, t25, t26;
43 out30 = 0;
7 int return_port;
44 t5 = in3 - in4;
8 out30 = 0;
45 t6 = in7 + in8;
9 t5 = in3 - in4;
46 out13 = in14 - in15;
10 t6 = in7 + in8;
47 //cut 1
11 out13 = in14 - in15;
48 if (in2 == in1)
12 t11 = t6 + in12;
49 {
13 //cut 1
50 t11 = t6 + in12;
14
51 t16 = t11 - in17;
15 if (in2 == in1)
52 }
16 t16 = t11 - in17;
53 else
17 else
54 {
18 {
55 t18 = in19 + in20;
19 t18 = in19 + in20;
56 if (in9 < in10)
20 if (in9 < in10)
57 {
21 {
58 t11 = t6 + in12;
22 t21 = t11 + in22;
59 t21 = t11 + in22;
23 t23 = t5 - in24;
60 t23 = t5 - in24;
24 t25 = t21 + t23;
61 t25 = t21 + t23;
25 t26 = t25 + in27;
62 t26 = t25 + in27;
26 }
63 }
27 else
64 else
28 t26 = t5 + t18;
65 t26 = t5 + t18;
29 t16 = t26 - in28;
66 t16 = t26 - in28;
30 out30 = t26 + in29;
67 out30 = t26 + in29;
31 }
68 }
32 out31 = t16 + in32;
69 out31 = t16 + in32;
33 return_port = out13 + out30 + out31;
70 return_port = out13 + out30 + out31;
34 //cut 2
71 //cut 2
35
72 return out13 + out30 + out31;
36 return out13 + out30 + out31;
73 }
37 }

Input to program1 are variables on line no 4 and for program 2 at line no 38. Output
port to program1 is return port and for program 2 is return port; To each variables name
in the first program i concatenated 21 and 22 to variable in second programs just to make
difference between variables in program1 and program2. Our goal is show return port21 =

29
return port22.
If you see the difference between the programs is t11 in first code is calculated at line no
12 in program 1 but in program 2 t11 is calculated whenever it is needed i.e at line no 50
and 58.code is shifted later in program 2, since these type of code motions happens HLS
this example gives the analogy how data driven and cut point is working.
Invariant at cut0 is input variables are same

1 in121 == in122
2 in221 == in222
3 in321 == in322
4 in421 == in422
5 in721 == in722
6 in821 == in822
7 in921 == in922
8 in1021 == in1022
9 in1221 == in1222
10 in1421 == in1422
11 in1521 == in1522
12 in1721 == in1722
13 in1921 == in1922
14 in2021 == in2022
15 in2221 == in2222
16 in2421 == in2422
17 in2721 == in2722
18 in2821 == in2822
19 in2921 == in2922
20 in3221 == in3222

Invariant at cut1 :-
iteration 1:

1 in121 == in122
2 in221 == in222

30
3 in321 == in322
4 in421 == in422
5 in721 == in722
6 in821 == in822
7 in921 == in922
8 in1021 == in1022
9 in1421 == in1422
10 in1221 == in1222
11 in1521 == in1522
12 in1721 == in1722
13 in1921 == in1922
14 in2021 == in2022
15 in2221 == in2222
16 in2421 == in2422
17 in2721 == in2722
18 in2821 == in2822
19 in2921 == in2922
20 in3221 == in3222
21 out1321 == out1322
22 t521 == t522
23 t621 == t622
24 in321 - in421 - t521 == 0
25 in721 + in821 - t621 == 0
26 in1421 - in1521 - out1321 == 0
27 in1221 + t621 - t1121 == 0

since all invariant produced by daikon is true,algorithm 1 stopped in one iteration i.e algo
1 entered the while loop only once.

Invariant at cut2:-
iteration 1

31
1 in121 == in122
2 in221 == in222
3 in321 == in322
4 in421 == in422
5 in721 == in722
6 in821 == in822
7 in921 == in922
8 in1021 == in1022
9 in1421 == in1422
10 in1221 == in1222
11 in1521 == in1522
12 in1721 == in1722
13 in1921 == in1922
14 in2021 == in2022
15 in2221 == in2222
16 in2421 == in2422
17 in2721 == in2722
18 in2821 == in2822
19 in2921 == in2922
20 in3221 == in3222
21 out1321 == out1322
22 out3021 == out3022
23 out3121 == out3122
24 t521 == t522
25 t621 == t622
26 t1621 == t1622
27 t1821 == t1822
28 t2121 == t2122
29 t2321 == t2322
30 t2521 == t2522
31 t2621 == t2622
32 return_port21 == return_port22

32
33 in321 - in421 - t521 == 0
34 in721 + in821 - t621 == 0
35 in1421 - in1521 - out1321 == 0
36 in1221 + t621 - t1121 == 0
37 in3221 - out3121 + t1621 == 0
38 t2121 + t2321 - t2521 == 0

At cut2 also invariants produced by daikon is true in first iteration. If you observe the
invariant, one of them is return port21 == return port22. and we proved these invariants
actually true for all possible test cases. So programs are equivalent.
Results on some Test benchmarks

Table 5.1 Experimental Results for some benchmarks


#in #out C code RTL code GenC cut points Equivalent
Bench
#line #var #line #regs #line #var #C #RTLC #invar time result
(1) (2) (3) (4) (5) (6) (7) (8) (9) (10) (11) (12) (13) (14)
Waka 20 3 33 32 270 12 382 126 2 2 (20,125) 1m50.7s Eq
arf 11 4 53 43 351 19 607 158 2 2 (16,214) 1m38.26s Eq
test eq 2 1 79 15 1975 115 712 151 4 4 (2,100,134,129) 20m38s Eq

The experiment results of our benchmarks are shown in Table 5.1. For each benchmark,
the 2nd (#in) and 3rd (#out) show the number of inputs and outputs for each benchmark,
respectively. We have recorded the number of code lines (#line) and variables (#var) of
the input C in 4th and 5th columns, respectively. The 6th and 7th columns represent the
number of lines (#line) and registers (#regs) in Verilog RTL code generated by Vivado
HLS, respectively. The 8th and 9th columns show the number of lines (#line) and the
number of variables (#var) in generated RTL-C code, respectively.The 10th , 11th are no of
cuts points in input C and generated RTL-C code. The 12th contains the no of invariants
at each cutpoint which is mathematically proven removing the falsified invariants.13th is
the total time spent by our equivalent checking framework to solve all invariants at each
cut point, thus proving the equivalence

33
5.2 Observations

• We found that if Daikon didn’t produce enough invariants, then we have to do the
extra computation in Algorithm 2 which is similar to Algorithm 1 i.e. time spent for
proving will be more.

• If we look into the huge no of invariants generated at each cutpoint, so many of them
are not useful. But we are proving them mathematically, which is costly in terms of
time.

• From the testbench, we have observed that if Daikon produce enough invariants, then
our algorithm doesn’t need to do the extra computation, thus saving a lot of time.

• In generated RTL-C code, each variable is mapped to one real-time register, and only
those registers are used later in RTL-C code. So invariants that map the variable in
RTL-c to variable in C code will be enough and sufficient for Algorithm 2.

5.3 Conclusion and Future works

From the observations, we need fewer and sufficient invariants to be generated at each
cutpoint so that our algorithm works efficiently. So instead of directly comparing C code
and generated RTL-C code, we compare generated C code with scheduled C code generated
from source C code. [1] proposed the method to generate equivalent Scheduled C code to
C code. Generated C code has the same structure as the scheduled C code, i.e. states will
be the same. Other research under Prof, Karfa shows the mapping between registers in
generated C code to the variables in Scheduled C code can be recovered 100% for most
of the test cases. Hence, working on Scheduled C code and generated would give better
results in terms of time. So my future work is to show the equivalence between scheduled
C code and RTL.

34
Algorithm 4: Algorithm-1
Input: Input-C, RTL-C
Result: Equivalent, May not equivalent
T0 = findTrace(C); T1 = findTrace(RTL-C);
T0 = mergeTrace (T0 ); T1 = mergeTrace (T1 );
copyT0 = T0 ; copyT1 = T1 ; flag = 0;
//First part
while T0 6= φ do
τ0 = select a trace from T0 ;
TC = getTestcase(τ0 );
τ1 = getCorrespondingTrace(T1 , TC);
if ((cτ0 ≡ cτ1 ) ∧ (sτ0 ≡ sτ1 )) then
//τ0 and τ1 are equivalent
removeTrace (τ0 , copyT0 );
removeTrace (τ1 , copyT1 );
end
else if ((cτ0 ≡ cτ1 ) ∧ (sτ0 6= sτ1 )) then
//τ0 and τ1 may not equivalent
Report “May not equivalent” and Exit;
else
flag=1;
end
endif
removeTrace (τ0 , T0 );
end
endwhile
//second part
if (flag = 1) then
foreach τ0 ∈ copyT0 do
foreach τ1 ∈ copyT1 do
if (cτ0 ∧ cτ1 6= φ) then
if (cτ0 ∧ cτ1 ∧ sτ0 6= sτ1 ) then
Report “May not equivalent” and Exit;
end
end
Report Equivalent;

35
Publication out of this work:
M. Abderrahman, R. Reddy, J. Patidar, C. Karfa, “C to RTL Translation Validation of
High-level Synthesis”, in 29th IFIP/IEEE International Conference on Very Large Scale
Integration. (under review)
Tools we used:

• KLEE Documentation

• Daikon Invariant Detector Documentation

36
References

[1] R. Chouksey and C. Karfa. Verification of scheduling of conditional behaviors in high-


level synthesis. IEEE Transactions on Very Large Scale Integration (VLSI) Systems,
pages 1–14, 2020.

[2] Shubhani Gupta, Aseem Saxena, Anmol Mahajan, and Sorav Bansal. Effective use of
smt solvers for program equivalence checking through invariant-sketching and query-
decomposition. In Olaf Beyersdorff and Christoph M. Wintersteiger, editors, Theory
and Applications of Satisfiability Testing – SAT 2018, pages 365–382, Cham, 2018.
Springer International Publishing.

[3] Chandan Karfa, Chittaranjan A. Mandal, Dipankar Sarkar, and Chris Reade. Register
sharing verification during data-path synthesis. In Computing: Theory and Applica-
tions, 2007. ICCTA ’07. International Conference on,, pages 135–140. IEEE, 2007.

[4] Chandan Karfa, Dipankar Sarkar, and Chitta Mandal. Verification of datapath and
controller generation phase in high-level synthesis of digital circuits. IEEE Trans. on
CAD of Integrated Circuits and Systems, 29(3):479–492, 2010.

[5] Chandan Karfa, Dipankar Sarkar, Chitta Mandal, and P. Kumar. An equivalence-
checking method for scheduling verification in high-level synthesis. IEEE Transactions
on Computer-Aided Design of Integrated Circuits and Systems, 27(3):556–569, 2008.

37
[6] Anushree Mahapatra, Yidi Liu, and Benjamin [Carrion Schafer]. Accelerating cycle-
accurate system-level simulations through behavioral templates. Integration, 62:282 –
291, 2018.

[7] Anushree Mahapatra and Benjamin Carrión Schäfer. Veriintel2c: Abstracting rtl to c
to maximize high-level synthesis design space exploration. Integr., 64:1–12, 2019.

[8] Rahul Sharma, Eric Schkufza, Berkeley Churchill, and Alex Aiken. Data-driven equiv-
alence checking. SIGPLAN Not., 48(10):391–406, October 2013.

[9] D. Galbi Verilator W. Snyder, P. Wasson. Verilator


tool(http://www.veripool.org/wiki/verilator), 2017.

38

You might also like