Design and Verification of A Round-Robin Arbiter
Design and Verification of A Round-Robin Arbiter
8-2018
Recommended Citation
Toe, Aung, "Design and Verification of a Round-Robin Arbiter" (2018). Thesis. Rochester Institute of Technology. Accessed from
This Master's Project is brought to you for free and open access by the Thesis/Dissertation Collections at RIT Scholar Works. It has been accepted for
inclusion in Theses by an authorized administrator of RIT Scholar Works. For more information, please contact [email protected].
Design and verification of a Round-Robin Arbiter
by
Aung Toe
Graduate Paper
Approved by:
As the number of bus masters increases in chip, the performance of a system largely depends
on the arbitration scheme. The throughput of the system is affected by the arbiter circuit
which controls the grant for various requestors. An arbitration scheme is usually chosen
based on the application. A memory arbiter decides which CPU will get access for each
cycle. A packet switch uses an arbiter to decide which input packet will be scheduled to
the output. This paper introduces a Round-robin arbitration with adjustable weight of
resource access time. The Round-robin arbiter mechanism is useful when no starvation
of grants is allowed. The arbiter quantizes time shares each requestor is allowed to have.
A minimal fairness is guaranteed by granting requestors in Round-robin manner. The
requestors can prioritize their time shares by the weight. For example, if requestor A has
a weight of two and requestor B has a weight of four, arbiter will allocate requestor B with
time slice two times longer than that of requestor A’s. The verification of the design is
carried out using SystemVerilog. The inputs of the arbiter are randomized, outputs are
predicted in a software model and verification coverage is collected. The work in this paper
includes design and verification of a weighted Round-robin arbiter.
Declaration
I hereby declare that except where specific reference is made to the work of others, the
contents of this paper are original and have not been submitted in whole or in part for
consideration for any other degree or qualification in this, or any other University. This
paper is the result of my own work and includes nothing which is the outcome of work
done in collaboration, except where specifically indicated in the text.
Aung Toe
August 2018
Acknowledgements
Abstract ii
Declaration iii
Acknowledgements iv
Contents v
List of Tables ix
1 Introduction 1
1.1 Organization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
2 Background Research 4
2.1 Fixed Priority Arbitration . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2.2 Lottery Arbiter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2.3 Matrix Arbiter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
4.6 Checker . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
4.7 Scoreboard . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
4.8 Determinism . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
6 Conclusions 28
6.1 Future Work . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
References 30
Introduction
Scheduling algorithms are required when multiple requestors require access to a shared
resource. In a System on Chip (SoC), multiple devices in the chip are needed to work
together. As a result, an SoC may have multiple bus masters. A fast and powerful arbiter
becomes important to service all the bus masters. Another example of arbitration system
application is network switches. In a network switch, packets from multiple input ports
need to go through a single output port[4, 5]. As the number of parallel processes increases,
accessing a shared resource becomes the bottleneck in performance[6]. One of the goals
of a scheduler is to maximize throughput. The throughput of a system can be maximized
by minimizing wait time for each request. The advantages of utilizing arbiters include
access fairness for the requestors to the resources, utilization without wasting cycles, re-
usability, arbitration speed, power and resource overhead[7, 8]. Different types of Round-
robin arbiters such as baseline arbiters, time speculative arbiters, acyclic arbiters, parallel
prefix arbiters, priority based arbiters, etc... are used in various applications[9].
In the case of multiple bus masters, all masters require access to a shared resource
at the same or similar level of priority. A Round-robin arbitration mechanism fits the
1.1 Organization 2
1.1 Organization
Background Research
Arbiters play an important role when multiple requests are sent to access a single resource.
In a network switching router, the packets received on input ports are sent out to the
respective output ports. The arbiter acts a middle man to direct which input gets to send
its packet to the designated output. The arbitration speed of the arbiter has a large factor
in determining the speed of switching performance. Of the many metrics to benchmark
an arbiter, fairness is a good unit to measure the performance, and there are a few types
typically utilized:
• Weak Fairness
• Weighted Fairness
Weak Fairness means a request may have to wait indefinitely until it gets served. There
may be higher priority requestors holding on to the grant. Section 2.1 discusses a Fixed
Priority Arbiter that demonstrates the weak fairness metric. The Lottery Arbiter discussed
in Section 2.2 updates the weight of the lottery ticket as it arbitrates. The weight of the
2.1 Fixed Priority Arbitration 5
ticket increases the chances of winning the grant. This algorithm has the property of
Weighted Fairness. The Matrix Arbiter in Section 2.3 has the property of LSLP. The last
served requestor will have the lowest priority in the arbiter.
Fixed priority arbiter is the simplest form of arbiter. It is also known as per-emptive arbiter
due to the nature of its scheduling algorithm. Each master is given a priority from high to
low. As shown in Eqn 2.1, master i − 1 has higher priority than master i[7, 9]. For master
i to get the grant, all the masters higher priority than master i must not be requesting to
the arbiter.
For example, if there are 3 masters, master 0 is given priority 0, master 1 priority 1 and
master 2 priority 2. Grant is given to the master that has the highest priority. If master
0 and master 1 request at the same time, master 0 will get the grant since it has higher
priority. As a result, a higher priority master can starve other masters by monopolizing
the bus. However, due to the simplicity of the design, fixed priority arbiters are very useful
in applications where high priority tasks need immediate servicing and low priority tasks
can wait indefinitely to get grant.
lottery manger gives a numbered ticket/request to each master. The weight of the ticket
number is increased each time a specific master requests.
wi
pi = Pn (2.2)
j=1 wj
The manager draws the highest numbered ticket as a winner. The ticket count of the
granted master is reset on winning the lottery. The reset makes the current winner less
likely to be chosen on the next draw. In case of a tie, the manager may choose any master.
If there is only one master requesting, the manger will choose the trivial solution. As a
result of this pseudo-randomization, the masters get a fair share of bus time dictated by
the weight of the lottery ticket.
2.3 Matrix Arbiter 7
Matrix arbiters are designed to enforce last served master to have the lowest priority on
the shared resources. It keeps track of the priority in a square matrix form. The rows and
columns of the matrix represents the requestors. The ith row can be linked to requestor i
and j th column requestor j. Figure 2.2 shows the 4 requestors mapping in a 4 by 4 matrix.
The rule of the matrix arbiter is if there is a 1 in ith row and j th column, requestor i
has priority over requestor j. As in Figure 2.3, if requestor 2 sends a request, the grant
will be issued to requestor 2. The elements in row 2 are set to zero. It forces requestor 2
to have the lowest priority. At the same time the elements in column 2 are set to 1. It
makes other requestors beat requestor 2 in the next iteration. Matrix arbiters are useful
when the number of inputs are small. If the number of requests increases, the structure of
the arbiter increases leading to larger area overhead[11].
2.3 Matrix Arbiter 8
Round-robin arbitration has multiple flavors to fit the desired application. In some applica-
tions two-pick Round-robin arbiters are used instead of one pick arbiters[12]. However, the
final goal, starvation prevention and statistical fairness, is the same[13]. The algorithms
introduced in Chapter 2 give the grant to the master that has the higher priority. It means
a master has the ability to monopolize the bus for a long time. This causes bus starvation
to the masters with lower priorities. Weighted Round-robin arbiter design is based on the
algorithm that the scheduling of grants must go on in a Round-robin manner. This work
is based on a two-step approach. The arbiter monitors the requests and give them grants
in the next clock. In best case condition, the request at time ti will get serviced at time
ti+1 [14]. This scheduling algorithm makes sure each master gets its share of time slice in
a fair amount of time. A good analogy would be if there are 4 masters in x cycle arbiter,
each master will get a quantized time slice of x/4 cycles. However, in some applications,
one bus master may require more bus time than others. Figure 3.1 shows top level view of
Round-robin arbiter in a network packet switching system.
3.1 Weight Decoder 10
This paper introduces another configurable variable called weight. The weight of each
master can be defined as the grant time slice that the master can configure in the arbiter.
If all the masters have the same amount of weight, each master will get an equal time
share of the pie. If master A requests 20 cycles and master B requests 10 cycles, master
A will get grant 2 times longer than master B. One disadvantage of letting the masters to
configure the weight is a master may configure a very large weight. To reduce this large
weight monopoly, another global configurable maximum allowed weight is added. A master
may request a very large weight value, but the arbiter will only grant up to the maximum
allowed weight if there are other masters waiting.
Weight decoder decodes one-hot grant to decode the correct weight of the granted master.
As shown in Figure 3.2, the weight of the masters are concatenated to form a weight bus.
As in Eqn 3.1, the width of the bus can be calculated by the width of a single weight and
the total number of masters in the arbiter.
3.1 Weight Decoder 11
Weight decoder takes current grant as an one-hot input. The input grant is decoded
to produce an index for correct bit slice positions of the weight bus. Figure 3.3 shows
the flowchart to produce the correct index. For example, if the grant is b′ 0010, the index
output is 1. Index of 1 stands for the master no. 1. The weight of master 1 is decoded as
an output. If the grant is b′ 0100, index output is 2. The weight of master 2 is decoded as
an output.
3.2 Next Grant Precalculator 12
Next Grant PReCalculator(NGPRC) calculates the next possible grants mask based on
current grant. By precalculating the next possible grants, NGPRC dictates the Round-
robin arbitration of the arbiter. As in Figure 3.4, if all 4 masters in the arbiter are
3.2 Next Grant Precalculator 13
requesting and current grant is master 1, next possible grant is restricted to be in the order
of master 2, master 3 and master 0. The arbiter cannot skip master 2 to grant master 3.
It would violate Round-robin scheme and it is not allowed. By giving next possible grant
priority to the Grant State-machine, it forces the grant to be in strict Round-robin order.
Figure 3.5 shows the calculation steps NGPRC takes to compute the next possible grant
priority. For example, if current grant is b′ 0010, rotate left gives b′ 0100. After inversion,
the bits become b′ 1011. After increment by 1, the next possible grant becomes b′ 1100. It
means the leftmost 2 bits are in line in priority.
3.3 Grant State Machine 14
Grant state machine is the logic to calculate which master gets the grant and for how long
based on the weight. The grant logic is based on the requests and next grant priority
mask created by NGPRC. Figure 3.6 shows the state flow diagram of grant state machine.
“Grant Process” state masks requests using precalculated mask to grant the next requesting
master. After the grant is decided, it moves to “Get Weight” state to fetch the weight of
the grant from Weight Decoder. After that, it moves to “Count” state to count the clock
cycles until local counter reaches the desired weight.
3.3 Grant State Machine 15
As the sizes and complexity of electronic design increases, faster integration of design and
verification of complex systems become mandatory[15]. The beginning of a new feature
starts with architectural exploration and ends with functional verification. The studies
find that the verification of a design occupies the most amount of time in a project life-
cycle[16]. The time required to verify a design from the end of a design life-cycle can
be defined as a verification gap. As engineers reuse Intellectual Property (IP) cores, de-
sign engineers can produce complex features in short time. However, these new features
are still needed to be verified. As a result, the verification gap increases as the product
cycle rotates between debugging and verification. To reduce the gap, design engineers
and verification engineers have to come to an agreement of having a universal verification
process[17]. SystemVerilog language is introduced as a common language to design verifi-
cation environment as a Universal Verification Methodology (UVM). A unified verification
methodology is important because about 70% of the design cycle time is used to develop
verification environment[18]. The re-usability of the verification environment shortens the
verification gap. A general verification includes multiple layers that can be re-used with
17
• Test Layer : Different test cases with constraint random and/or direct stimulus.
• Functional Layer : This layer predicts possible Device Under Test (DUT) outputs
(golden test vectors) based on the random inputs using a reference mode[20]. It may
also contain a scoreboard to keep track of the results.
• Command Layer : Command layer is a pin-level layer. On the input side, it receives
stimulus from functional layer and drives the DUT. DUT output is also monitored
to be compared with golden test vectors.
4.1 Requestor
Requestor class is designed to behave like a master that would request access to the shared
resource from the arbiter. Requestor class contains two members, request and weight. The
members are of the type “rand”. It allows the calling class to be able to randomize to
provide random stimuli to the DUT. Having random test cases is important because the
verification engineers might not be able to consider many combinations of test cases for
complex systems. However, randomization can produce test cases not applicable to DUT.
Adding constraints to the random variable makes the random stimuli applicable to the
target DUT verification. Verification engineers spend most of the time on iterating runs
by adding constraints and various random seeds. To achieve full coverage, some direct test
4.2 Generator 19
cases may be required to fully close the loop. Figure 4.2 shows the functional coverage
loop.
4.2 Generator
Generator is a part of Scenario Layer. The purpose of the generator is to create different
test stimuli based on scenarios. For example, the verification of a TV remote have many test
scenarios. One of the test scenarios could be pressing mute button. A different test scenario
could be changing channels or adjust volumes. In case of Round-robin arbiter, random
requests/non-request could be simulated with different weights. The requestor class is
instantiated in generator. The generator class generates different requests by randomizing
the requestor class. Generator module can be used to generate different random stimuli
according to the different test case scenarios.
4.3 Agent 20
4.3 Agent
Agent is located in functional level. As in Figure 4.1, agent acts as a mediator between
Scenario Layer and Command Layer. At functional level, agent class is responsible to
receive stimuli and predict output of DUT according to that stimuli. To achieve that,
agent class usually has a functional model of Device Under Test. The input stimuli and
predicted output test vectors can be called “golden” test vectors. Engineers can analyze
the input test vector set to predict the expected output results.
In this verification environment, the agent class instantiates the generator class. The
stimuli generated by the generator are used to convert to golden test vectors by predicting
the expected outcome of the given stimuli. Each randomization contains a bit representing
request or no-request accompanied by the weight. The model checks for the bit and if the
bit is request bit, the weight value is recoded as the number of clock cycles the bit should
be granted. If the bit is no-request the the output is recorded as no request with zero
cycles. The test vectors are passed onto the driver module and expected golden vectors to
checker module.
4.4 Driver
The driver located in Command Layer is closest to hardware. Driver class connects the
input of DUT to the rest of the verification environment. It is responsible to drive signals
synchronously to DUT. It can contains functions such as reset conditions. The test vectors
from agent are driven to DUT by the driver in synchronous with system clock. In this
verification environment, request bits and weights are driven to DUT using DUT system
clock. Because driver controls the input of DUT, Monitor class described in the following
section needs to know when the driver finished driving a particular test vector. The
4.5 Monitor 21
synchronization between class modules is done using event triggering. After driver finished
sending a set of test vector to DUT, it raises an event for monitor class to catch. Monitor
class uses this event to know the respective DUT output. By having synchronization,
driver can insure that all the input test vectors are aligned correctly with the expected
golden test vectors.
4.5 Monitor
Similar to driver class, monitor class resides in Command Layer. Monitor class is connected
to the output of DUT to capture data from DUT output ports synchronously. The purpose
of monitor is to record DUT output for each input driven by driver. The recorded data
can be transferred to checker module to check for errors.
In this verification environment, monitor module starts counting once it sees a grant
signal of a request. The number of cycles or the amount of time a request is granted can be
determined by the counter value of the monitor. For example, if a requestor 1 is granted
for 5 clock cycles, monitor will get a count of 5 for requestor 1. In other words, monitor
collects the grants and their respective granted cycles. The collected data is sent to the
check to be matched with the golden test vectors.
4.6 Checker
Like Agent class, Checker class is located in Functional Layer. Checker class is responsible
to match the output of DUT collected by monitor and the golden test vectors predicted by
reference model. In this verification environment, checker class receives grants and grant
time (cycles) from monitor module. It also receives the expected output of golden test
4.7 Scoreboard 22
vectors. For each test data set, checker verifies DUT output against golden test vectors.
It also records the verification statistics in scoreboard.
4.7 Scoreboard
As the name stands, Scoreboard module contains the statistics of current verification.
Checker module calls the “record” member function of scoreboard after each test vector.
The function records which requestor (master) is granted by updating member variables.
Using the recorded data, statistical analysis can be performed.
4.8 Determinism
If a bug were found during the verification process, it is important for the design and
verification engineers to be able to reproduce easily. Knowing the sets of test vectors
caused the failure is crucial for debugging purposes. Therefore, when the requestor module
is instantiated in Generator module, the seed of the requestor’s random variables can be
set. Each “randomize” function call is based on a different seed. If a failure occurs, the
seed of the failure test vectors can be extracted for the design engineers to debug. It
allows verification engineers to reproduce the failing inputs easily without restarting the
whole verification process. This approach of seeding makes the randomization process to
be deterministic every iteration in every run.
Chapter 5
This section discusses the simulation results of the arbiter, as well as the area and power
overhead of the top level design.
5.1 Simulation
Figure 5.1 shows the simulation of weight decoder. Input dataInBus contains the weights
of the channels preconfigured. Input selOneHot port/grant the input used to decode the
weight of current grant. The decoded weight is outputted to the dataOut port.
5.2 SystemVerilog Verification Results 24
Figure 5.2 shows the simulation waveform of Next Grant PreCalculator. Based on the input
request and grant, next grant mask is created to dictate Round-robin order to restrict the
grant order.
The Figure 5.3 shows the simulation top level Round-Robin Arbiter. Grant is serviced
based on the requests and precalculated mask from NGPRC. The grant is given the access
time for the number of weight cycles before servicing the next request.
Table 5.1 shows the results of SystemVerilog verification of 20,000 iterations. As seen in
the table, the hit score distribution is fairly uniform since the randomization of test vector
generation is based on uniform probability distribution.
5.3 System Overhead 25
Score
Channel 0 1021
Channel 1 972
Channel 2 1036
Channel 3 980
Channel 4 1048
Channel 5 995
Channel 6 1009
Channel 7 971
The arbiter is synthesized using a TSMC 65 nm technology library and Synopsis Design
Compiler using a two step process. The first step, RTL synthesis, performs logic synthesis
and produces what is called a pre-scan netlist. In the second step, test synthesis, Design
For Test (DFT) structures for full scan testing are added to the design and optimized
producing what is called a post-scan netlist. The top level design is targeted at 8 channels
to be able to arbitrate 8 different requestors. Table 5.2 shows the pre-scan and post-scan
area overhead for Weight Decoder, Next Grant PreCalculator and Grant Statemachine.
Similarly, Table 5.3 shows power overhead for Weight Decoder, Next Grant PreCalculator
and Grant state machine.
5.3 System Overhead 26
Module Pre-Scan
Combinational Non- Percent Total (µm2)
(µm2) Combinational Total (%)
(µm2)
Weight Decoder 612.0576 0.0000 13.4 612.0576
(MUX)
Next Grant 755.0928 691.8912 31.8 1446.9840
PreCalculator
(NGPRC)
Grant 1167.5664 1327.2336 54.8 2494.8000
Statemachine
(Grant)
Top Level Arbiter 2534.7168 2019.1248 100 4553.8416
Module (8
Channels)
Post-Scan
Weight Decoder 612.0576 0.0000 12.4 612.0576
(MUX)
Next Grant 755.0928 828.2736 32.0 1583.3664
PreCalculator
(NGPRC)
Grant 1167.5664 1580.0401 55.6 2747.6065
Statemachine
(Grant)
Top Level Arbiter 2534.7168 2408.3137 100.0 4943.0305
Module (8
Channels)
5.3 System Overhead
Netlist
Group Internal Switching Leakage Total Percentage
Type
Register 9.9823e-02 mW 4.3251e-03 mW 9.9996 nW 0.1042 mW 76.50 %
Pre-Scan
3.1997e-02
Netlist Combinational 1.1323e-02 mW 2.0664e-02 mW 9.8877 nW 23.50 %
mW
Total 0.1111 mW 2.4989e-02 mW 19.8873 nW 0.1362 mW 100 %
Register 0.1240 mW 9.2250e-03 mW 11.8287 nW 0.1332 mW 74.45 %
Post-Scan
4.5710e-02
Netlist Combinational 1.7618e-02 mW 2.8082e-02 mW 9.8877 nW 25.55 %
mW
Total 0.1416 mW 3.7307e-02 mW 21.7164 nW 0.1789 mW 100 %
27
Chapter 6
Conclusions
This work discussed the design and verification of Round-Robin Arbitration. As the num-
ber of masters requires access the shared resources increases, a good arbitration system
becomes essential. This work focused on the fairness metric to measure the performance
of an arbiter. However, it is important to not overlook the area overhead and power con-
sumption. A complex system may have good fairness at the trade-off of large overhead.
Therefore, the design preference is based on the application of the arbiter. Round-robin ar-
biter is chosen because of its fairness in granting access. Bus grant time quantization allows
the requestors to be able to predict the maximum amount of time to get grant. However,
in some applications, one requestor might require to have the grant twice as long. This
work introduced the weight or the number of clock cycle that the requestor can configure
during synthesis. This makes the fairness adjustable (more fair or less fair). At the same
time, increasing or decreasing the weights allows the time quantization adjustable.
SystemVerilog is used as a verification environment for the design. By having a verifi-
cation environment, engineers can have a higher confidence on the release of the product.
Code maintenance is easier for each time the design changes due to bugs or feature intro-
6.1 Future Work 29
duction as the verification can filter out issues before reaching to the customers. This work
discussed that design process from the aspect of customer requirements and applications.
To summarize, although fairness is used as a performance measurement, fairness is
only good when a particular application requires it. This Round-Robin Arbiter design
is customized to be more fair or less fair. The design trade-off between fairness and/or
overhead remains at the process of the intended design application.
Since the arbiter are application specific, for future work, this implementation of Round-
robin arbiter can be modified to suit the intended usage. One of the applications of
Round-robin arbiter is system-on-chip shared memory. In this application, two independent
Round-robin arbiters are used, one for address and one for data. For read access, the two
arbiters can operate independently[21]. However, for write back operations, both the data
and address needs to go together[22]. It might be beneficial to implement a modified
version that is aware of the condition when address or data arbiter needs to freeze in order
to write back.
Another applications is communication arbiter for Network-On-Chip (NOC), where
communication between IP cores are usually non-uniform or hot-spot in traffic[22, 23].
The arbiter in this work only allow a fixed time slice preconfigured. It would be beneficial
to implement logic to detect the load of the inputs and adjust priority dynamically. By
adjusting priority or grant time based on the traffic would make sure that busy master/re-
questor traffic is well balanced and not starved.
References
[2] Z. Fu and X. Ling, “The design and implementation of arbiters for Network-on-chips,”
in 2010 2nd International Conference on Industrial and Information Systems, vol. 1,
July 2010, pp. 292–295.
[3] C. Spear, SystemVerilog for Verification: A Guide to Learning the Testbench Language
Features. New York NY: Springer, 2006.
[7] Y. Yang, R. Wu, L. Zhang, and D. Zhou, “An Asynchronous Adaptive Priority Round-
Robin Arbiter Based on Four-Phase Dual-rail Protocol,” Chinese Journal of Electron-
ics, vol. 24, no. 1, pp. 1–7, 2015.
[9] R. Kamal and J. M. M. Arostegui, “RTL implementation and analysis of fixed pri-
ority, round robin, and matrix arbiters for the NoC’s routers,” in 2016 International
Conference on Computing, Communication and Automation (ICCCA), April 2016,
pp. 1454–1459.
[10] E. S. Shin, V. J. Mooney, and G. F. Riley, “Round-robin Arbiter Design and Gener-
ation,” in 15th International Symposium on System Synthesis, 2002., Oct 2002, pp.
243–248.
[12] H. F. Ugurdag, F. Temizkan, O. Baskirt, and B. Yuce, “Fast two-pick n2n round-robin
arbiter circuit,” Electronics Letters, vol. 48, no. 13, pp. 759–760, June 2012.
[13] K. C. Lee, “A variable round-robin arbiter for high speed buses and statistical mul-
tiplexers,” in [1991 Proceedings] Tenth Annual International Phoenix Conference on
Computers and Communications, Mar 1991, pp. 23–29.
References 32
[16] D. Rich, “The unique challenges of debugging design and verification code jointly in
SystemVerilog,” in Proceedings of the 2013 Forum on specification and Design Lan-
guages (FDL), Sept 2013, pp. 1–7.
[20] Y. Zhu, T. Li, J. Guo, H. Zhou, and F. Fu, “A novel low-cost interface design for Sys-
References 33
[22] J. Reed and N. Manjikian, “A dual round-robin arbiter for split-transaction buses
in system-on-chip implementations,” in Canadian Conference on Electrical and Com-
puter Engineering 2004 (IEEE Cat. No.04CH37513), vol. 2, May 2004, pp. 835–840
Vol.2.
[23] A. A. Khan, R. N. Mir, and N. ud din, “Buffer aware arbiter design to achieve improved
QoS for NoC,” in TENCON 2017 - 2017 IEEE Region 10 Conference, Nov 2017, pp.
2494–2499.
[24] J. Bromley, “If SystemVerilog is so good, why do we need the UVM? Sharing respon-
sibilities between libraries and the core language,” in Proceedings of the 2013 Forum
on specification and Design Languages (FDL), Sept 2013, pp. 1–7.
[25] J. Wang, Y. Li, Q. Peng, and T. Tan, “A dynamic priority arbiter for Network-on-
Chip,” in 2009 IEEE International Symposium on Industrial Embedded Systems, July
2009, pp. 253–256.
Appendix I
// MUX module
// This module s e l e c t s one o f t h e i n p u t s a c c o r d i n g t o t h e i n p u t s e l e c t
signal
// C o m b i n a t i o n a l L o g i c
// I n p u t : selOneHot − s i g n a l ONE HOT STYLE
// : daataInBus − i n p u t d a t a bus f o r a l l c h a n n e l s c o n c a t from
ch0 t o
// chN
// Output : dataOut − o u t p u t d a t a a c c o r d i n g t o s e l e c t s i g n a l
//
module MUX
#(
parameter WIDTH = 3 2 , // w i d t h o f each c h a n n e l
parameter CHANNELS = 8 // number o f c h a n n e l s
)
(
reset ,
clk ,
scan_in0 ,
scan_in1 ,
scan_in2 ,
scan_in3 ,
scan_in4 ,
scan_enable ,
I-2
test_mode ,
scan_out0 ,
scan_out1 ,
scan_out2 ,
scan_out3 ,
scan_out4 ,
selOneHot , // one h o t s e l e c t i n p u t
dataInBus , // i n p u t bus
dataOut // o u t p u t d a t a
);
input
reset , // system r e s e t
clk ; // system c l o c k
input
scan_in0 , // test scan mode data input
scan_in1 , // test scan mode data input
scan_in2 , // test scan mode data input
scan_in3 , // test scan mode data input
scan_in4 , // test scan mode data input
scan_enable , // test scan mode enable
test_mode ; // test mode
output
scan_out0 , // test scan mode data output
scan_out1 , // test scan mode data output
scan_out2 , // test scan mode data output
scan_out3 , // test scan mode data output
scan_out4 ; // test scan mode data output
output r e g
[ (WIDTH−1) : 0 ] dataOut ; // o u t p u t d a t a a f t e r s e l e c t
// r e g [ (CHANNELS∗WIDTH)−1 : 0 ] tempData ;
// g e n e r a t e v a r i a b l e
genvar gv ;
I-3
// temporary a r r a y t o h o l d i n p u t c h a n n e l s
w i r e [ (WIDTH−1) : 0 ] i n p u t A r r a y [ 0 : (CHANNELS−1) ] ;
generate
// g e n e r a t e s t a t e m e n t t o a s s i g n i n p u t c h a n n e l s t o temp a r r a y
f o r ( gv = 0 ; gv < CHANNELS; gv = gv+1) b e g i n : a r r a y A s s i g n m e n t s
end // a r r a y A s s i g n m e n t s
endgenerate
// f u n c t i o n t o c o n v e r t one h o t t o d e c i m a l
function i n t e g e r decimal ;
i n p u t [CHANNELS−1 : 0 ] oneHotInput ;
integer i ;
f o r ( i = 0 ; i <CHANNELS; i = i +1)
i f ( oneHotInput [ i ] )
decimal = i ;
endfunction
// s e l e c t t h e o u t p u t a c c o r d i n g t o i n p u t oneHot
always@ ∗
begin
dataOut = i n p u t A r r a y [ d e c i m a l ( selOneHot ) ] ;
end // end a l w a y s
endmodule // MUX
I-4
module t e s t ;
l o c a l p a r a m WIDTH = 3 2 ;
l o c a l p a r a m CHANNELS = 8 ;
// c l o c k p e r i o d
l o c a l p a r a m CLOCK_PERIOD = 2 0 ; // 20 ns (50Mhz)
// i n p u t s
r e g [ (CHANNELS−1) : 0 ] t e s t _ s e l O n e H o t ;
r e g [ (CHANNELS∗WIDTH)−1 : 0 ] t e s t _ d a t a I n B u s ;
// o u t p u t
w i r e [ (WIDTH−1) : 0 ] test_dataOut ;
// f l o w control flags
integer testDoneFlag = 0 ;
integer i = 1;
integer j = 0;
integer k = 0;
integer waveCounter = 1 ;
// temp r e g / v a r i a b l e s
r e g [ (WIDTH−1) : 0 ] tempDataIn ;
r e g [ (WIDTH−1) : 0 ] dataArray [ (CHANNELS−1) : 0 ] ; // a r r a y t o c h e c k
output
MUX top (
. reset ( reset ) ,
. clk ( clk ) ,
. scan_in0 ( scan_in0 ) ,
. scan_in1 ( scan_in1 ) ,
. scan_in2 ( scan_in2 ) ,
. scan_in3 ( scan_in3 ) ,
. scan_in4 ( scan_in4 ) ,
I-5
. scan_enable ( scan_enable ) ,
. test_mode ( test_mode ) ,
. scan_out0 ( scan_out0 ) ,
. scan_out1 ( scan_out1 ) ,
. scan_out2 ( scan_out2 ) ,
. scan_out3 ( scan_out3 ) ,
. scan_out4 ( scan_out4 ) ,
. selOneHot ( t e s t _ s e l O n e H o t ) ,
. dataInBus ( t e s t _ d a t a I n B u s ) ,
. dataOut ( test_dataOut )
);
initial
begin
$ t i m e f o r m a t ( −9 ,2 , " ns " , 1 6 ) ;
` i f d e f SDFSCAN
$ s d f _ a n n o t a t e ( " s d f /ADDC_tsmc18_scan . s d f " , t e s t . top ) ;
`endif
c l k = 1 ' b0 ;
r e s e t = 1 ' b0 ;
scan_in0 = 1 ' b0 ;
scan_in1 = 1 ' b0 ;
scan_in2 = 1 ' b0 ;
scan_in3 = 1 ' b0 ;
scan_in4 = 1 ' b0 ;
scan_enable = 1 ' b0 ;
test_mode = 1 ' b0 ;
// i n i t i a l i z e i n p u t t o 1
test_ s e l O n e H o t = 1 ;
// s e t t h e v e r y f i r s t w e i g h t t o 2 ( c h a n n e l 0)
test_dataInBus = 2 ;
tempDataIn = 2 ;
dataArray [ 0 ] = 2 ;
// i n p u t w e i g h t d a t a bus g e n e r a t i o n
f o r ( j = 1 ; j < CHANNELS; j = j +1)
begin
// m a n i p u l a t e t e s t d a t a f o r each c h a n n e l ( i n c r e m e n t by 2 i n
t h i s case )
tempDataIn = tempDataIn + 2 ;
I-6
// s e t w e i g h t d a t a bus by s h i f t i n g and b i t w i s e or
t e s t _ d a t a I n B u s = t e s t _ d a t a I n B u s | ( tempDataIn << WIDTH∗ j ) ;
// s a v e d a t a t o o u t p u t c h e c k e r a r r a y as w e l l
dataArray [ j ] = tempDataIn ;
end
while ( ! testDoneFlag )
begin
@( p o s e d g e c l k )
begin
// a s s i g n i t o s e l i n p u t as t e s t v e c t o r
test_selOneHot = i ;
// i =1 w i l l be s h i f t e d by 1 from b i t 0 t o b i t (WIDTH−1)
i = i << 1 ;
// r e s e t i f we o v e r f l o w
i f ( t e s t _ s e l O n e H o t == 0 )
i = 1;
end
end
end
// c h e c k o u t p u t i n p a r a l l e l on n e g a t i v e e d g e
always @( negedge c l k )
begin
f o r ( k = 0 ; k < CHANNELS; k = k+1)
begin
// make s u r e i n p u t i s v a l i d ( one h o t )
i f ( t e s t _ s e l O n e H o t == 1 << k )
// c h e c k i f DUT o u t p u t matches e x p e c t e d o u t p u t
i f ( test_dataOut !== dataArray [ k ] )
begin
// d i s p l a y u s e f u l i n f o r m a t i o n i f t h e o u t p u t s don ' t
match
$ d i s p l a y ( " Wrong␣ output ␣ a t ␣%0t " , $time ) ;
I-7
// s t o p i f we s e e e r r o r
// $ f i n i s h ;
end
end
// c ou n t waves
waveCounter = waveCounter + 1 ;
// s t o p i f we l o o p e d t h r o u g h a l l c h a n n e l v a l u e s (∗2 t o s e e some
extra
// l e n g t h )
i f ( waveCounter >= CHANNELS∗ 2 )
$finish ;
end
// c l o c k g e n e r a t i o n
always #(CLOCK_PERIOD/ 2 )
clk = ~clk ;
endmodule
I-8
// NGPRC module
// Next Grant P Re Ca l cu la t e
//
//
// This module p r e c a l c u l a t e t h e mask f o r t h e Grant P r o c e s s
// The mask i s s h f t e d l e f t t o d i c t a t e round r o b i n manner
// I n p u t : r e q u e s t , g r a n t
// Output : nextGrant mask
//
module NGPRC
#(
parameter CHANNELS = 8 // t o t a l number o f r e q u e s t o r s
)
(
reset ,
clk ,
scan_in0 ,
scan_in1 ,
scan_in2 ,
scan_in3 ,
scan_in4 ,
scan_enable ,
test_mode ,
scan_out0 ,
scan_out1 ,
scan_out2 ,
scan_out3 ,
scan_out4 ,
// i n p u t s
request , // r e q u e s t i n p u t
grant , // g r a n t i n p u t
// o u t p u t s
nextGrant // n e x t g r a n t o u t p u t
);
input
reset , // system r e s e t
clk ; // system c l o c k
I-9
input
scan_in0 , // test scan mode data input
scan_in1 , // test scan mode data input
scan_in2 , // test scan mode data input
scan_in3 , // test scan mode data input
scan_in4 , // test scan mode data input
scan_enable , // test scan mode enable
test_mode ; // test mode
output
scan_out0 , // test scan mode data output
scan_out1 , // test scan mode data output
scan_out2 , // test scan mode data output
scan_out3 , // test scan mode data output
scan_out4 ; // test scan mode data output
i n p u t [ (CHANNELS−1) : 0 ] r e q u e s t ;
i n p u t [ ( CHANNELS−1) : 0 ] g r a n t ;
r e g [ (CHANNELS−1) : 0 ] p r i o r i t y M a s k ;
//−−− I n t e r n a l C o n s t a n t s −−−//
l o c a l p a r a m SIZE = 2 ;
// STATES
r e g [ ( SIZE−1) : 0 ] s t a t e ;
// a l w a y s b l o c k f o r s t a t e t r a n s i t i o n
always@ ( p o s e d g e c l k , p o s e d g e r e s e t )
begin : preCalStateTransition
i f ( r e s e t == 1 ' b1 )
begin
I-10
s t a t e = RESET;
end
else
// s t a t e t r a n s i t i o n
case ( state )
// c h e c k i f we a r e o u t o f r e s e t
RESET :
begin
// t r a n s i t i o n r i g h t away once NOT i n r e s e t
s t a t e = NEXT_GRANT;
end
NEXT_GRANT :
begin
// go b a c k t o r e s e t i f t h e r e i s r e s e t
state = state ;
end
default :
begin
// s t a y i n t h e same s t a t e
s t a t e = RESET;
end
endcase
end
// o u t p u t l o g i c
always @( p o s e d g e c l k , p o s e d g e r e s e t )
b e g i n : preCalOutputLogic
i f ( r e s e t == 1 ' b1 )
begin
nextGrant = 0 ;
priorityMask = 0;
end
else
I-11
case ( state )
// r e s e t s i g n a l s i n r e s e t s t a t e
RESET :
begin
nextGrant = 0 ;
priorityMask = ~0;
end
// s e t n e x t g r a n t and p r i o r i t y M a s k
// Handle wrap around c a s e
NEXT_GRANT :
begin
// c a l c u l a t e p r i o r i t y M a s k
// R o t a t e l e f t , i n v e r t and add 1
p r i o r i t y M a s k = ~{ g r a n t [CHANNELS−2 : 0 ] , g r a n t [CHANNELS−1]}
+ 1;
// i f g r a n t somehow becomes ze r o , s e t p r i o r i t y M a s k t o a l l
1
i f ( p r i o r i t y M a s k == 0 )
priorityMask = ~0;
else
priorityMask = priorityMask ;
// c a l c u l a t e nextGrant
nextGrant = r e q u e s t & p r i o r i t y M a s k ;
// nextGrant = p r i o r i t y M a s k ;
// i f we s e e a r e q u e s t b u t nextGrant i s z e r o
// i t means we wrap around
i f ( ( nextGrant == 0 ) && ( r e q u e s t != 0 ) )
nextGrant = request ;
end
// i f s t a t e m a c h i n e n e v e r g o e s o u t o f wack
// we s h o u l d NOT r e a c h t o t h i s c a s e
default :
begin
// k e e p a l l t h e s i g n a l s t h e same
I-12
priorityMask = priorityMask ;
nextGrant = nextGrant ;
end
endcase
end
endmodule //NGPRC
I-13
module t e s t ;
l o c a l p a r a m WIDTH = 3 2 ;
l o c a l p a r a m CHANNELS = 8 ;
// c l o c k p e r i o d
l o c a l p a r a m CLOCK_PERIOD = 1 0 0 ; // 20 ns (50Mhz)
// i n p u t s
r e g [ (CHANNELS−1) : 0 ] t e s t _ r e q u e s t ;
r e g [ (CHANNELS−1) : 0 ] t e s t _ g r a n t ;
// f l o w c o n t r o l
r e g [ (CHANNELS−1) : 0 ] expectedNextGrant ;
reg sticky ;
// o u t p u t
w i r e [ (CHANNELS−1) : 0 ] t es t_n e x tG r an t ;
w i r e [ 4 : 0 ] test_debugPreCal ;
NGPRC top (
. reset ( reset ) ,
. clk ( clk ) ,
. scan_in0 ( scan_in0 ) ,
. scan_in1 ( scan_in1 ) ,
. scan_in2 ( scan_in2 ) ,
. scan_in3 ( scan_in3 ) ,
. scan_in4 ( scan_in4 ) ,
. scan_enable ( scan_enable ) ,
. test_mode ( test_mode ) ,
. scan_out0 ( scan_out0 ) ,
. scan_out1 ( scan_out1 ) ,
I-14
. scan_out2 ( scan_out2 ) ,
. scan_out3 ( scan_out3 ) ,
. scan_out4 ( scan_out4 ) ,
// i n p u t
. request ( test_request ) ,
. grant ( test_grant ) ,
// o u t p u t
. nextGrant ( t e s t_ n e xt G ra n t )
// . debugPreCal ( t e s t _ d e b u g P r e C a l )
);
initial
begin
$ t i m e f o r m a t ( −9 ,2 , " ns " , 1 6 ) ;
` i f d e f SDFSCAN
$ s d f _ a n n o t a t e ( " s d f /ADDC_tsmc18_scan . s d f " , t e s t . top ) ;
`endif
c l k = 1 ' b0 ;
r e s e t = 1 ' b1 ;
scan_in0 = 1 ' b0 ;
scan_in1 = 1 ' b0 ;
scan_in2 = 1 ' b0 ;
scan_in3 = 1 ' b0 ;
scan_in4 = 1 ' b0 ;
scan_enable = 1 ' b0 ;
test_mode = 1 ' b0 ;
sticky = 0;
test_request = 0;
test_grant = 0;
// r e l e a s e r e s e t
@( p o s e d g e c l k ) ;
r e s e t = 1 ' b0 ;
// t e s t c a s e 1
// r e q u e s t = 0000_000
// g r a n t = don ' t c a r e
// nextGrant = 0000 _0000
@( p o s e d g e c l k ) ;
test_request = 0;
test_grant = 0;
I-15
expectedNextGrant = 0 ;
$ d i s p l a y ( "−−−−−Test ␣ c a s e ␣1−−−−−" ) ;
$ d i s p l a y ( " Request ␣=␣%b " , t e s t _ r e q u e s t ) ;
$ d i s p l a y ( " g r a n t ␣=␣%b " , t e s t _ g r a n t ) ;
@( negedge c l k ) ;
i f ( tes t _ ne x tG r a nt != expectedNextGrant )
begin
sticky = 1;
$ d i s p l a y ( " Expected ␣ next ␣ g r a n t ␣=␣%b , ␣ Actual ␣=␣%b " ,
expectedNextGrant , t es t _n e x tG r an t ) ;
end
else
$ d i s p l a y ( " next ␣ g r a n t ␣=␣%b " , t es t _n e x tG r an t ) ;
// t e s t c a s e 2
// r e q u e s t = 1111 _1111
// g r a n t = 0001
// nextGrant = 1111 _1110
@( p o s e d g e c l k ) ;
t e s t _ r e q u e s t = 8 'hFF ;
test_grant = 1;
expectedNextGrant = 8 ' b1111_1110 ;
$ d i s p l a y ( "−−−−−Test ␣ c a s e ␣2−−−−−" ) ;
$ d i s p l a y ( " Request ␣=␣%b " , t e s t _ r e q u e s t ) ;
$ d i s p l a y ( " g r a n t ␣=␣%b " , t e s t _ g r a n t ) ;
@( negedge c l k ) ;
i f ( tes t _ ne x tG r a nt != expectedNextGrant )
begin
sticky = 1;
$ d i s p l a y ( " Expected ␣ next ␣ g r a n t ␣=␣%b , ␣ Actual ␣=␣%b " ,
expectedNextGrant , t es t _n e x tG r an t ) ;
end
else
$ d i s p l a y ( " next ␣ g r a n t ␣=␣%b " , t es t _n e x tG r an t ) ;
// t e s t c a s e 3
// r e q u e s t = 1111 _1111
// g r a n t = 0010
// nextGrant = 1111 _1100
@( p o s e d g e c l k ) ;
I-16
t e s t _ r e q u e s t = 8 'hFF ;
t e s t _ g r a n t = 8 ' b0000_0010 ;
expectedNextGrant = 8 ' b1111_1100 ;
$ d i s p l a y ( "−−−−−Test ␣ c a s e ␣3−−−−−" ) ;
$ d i s p l a y ( " Request ␣=␣%b " , t e s t _ r e q u e s t ) ;
$ d i s p l a y ( " g r a n t ␣=␣%b " , t e s t _ g r a n t ) ;
@( negedge c l k ) ;
i f ( tes t _ ne x tG r a nt != expectedNextGrant )
begin
sticky = 1;
$ d i s p l a y ( " Expected ␣ next ␣ g r a n t ␣=␣%b , ␣ Actual ␣=␣%b " ,
expectedNextGrant , t es t _n e x tG r an t ) ;
end
else
$ d i s p l a y ( " next ␣ g r a n t ␣=␣%b " , t es t _n e x tG r an t ) ;
// t e s t c a s e 4
// r e q u e s t = 1111 _1111
// g r a n t = 0000 _0100
// nextGrant = 1111 _1000
@( p o s e d g e c l k ) ;
t e s t _ r e q u e s t = 8 'hFF ;
t e s t _ g r a n t = 8 ' b0000_0100 ;
expectedNextGrant = 8 ' b1111_1000 ;
$ d i s p l a y ( "−−−−−Test ␣ c a s e ␣4−−−−−" ) ;
$ d i s p l a y ( " Request ␣=␣%b " , t e s t _ r e q u e s t ) ;
$ d i s p l a y ( " g r a n t ␣=␣%b " , t e s t _ g r a n t ) ;
@( negedge c l k ) ;
i f ( tes t _ ne x tG r a nt != expectedNextGrant )
begin
sticky = 1;
$ d i s p l a y ( " Expected ␣ next ␣ g r a n t ␣=␣%b , ␣ Actual ␣=␣%b " ,
expectedNextGrant , t es t _n e x tG r an t ) ;
end
else
$ d i s p l a y ( " next ␣ g r a n t ␣=␣%b " , t es t _n e x tG r an t ) ;
// t e s t c a s e 5
// r e q u e s t = 1111 _1111
// g r a n t = 1000 _0000
// nextGrant = 1111 _1111
@( p o s e d g e c l k ) ;
I-17
t e s t _ r e q u e s t = 8 'hFF ;
t e s t _ g r a n t = 8 ' b1000_0000 ;
expectedNextGrant = 8 ' b1111_1111 ;
$ d i s p l a y ( "−−−−−Test ␣ c a s e ␣5−−−−−" ) ;
$ d i s p l a y ( " Request ␣=␣%b " , t e s t _ r e q u e s t ) ;
$ d i s p l a y ( " g r a n t ␣=␣%b " , t e s t _ g r a n t ) ;
@( negedge c l k ) ;
i f ( tes t _ ne x tG r a nt != expectedNextGrant )
begin
sticky = 1;
$ d i s p l a y ( " Expected ␣ next ␣ g r a n t ␣=␣%b , ␣ Actual ␣=␣%b " ,
expectedNextGrant , t es t _n e x tG r an t ) ;
end
else
$ d i s p l a y ( " next ␣ g r a n t ␣=␣%b " , t es t _n e x tG r an t ) ;
// t e s t c a s e 6
// r e q u e s t = 0000 _0000
// g r a n t = don ' t c a r e
// nextGrant = 0000 _0000
@( p o s e d g e c l k ) ;
t e s t _ r e q u e s t = 8 ' h00 ;
t e s t _ g r a n t = 8 ' b1 ;
expectedNextGrant = 8 ' b0 ;
$ d i s p l a y ( "−−−−−Test ␣ c a s e ␣6−−−−" ) ;
$ d i s p l a y ( " Request ␣=␣%b " , t e s t _ r e q u e s t ) ;
$ d i s p l a y ( " g r a n t ␣=␣%b " , t e s t _ g r a n t ) ;
@( negedge c l k ) ;
i f ( tes t _ ne x tG r a nt != expectedNextGrant )
begin
sticky = 1;
$ d i s p l a y ( " Expected ␣ next ␣ g r a n t ␣=␣%b , ␣ Actual ␣=␣%b " ,
expectedNextGrant , t es t _n e x tG r an t ) ;
end
else
$ d i s p l a y ( " next ␣ g r a n t ␣=␣%b " , t es t _n e x tG r an t ) ;
// t e s t c a s e 7
// r e q u e s t = 0000 _0010
// g r a n t = 0000 _0010
I-18
// t e s t c a s e 8
// r e q u e s t = 0000 _0010
// g r a n t = 0
// nextGrant = 0000 _0010
@( p o s e d g e c l k )
t e s t _ g r a n t = 8 ' b0000_0010 ;
t e s t _ g r a n t = 8 ' b0 ;
expectedNextGrant = 8 ' b0000_0010 ;
$ d i s p l a y ( "−−−−−Test ␣ c a s e ␣8−−−−−" ) ;
$ d i s p l a y ( " Request ␣=␣%b " , t e s t _ r e q u e s t ) ;
$ d i s p l a y ( " g r a n t ␣=␣%b " , t e s t _ g r a n t ) ;
@( negedge c l k ) ;
i f ( tes t _ ne x tG r a nt != expectedNextGrant )
begin
sticky = 1;
$ d i s p l a y ( " Expected ␣ next ␣ g r a n t ␣=␣%b , ␣ Actual ␣=␣%b " ,
expectedNextGrant , t es t _n e x tG r an t ) ;
end
else
$ d i s p l a y ( " next ␣ g r a n t ␣=␣%b " , t es t _n e x tG r an t ) ;
@( p o s e d g e c l k )
r e s e t = 1 ' b1 ;
I-19
@( p o s e d g e c l k )
r e s e t = 1 ' b0 ;
@( p o s e d g e c l k ) ;
@( p o s e d g e c l k ) ;
@( p o s e d g e c l k ) ;
i f ( s t i c k y == 1 )
$ d i s p l a y ( " Test ␣ f a i l e d " ) ;
else
$ d i s p l a y ( " Test ␣ p a s s e d " ) ;
$finish ;
end
// c h e c k o u t p u t i n p a r a l l e l on n e g a t i v e e d g e
// a l w a y s @( n e g e d g e c l k )
// b e g i n
// f o r ( k = 0 ; k < CHANNELS; k = k+1)
// begin
// make s u r e i n p u t i s v a l i d ( one h o t )
// i f ( t e s t _ s e l O n e H o t == 1 << k )
// c h e c k i f DUT o u t p u t matches e x p e c t e d o u t p u t
// i f ( t e s t _ d a t a O u t !== dataArray [ k ] )
// begin
// d i s p l a y u s e f u l i n f o r m a t i o n i f t h e o u t p u t s don ' t
match
// $ d i s p l a y ( " Wrong o u t p u t a t %0t " , $time ) ;
// $ d i s p l a y ( " E x p e c t e d %H, A c t u a l %H" , dataArray [ k ] ,
test_dataOut ) ;
// s t o p i f we s e e e r r o r
// $ f i n i s h ;
// end
// end
// c ou n t waves
I-20
// waveCounter = waveCounter + 1 ;
// s t o p i f we l o o p e d t h r o u g h a l l c h a n n e l v a l u e s (∗2 t o s e e some
extra
// l e n g t h )
// i f ( waveCounter >= CHANNELS∗2)
// $finish ;
// end
// c l o c k g e n e r a t i o n
always #(CLOCK_PERIOD/ 2 )
clk = ~clk ;
endmodule
I-21
// GRANT module
//
//
module GRANT
#(
parameter CHANNELS = 8 , // t o t a l number o f r e q u e s t o r s
parameter WIDTH = 3 2 , // t h e w i d t h o f each r e q u e s t o r ' s
weight
parameter WEIGHTLIMIT = 16
)
(
reset ,
clk ,
scan_in0 ,
scan_in1 ,
scan_in2 ,
scan_in3 ,
scan_in4 ,
scan_enable ,
test_mode ,
scan_out0 ,
scan_out1 ,
scan_out2 ,
scan_out3 ,
scan_out4 ,
// i n p u t
request , // r e q u e s t i n p u t
nextGrant , // nextGrant from NGPRC
weight , // w e i g h t o f c u r r e n t g r a n t
// o u t p u t
grant // g r a n t o u t p u t
);
input
reset , // system r e s e t
clk ; // system c l o c k
input
scan_in0 , // t e s t scan mode d a t a i n p u t
I-22
output
scan_out0 , // test scan mode data output
scan_out1 , // test scan mode data output
scan_out2 , // test scan mode data output
scan_out3 , // test scan mode data output
scan_out4 ; // test scan mode data output
// i n p u t
i n p u t [ (CHANNELS−1) : 0 ] r e q u e s t ;
i n p u t [ ( CHANNELS−1) : 0 ] nextGrant ;
i n p u t [ (WIDTH−1) : 0 ] w e i g h t ;
// o u t p u t
output r e g [ ( CHANNELS−1) : 0 ] g r a n t ;
// i n t e r n a l r e g i s t e r s
r e g [ (WIDTH−1) : 0 ] s_counter ;
r e g [ (CHANNELS−1) : 0 ] s _ r e q u e s t ;
r e g [ (WIDTH−1) : 0 ] s_weight ;
// r e g u p d a t e ;
//−−− I n t e r n a l C o n s t a n t s −−−//
l o c a l p a r a m SIZE = 4 ;
// STATES
r e g [ ( SIZE−1) : 0 ] s t a t e ;
l o c a l p a r a m RESET = ' b0001 ; // ' b00001
l o c a l p a r a m GRANT_PROCESS = ' b0010 ; // ' b00100
l o c a l p a r a m COUNT = ' b0100 ; // ' b01000
l o c a l p a r a m GETWEIGHT = ' b1000 ; // ' b10000
// r e g i s t e r i / d e l a y r e q u e s t
always@ ( p o s e d g e c l k , p o s e d g e r e s e t )
begin : requestDelay
I-23
i f ( r e s e t == 1 ' b1 )
s_request = 0;
else
s_request = request ;
end
// a l w a y s b l o c k f o r s t a t e t r a n s i t i o n
always@ ( p o s e d g e c l k , p o s e d g e r e s e t )
begin : grantStateTransition
// r e s e t c o n d i t i o n
i f ( r e s e t == 1 ' b1 )
begin
state = 0;
end
// o u t o f r e s e t
else
begin
// s t a t e t r a n s i s i t o n
case ( state )
// g r a n t p r o c e s s t h i s o u t p u t g r a n t
GRANT_PROCESS :
begin
// i f t h e r e i s r e q u e s t
// go t o COUNT s t a t e t o co u nt
i f ( g r a n t != 0 )
s t a t e = GETWEIGHT;
// j u s t s t a y h e r e and p r o c e s s n e x t
else
state = state ;
end
GETWEIGHT :
begin
s t a t e = COUNT;
end
// c ou n t c l o c k c y c l e a c c o r d i n g t o w e i g h t
COUNT :
begin
// i f c o u n t e r i s up
I-24
// move t o g r a n t n e x t
i f ( s_counter >= s_weight )
s t a t e = GRANT_PROCESS;
// f a i r n e s s l i m i t s e t by u s e r
// d e f a u l t i s 16
e l s e i f ( s_counter >= WEIGHTLIMIT)
s t a t e = GRANT_PROCESS;
// e l s e
// k e e p c o u n t i n g
else
state = state ;
end
// i f s t a t e m a c h i n e n e v e r g o e s o u t o f wack
default :
begin
s t a t e = GRANT_PROCESS;
end
endcase
end
end
// o u t p u t l o g i c
always@ ( p o s e d g e c l k , p o s e d g e r e s e t )
b e g i n : gr a n t S t a t e M a c h i n e O u t p u t L o g i c
i f ( r e s e t == 1 ' b1 )
begin
grant = 0;
s_counter = 0 ;
s_weight = 0 ;
end
else
case ( state )
RESET :
begin
// r e s e t e v e r y t h i n g i n r e s e t s t a t e
grant = 0;
I-25
s_counter = 0 ;
//s_mask = ~ 0 ;
end
GRANT_PROCESS :
begin
// u p d a t e mask
//s_mask = nextGrant & (~ nextGrant + 1) ;
// g r a n t i n g l o g i c
g r a n t = r e q u e s t & nextGrant & (~ nextGrant + 1 ) ;
// i t t a k e s 3 c y c l e t o l o o k b a c k h e r e
// so s e t t h e c o u n t e r f o r when w e i g h t >= 2
s_counter = 2 ;
end
GETWEIGHT:
begin
s_weight = w e i g h t ;
end
COUNT :
begin
// c ou n t up u n t i l w e i g h t i s r e a c h e d a c c o u n t f o r c l o c k
cycle
s_counter = s_counter + 1 ;
// no change t o g r a n t
grant = grant ;
end
// i f s t a t e m a c h i n e n e v e r g o e s o u t o f wack
default :
begin
grant = grant ;
s_counter = s_counter ;
end
endcase
end
I-26
endmodule // GRANT
I-27
// RRBTOP module
// Top l e v e l o f Round Robin A r b i t e r
// This module c o n n e c t s MUX, Next Grant P r e c a l c u l a t o r and Grant
statemachine
// I n p u t : r e q u e s t , w e i g h t bus
// Output : g r a n t
`include " i n c l u d e / RRB_verification . h"
module RRBTOP
#(
parameter CHANNELS = `CHANNELS,
parameter WIDTH = `WIDTH,
parameter WEIGHTLIMIT = `WEIGHTLIMIT
)
(
reset ,
clk ,
// i n p u t t o RRB
request ,
weight , // w e i g h t bus each h a v i n g b i t s i z e o f WIDTH f o r
each c h a n n e l
// o u t p u t from RRB
grant ,
scan_in0 ,
scan_in1 ,
scan_in2 ,
scan_in3 ,
scan_in4 ,
scan_enable ,
test_mode ,
scan_out0 ,
scan_out1 ,
scan_out2 ,
scan_out3 ,
scan_out4
);
input
I-28
reset , // system r e s e t
clk ; // system c l o c k
input
scan_in0 , // test scan mode data input
scan_in1 , // test scan mode data input
scan_in2 , // test scan mode data input
scan_in3 , // test scan mode data input
scan_in4 , // test scan mode data input
scan_enable , // test scan mode enable
test_mode ; // test mode
output
scan_out0 , // test scan mode data output
scan_out1 , // test scan mode data output
scan_out2 , // test scan mode data output
scan_out3 , // test scan mode data output
scan_out4 ; // test scan mode data output
i n p u t [ (CHANNELS−1) : 0 ] r e q u e s t ;
i n p u t [ (CHANNELS∗WIDTH)−1 : 0 ] w e i g h t ;
output w i r e [ ( CHANNELS−1) : 0 ] g r a n t ;
w i r e [ (CHANNELS−1) : 0 ] s_selOneHot ;
w i r e [ (WIDTH−1) : 0 ] s_weight ;
w i r e [ (CHANNELS−1) : 0 ] s_nextGrant ;
// COMBINATIONAL SECTION //
a s s i g n g r a n t = s_selOneHot ;
// MUX
MUX #(
.WIDTH(WIDTH) ,
.CHANNELS(CHANNELS)
)
MUX(
. reset ( reset ) ,
. clk ( clk ) ,
I-29
. scan_in0 ( scan_in0 ) ,
. scan_in1 ( scan_in1 ) ,
. scan_in2 ( scan_in2 ) ,
. scan_in3 ( scan_in3 ) ,
. scan_in4 ( scan_in4 ) ,
. scan_enable ( scan_enable ) ,
. test_mode ( test_mode ) ,
. scan_out0 ( scan_out0 ) ,
. scan_out1 ( scan_out1 ) ,
. scan_out2 ( scan_out2 ) ,
. scan_out3 ( scan_out3 ) ,
. scan_out4 ( scan_out4 ) ,
// i n p u t
. selOneHot ( s_selOneHot ) ,
. dataInBus ( w e i g h t ) ,
// o u t p u t
. dataOut ( s_weight )
);
NGPRC #(
.CHANNELS(CHANNELS)
)
NGPRC(
. reset ( reset ) ,
. clk ( clk ) ,
. scan_in0 ( scan_in0 ) ,
. scan_in1 ( scan_in1 ) ,
. scan_in2 ( scan_in2 ) ,
. scan_in3 ( scan_in3 ) ,
. scan_in4 ( scan_in4 ) ,
. scan_enable ( scan_enable ) ,
. test_mode ( test_mode ) ,
. scan_out0 ( scan_out0 ) ,
. scan_out1 ( scan_out1 ) ,
. scan_out2 ( scan_out2 ) ,
. scan_out3 ( scan_out3 ) ,
. scan_out4 ( scan_out4 ) ,
// i n p u t
. request ( request ) ,
I-30
. g r a n t ( s_selOneHot ) ,
// o u t p u t
. nextGrant ( s_nextGrant )
);
GRANT #(
.CHANNELS(CHANNELS) ,
.WIDTH(WIDTH) ,
. WEIGHTLIMIT(WEIGHTLIMIT)
)
GRANT(
. reset ( reset ) ,
. clk ( clk ) ,
. scan_in0 ( scan_in0 ) ,
. scan_in1 ( scan_in1 ) ,
. scan_in2 ( scan_in2 ) ,
. scan_in3 ( scan_in3 ) ,
. scan_in4 ( scan_in4 ) ,
. scan_enable ( scan_enable ) ,
. test_mode ( test_mode ) ,
. scan_out0 ( scan_out0 ) ,
. scan_out1 ( scan_out1 ) ,
. scan_out2 ( scan_out2 ) ,
. scan_out3 ( scan_out3 ) ,
. scan_out4 ( scan_out4 ) ,
// i n p u t
. request ( request ) ,
. nextGrant ( s_nextGrant ) ,
. w e i g h t ( s_weight ) ,
// o u t p u t
. g r a n t ( s_selOneHot )
);
endmodule // RRB
I-31
module t e s t ;
l o c a l p a r a m WIDTH = 3 2 ;
l o c a l p a r a m CHANNELS = 4 ;
l o c a l p a r a m WEIGHTLIMIT = 1 0 0 ;
// c l o c k p e r i o d
l o c a l p a r a m CLOCK_PERIOD = 2 0 ; // 20 ns (500MHZ)
// i n p u t s
r e g [ (CHANNELS∗WIDTH−1) : 0 ] t e s t _ w e i g h t ;
r e g [ (CHANNELS−1) : 0 ] t e s t _ r e q u e s t ;
// r e g t e s t _ a c k ;
// o u t p u t
w i r e [ (CHANNELS−1) : 0 ] t e s t _ g r a n t ;
//
r e g [ (WIDTH−1) : 0 ] tempData ;
// f l o w c o n t r o l f l a g s
integer j = 0;
RRBTOP #(
.CHANNELS(CHANNELS) ,
.WIDTH(WIDTH) ,
. WEIGHTLIMIT(WEIGHTLIMIT)
)
top (
. reset ( reset ) ,
. clk ( clk ) ,
. scan_in0 ( scan_in0 ) ,
. scan_in1 ( scan_in1 ) ,
. scan_in2 ( scan_in2 ) ,
. scan_in3 ( scan_in3 ) ,
I-32
. scan_in4 ( scan_in4 ) ,
. scan_enable ( scan_enable ) ,
. test_mode ( test_mode ) ,
. scan_out0 ( scan_out0 ) ,
. scan_out1 ( scan_out1 ) ,
. scan_out2 ( scan_out2 ) ,
. scan_out3 ( scan_out3 ) ,
. scan_out4 ( scan_out4 ) ,
// i n p u t
//
. request ( test_request ) ,
. weight ( test_weight ) ,
// . ack ( t e s t _ a c k ) ,
// o u t p u t
. grant ( test_grant )
);
initial
begin
$ t i m e f o r m a t ( −9 ,2 , " ns " , 1 6 ) ;
` i f d e f SDFSCAN
$ s d f _ a n n o t a t e ( " s d f /ADDC_tsmc18_scan . s d f " , t e s t . top ) ;
`endif
c l k = 1 ' b0 ;
r e s e t = 1 ' b1 ;
scan_in0 = 1 ' b0 ;
scan_in1 = 1 ' b0 ;
scan_in2 = 1 ' b0 ;
scan_in3 = 1 ' b0 ;
scan_in4 = 1 ' b0 ;
scan_enable = 1 ' b0 ;
test_mode = 1 ' b0 ;
// t e s t _ a c k = 1 ' b0 ;
test_request = 0;
// s e t t h e v e r y f i r s t w e i g h t t o 2 ( c h a n n e l 0)
tempData = 3 ;
I-33
test_weight = 3;
// i n p u t w e i g h t d a t a bus g e n e r a t i o n
f o r ( j = 1 ; j < CHANNELS; j = j +1)
begin
// m a n i p u l a t e t e s t d a t a f o r each c h a n n e l ( i n c r e m e n t by 2 i n
this
// c a s e )
tempData = tempData + 2 ;
// s e t w e i g h t d a t a bus by s h i f t i n g and b i t w i s e or
t e s t _ w e i g h t = t e s t _ w e i g h t | ( tempData << WIDTH∗ j ) ;
end
// p u l l r e s e t h i g h
@( p o s e d g e c l k ) ;
@( p o s e d g e c l k ) ;
r e s e t = 1 ' b0 ;
@( p o s e d g e c l k ) ;
t e s t _ r e q u e s t = ' b1001 ;
#100
@( p o s e d g e c l k ) ;
// t e s t _ a c k = 1 ' b1 ;
t e s t _ r e q u e s t = ' b0010 ;
@( p o s e d g e c l k ) ;
// t e s t _ a c k = 1 ' b0 ;
#160
@( p o s e d g e c l k ) ;
// t e s t _ a c k = 1 ' b1 ;
t e s t _ r e q u e s t = ' b0001 ;
@( p o s e d g e c l k ) ;
// t e s t _ a c k = 1 ' b0 ;
#500
$finish ;
I-34
end
// c l o c k g e n e r a t i o n
always #(CLOCK_PERIOD/ 2 )
clk = ~clk ;
endmodule
Appendix II
// requestor . sv
// r e q u e s t o r module
// t h i s module g e n e r a t e s
// random r e q u e s t (0 or 1)
// w e i g h t (0 t o 2^32−1)
class requestor ;
rand b i t r e q u e s t ; // r e q u e s t
rand b i t [ 3 1 : 0 ] w e i g h t ; // w e i g h t
int seed ;
i n t weightLow ;
i n t weightHigh ;
// c o n s t r a i n t w e i g h t b e t w e e n t h e l i m i t s
c o n s t r a i n t weight_range {
w e i g h t i n s i d e { [ weightLow : weightHigh ] } ;
}
// c o n s t r u c t o r
f u n c t i o n new ( i n t s e e d = 1 , i n t weightLow = 2 , i n t weightHigh =
100) ;
this . request = 0;
t h i s . w e i g h t = weightLow ;
II-36
t h i s . seed = seed ;
t h i s . weightLow = weightLow ;
t h i s . weightHigh = weightHigh ;
// i n i t i a l i z e random seed
t h i s . srandom ( s e e d ) ;
e n d f u n c t i o n : new
endclass
II-37
// generator . sv
// generator class
// This c l a s s g e n e r a t e s random s t i m u l u s
// i n t h i s case , i t i n s t a n t i a t e s m u l t i p l e r e q u e s t o r s
class generator ;
requestor req ;
// c o n s t r u c t o r method
f u n c t i o n new ( r e q u e s t o r r e q ) ;
t h i s . req = req ;
e n d f u n c t i o n : new
// g e n e r a t e random r e q u e s t s
extern function void generate_requestor ;
// g e t r e q u e s t
extern function bit get_request ;
// g e t w e i g h t
e x t e r n f u n c t i o n b i t [`WIDTH−1 : 0 ] get_weight ;
endclass : generator
//−−−−−−−−−−E x t e r n a l Methods−−−−−−−−−//
// g e n e r a t e f u n c t i o n
// no a r g i n p u t
// randomize t h e r e q u e s t o r
function void generator : : generate_requestor ;
begin : randomize_requestor
// g e n e r a t e random r e q u e s t / w e i g h t i n r e q u e s t o r
a s s e r t ( r e q . randomize ( ) ) ;
i f (`DEBUG_GENERATOR)
$ d i s p l a y ( " g e n e r a t e d ␣ r e q u e s t o r ␣ : ␣%p\n " , r e q ) ;
end : r a n d o m i z e _ r e q u e s t o r
II-38
endfunction : generate_requestor
// g e t method f o r r e q u e s t o r ' s r e q u e s t
function bit generator : : get_request ;
begin
return req . request ;
end
endfunction : get_request
// g e t method f o r r e q u e s t o r ' s w e i g h t
f u n c t i o n b i t [`WIDTH−1 : 0 ] g e n e r a t o r : : get_weight ;
begin
return req . weight ;
end
e n d f u n c t i o n : get_weight
II-39
// agent . sv
// agent c l a s s
// a g e n t i n s t a n t i a t e s g e n e r a t o r module
// u s i n g t h a t g e n e r a t o r t o g e n e r a t e random r e q u e s t s
c l a s s agent ;
g e n e r a t o r gen ;
b i t [`CHANNELS−1 : 0 ] r e q u e s t s ;
b i t [ ( `CHANNELS∗`WIDTH)−1 : 0 ] w e i g h t s ;
b i t [`CHANNELS−1 : 0 ] g o l d e n _ g r a n t s ;
i n t golden_grant_weights [`CHANNELS] = ' { d e f a u l t : 0 } ;
i n t temp_weights [`CHANNELS] = ' { d e f a u l t : 0 } ;
// c o n s t r u c t o r method
f u n c t i o n new ( g e n e r a t o r gen ) ;
t h i s . gen = gen ;
this . requests = 0;
t h i s . weights = 0;
t h i s . golden_grants = 0 ;
t h i s . golden_grant_weights = ' { d e f a u l t : 0 } ;
t h i s . temp_weights = ' { d e f a u l t : 0 } ;
e n d f u n c t i o n : new
// g e n e r a t e new r e q u e s t s
extern function void generate_requests ;
e n d c l a s s : agent
//−−−−−−−−−−E x t e r n a l Methods−−−−−−−−−−//
// g e n e r a t e _ r e q u e s t s f u n c t i o n
// no a r g i n p u t
// g e n e r a t e n number o f r e q u e s t o r s
f u n c t i o n void agent : : generate_requests ;
b e g i n : generateNewRequests
// o n l y g e t g o l d e n v e c t o r i f r e q u e s t s a r e not z e r o
II-40
// by g e t t i n g g o l d e n v e c t o r a t t h e s t a r t o f t h i s r o u t i n e
// we a r e e s s e n t i a l l y d e l a y i n g t h e u p d a t e by one t e s t v e c t o r
set
// t h i s a l l o w s g o l d e n v e c t o r s t o be i n sync w i t h c h e c k e r /
monitor /DUT
i f ( r e q u e s t s != 0 )
begin
// g o l d e n t e s t d a t a t o c h e c k DUT
golden_grants = r e q u e s t s ;
golden_grant_weights = temp_weights ;
// r e s e t w e i g h t s
weights = 0;
// l o o p t h r o u g h t o g e n e r a t e n random r e q u e s t s
f o r ( i n t i = 0 ; i < `CHANNELS; i ++)
begin
gen . g e n e r a t e _ r e q u e s t o r ( ) ;
// random r e q u e s t d a t a
r e q u e s t s [ i ] = gen . g e t _ r e q u e s t ( ) ;
w e i g h t s = w e i g h t s | gen . get_weight ( ) << ( i ∗ `WIDTH) ;
temp_weights [ i ] = gen . get_weight ( ) ;
// d i s p l a y i f debug a g e n t f l a g i s s e t
// debug o n l y
i f (`DEBUG_AGENT)
begin
// $ d i s p l a y ( " i = %d " , i ) ;
// $ d i s p l a y ( " r e q u e s t = %d " , gen . g e t _ r e q u e s t ( ) ) ;
// $ d i s p l a y ( " w e i g h t = %d " , gen . g e t _ w e i g h t ( ) ) ;
end
end
// debug
i f (`DEBUG_AGENT)
II-41
begin
$ d i s p l a y ( " r e q u e s t s ␣=␣%b " , r e q u e s t s ) ;
$ d i s p l a y ( " w e i g h t s ␣=␣%h " , w e i g h t s ) ;
end : generateNewRequests
endfunction : generate_requests
II-42
// d r i v e r . s v
// d r i v e r c l a s s
`include " i n c l u d e / RRB_verification . h"
class driver ;
// h a n d l e f o r i n t e r f a c e
virtual intf_rrb i n t f ;
// h a n d l e f o r a g e n t
agent agt ;
// e v e n t h a n d l e
event e_start ;
e v e n t e_drv_done ;
// c o n s t r u c t o r method
f u n c t i o n new ( v i r t u a l i n t f _ r r b i n t f , a g e n t agt , e v e n t e_drv_done ) ;
this . intf = intf ;
t h i s . agt = agt ;
t h i s . e_drv_done = e_drv_done ;
e n d f u n c t i o n : new
// r e s e t method
extern task r e s e t () ;
// d r i v e new d a t a
e x t e r n t a s k drive_new_data ( ) ;
// e v e n t l o g i c
extern task event_logic () ;
endclass : driver
//−−−−−−−−−−E x t e r n a l Methods−−−−−−−−−−//
// d r i v e new d a t a
t a s k d r i v e r : : drive_new_data ( ) ;
// we need t o know how l o n g t o w a i t t o know when d r i v e new d a t a
// so w a i t f o r w e i g h t c y c l e s b e f o r e s e n d i n g new d a t a
b i t [ ( `CHANNELS∗`WIDTH)−1 : 0 ] w a i t C y c l e s , temp ;
waitCycles = 0;
II-43
temp = 0 ;
// g e t t h e sum o f a l l t h e w e i g h t s
f o r ( i n t i = 0 ; i < `CHANNELS; i ++)
begin
temp = a g t . w e i g h t s >> ( i ∗`WIDTH) ;
w a i t C y c l e s = w a i t C y c l e s + temp [`WIDTH−1 : 0 ] ∗ ( a g t . r e q u e s t s [ i
]) ;
end
// debug o n l y
i f (`DEBUG_DRIVER)
begin
$ d i s p l a y ( " a g t ␣%p\n " , a g t ) ;
$ d i s p l a y ( " w a i t C y c l e s ␣%d\n " , w a i t C y c l e s ) ;
end
// send r e q u e s t t o DUT s y n c h r o n o u s l y
// o n l y need t o w a i t i f w a i t C y c l e i s not z e r o
i f ( waitCycles > 0)
begin
// w a i t f o r w a i t C y c l e s i f o r DUT t o perform a r b i t e r a t i o n
f o r ( i n t i = 0 ; i < ( w a i t C y c l e s ) ; i ++)
begin
@( p o s e d g e i n t f . DRIVER . c l k ) ;
i n t f . DRIVER . r e q u e s t = a g t . r e q u e s t s ;
i n t f . DRIVER . w e i g h t = a g t . w e i g h t s ;
end
// a f t e r w a i t c y c l e i s done , t e l l e v e n t l o g i c t o s t a r t c o u n t e r
−> e _ s t a r t ;
// $ d i s p l a y ( " s t a r t a t %g " , $time ) ;
end
e n d t a s k : drive_new_data
// Event l o g i c
// t o w a i t 2 c y c l e s a f t e r d r i v e r i s done d r i v i n g
// t o sync up w i t h end o f DUT o u t p u t
task driver : : event_logic () ;
forever
begin
//@( p o s e d g e i n t f .DRIVER. c l k ) ;
II-44
@( e _ s t a r t ) ;
// $ d i s p l a y ( " c a u g h t a t %g " , $time ) ;
// r e p e a t ( 2 )
//@( p o s e d g e i n t f .DRIVER. c l k ) ;
−> e_drv_done ;
// $ d i s p l a y ( " d r i v e r done i s s u e d " ) ;
end
endtask : event_logic
// R e s e t Method
task driver : : r e s e t () ;
// i n i t i a l i z e e v e r y t h i n g
i n t f . DRIVER . r e s e t = 1 ' b0 ;
i n t f . DRIVER . r e q u e s t = 0 ;
i n t f . DRIVER . w e i g h t = 0 ;
// r e s e t on n e g a t i v e e d g e
@( negedge i n t f . DRIVER . c l k ) ;
i n t f . DRIVER . r e s e t = 1 ' b1 ;
// w a i t f o r a few c y c l e s
@( negedge i n t f . DRIVER . c l k ) ;
@( negedge i n t f . DRIVER . c l k ) ;
i n t f . DRIVER . r e s e t = 1 ' b0 ;
// w a i t f o r a few c y c l e s
@( negedge i n t f . DRIVER . c l k ) ;
@( negedge i n t f . DRIVER . c l k ) ;
endtask : r e s e t
II-45
// monitor . s v
// monitor c l a s s
// Monitor c a p t u r e s DU o u t p u t
class monitor ;
// h a n d l e f o r i n t e r f a c e
virtual intf_rrb i n t f ;
// DUT o u t p u t v e c t o r s
b i t [`CHANNELS−1 : 0 ] dut_grants ;
i n t dut_weight_array [`CHANNELS] = ' { d e f a u l t : 0 } ;
// d a t a t o be s e n t t o c h e c k e r
b i t [`CHANNELS−1 : 0 ] mon_grants ;
i n t mon_weight_array [`CHANNELS] = ' { d e f a u l t : 0 } ;
// e v e n t h a n d l e s
e v e n t e_drv_done ;
e v e n t e_mon_done ;
// b i t t o i n d i c a t e d a t a ne ed s t o be c l e a r e d
bit clearData ;
// c o n s t r u c t o r method
f u n c t i o n new ( v i r t u a l i n t f _ r r b i n t f , e v e n t e_drv_done , e v e n t
e_mon_done ) ;
this . intf = intf ;
this . dut_grants = 0 ;
this . dut_weight_array = ' { d e f a u l t : 0 } ;
this . mon_grants = 0 ;
this . dut_weight_array = ' { d e f a u l t : 0 } ;
t h i s . e_drv_done = e_drv_done ;
t h i s . e_mon_done = e_mon_done ;
t h i s . clearData = 0;
e n d f u n c t i o n : new
II-46
// monitor t h e o u t p u t
e x t e r n t a s k run ;
// e v e n t l o g i c
extern task event_logic ;
e n d c l a s s : monitor
//−−−−−−−−−−E x t e r n a l Methods−−−−−−−−−−//
// run method
t a s k monitor : : run ;
// w a i t time f o r d r i v e r
forever
begin
// c a p t u r e d a t a on p o s i t i v e e d g e o f c l o c k
@( p o s e d g e i n t f .MONITOR. c l k ) ;
i f ( i n t f .MONITOR. g r a n t != 0 )
begin
// i f we need t o c l e a r c o u n t e r s , do i t f i r s t b e f o r e
couting again
i f ( clearData )
begin
dut_grants = 0 ;
dut_weight_array = ' { d e f a u l t : 0 } ;
clearData = 0;
end
dut_grants [ $ c l o g 2 ( i n t f .MONITOR. g r a n t ) ] = 1 ;
dut_weight_array [ $ c l o g 2 ( i n t f .MONITOR. g r a n t ) ] =
dut_weight_array [ $ c l o g 2 ( i n t f .MONITOR. g r a n t ) ] + 1 ;
end
end
e n d t a s k : run
II-47
// e v e n t l o g i c
// when d r i v e r i s done d r i v i n g , i t means one t e s t v e c t o r i s done
// we need t o r e g i s t e r d a t a f o r monitor t o be read
// a t t h e same time s e t c l e a r b i t t o c l e a r o u t c o u n t e r s
t a s k monitor : : e v e n t _ l o g i c ;
forever
begin
//@( p o s e d g e i n t f .MONITOR. c l k ) ;
// w a i t ( e_drv_done . t r i g g e r e d ) ;
@( e_drv_done ) ;
$ d i s p l a y ( " e v e n t t r i g g e r e d ␣ a t ␣%g " , $time ) ;
repeat (2)
@( p o s e d g e i n t f .MONITOR. c l k ) ;
// d r i v e r /DUT f i n i s h e d one s e t o f t e s t v e c t o r s
// r e g i s t e r / copy o u t p u t f o r monitor
mon_grants = dut_grants ;
mon_weight_array = dut_weight_array ;
// i n d i c a t e monitor i s r e a d y f o r c h e c k e r
−> e_mon_done ;
// i f we f i n i s h e d one s e t o f t e s t v e c t o r s
// we need t o c l e a r c o u n t e r s
clearData = 1;
i f (`DEBUG_MONITOR)
begin
$ d i s p l a y ( "−−−" ) ;
$ d i s p l a y ( " dut ␣ g r a n t ␣=␣%b␣ a t ␣%g " , dut_grants , $time ) ;
$ d i s p l a y ( "mon␣ g r a n t ␣=␣%b␣ a t ␣%g " , mon_grants , $time ) ;
end
II-48
end
end
endtask : event_logic
II-49
// c h e c k . s v
// c h e c k c l a s s
// g e t o u t p u t o f DUT and a g e n t d a t a
// and compare and r e c o r e d i n s c o r e b o a r d
c l a s s check ;
// c l a s s h a n d l e s
s c o r e b o a r d sb ;
agent agt ;
monitor mon ;
// e v e n t h a n d l e s
e v e n t e_mon_done ;
e v e n t e_drv_done ;
// g o l d e n t e s t v e c t o r s
b i t [`CHANNELS−1 : 0 ] chk_golden_grants ;
i n t chk_golden_grant_weights [`CHANNELS] = ' { d e f a u l t : 0 } ;
// c o n s t r u c t o r method
f u n c t i o n new ( s c o r e b o a r d sb , a g e n t agt , monitor mon , e v e n t
e_mon_done , e v e n t e_drv_done ) ;
t h i s . sb = sb ;
t h i s . agt = agt ;
t h i s . mon = mon ;
t h i s . e_mon_done = e_mon_done ;
t h i s . e_drv_done = e_drv_done ;
t h i s . chk_golden_grants = 0 ;
t h i s . chk_golden_grant_weights = ' { d e f a u l t : 0 } ;
e n d f u n c t i o n : new
// t a s k t o c h e c k t h e o u t p u t o f DUT
e x t e r n t a s k check_output ;
// t e s t t o u p d a t e t h e g o l d e n d a t a
// i t i s a l w a y s running b u t i n sync w i t h end o f d r i v e r done e v e n t
II-50
e x t e r n t a s k update_golden_data ;
e n d c l a s s : check
//−−−−−−−−−−E x t e r n a l Methods−−−−−−−−−−//
// c h e c k t h e o u t p u t o f DUT and Agent g o l d e n d a t a
t a s k check : : check_output ( ) ;
forever
begin
@( e_mon_done ) ;
i f (`DEBUG_CHECKER)
begin
$ d i s p l a y ( " l o c a l ␣ g o l d e n ␣ g r a n t ␣=␣%b " , chk_golden_grants ) ;
$ d i s p l a y ( "mon␣DUT␣ g r a n t ␣=␣%b␣ a t ␣%g " , mon . mon_grants , $time
);
// l o o p t h r o u g h a l l t h e c h a n n e l s and c h e c k t h e o u t p u t
f o r ( i n t i = 0 ; i < `CHANNELS; i ++)
begin
// i f t h e r e q u e s t i s 1 , c h e c k t h e w e i g h t
i f ( chk_golden_grants [ i ] == 1 )
begin
// $ d i s p l a y ( " g o l d e n i n d e x p o s i t i o n = %h " , i ) ;
// $ d i s p l a y ( " d u t b i t o u t p u t = %h " , mon . mon_grants [ i ] ) ;
// i f t h e t e s t f a i l s , d i s p l a y some h e l p f u l
information
$ d i s p l a y ( " f a i l u r e ␣ a t ␣%g , ␣ i n d e x ␣%h , ␣ e x p e c t e d ␣ w e i g h t
␣=␣%h , ␣ a c t u a l ␣ w e i g h t ␣=␣%h " , $time , i ,
chk_golden_grant_weights [ i ] , mon .
mon_weight_array [ i ] ) ;
$finish ;
end
end
end
sb . d i s p l a y ( ) ;
// $ d i s p l a y ( " cov %e " , $ g e t _ c o v e r a g e ( ) ) ;
end
e n d t a s k : check_output
// u p d a t e g o l d e n t e s t v e c t o r s when d r i v e r i s done d r i v i n g
// i t i s a l w a y s r u n n i g − f o r e v e r
t a s k check : : update_golden_data ( ) ;
forever
begin
@( e_drv_done )
chk_golden_grants = a g t . g o l d e n _ g r a n t s ;
chk_golden_grant_weights = a g t . golden_grant_weights ;
// $ d i s p l a y ( " l o c a l g o l d e n g r a n t = %b " , c h k _ g o l d e n _ g r a n t s ) ;
// s c o r e b o a r d . s v
// s c o r e b o a r d c l a s s
// r e c o r d s t h e number o f h i t s
c l a s s scoreboard ;
i n t s c o r e _ a r r a y [`CHANNELS ] ;
// d e f a u l t c o n s t r u c t i o n
f u n c t i o n new ( ) ;
t h i s . score_array = '{ d e f a u l t : 0 } ;
e n d f u n c t i o n : new
// r e c o r d s c o r e
extern function void record ( i n t reqIndex ) ;
// d i s p l a y s c o r e
extern function void display ;
endclass : scoreboard
//−−−−−−−−−−E x t e r n a l Methods−−−−−−−−−−//
// r e c o r d f u n c t i o n
// u p d a t e t h e r e q u e s t o r c h a n n e l c o un t
function void scoreboard : : record ( i n t reqIndex ) ;
// i n c r e m e n t
score_array [ reqIndex ] = score_array [ reqIndex ] + 1;
endfunction : record
// d i s p l a y c u r r e n t s c o r e
function void scoreboard : : display ( ) ;
f o r ( i n t i = 0 ; i < `CHANNELS; i ++)
begin
$ d i s p l a y ( "CHANNEL␣%d␣ s c o r e ␣=␣%d " , i , s c o r e _ a r r a y [ i ] ) ;
end
endfunction : display
II-53
// a s s e r t i o n . s v
// This module d e f i n e s t h e a s s e r t i o n p r o p e r t i e s
module a s s e r t i o n ( i n t f _ r c c i n t f ) ;
// r e s e t s e q u e n c e
sequence reset_seq ;
( i n t f . r e s e t == 1 ) ##1 ( i n t f . g r a n t == 0 ) ;
endsequence
// r e s e t c o n d i t i o n
property reset_property ;
@( p o s e d g e i n t f . c l k )
( i n t f . r e s e t == 1 ) |−> r e s e t _ s e q ;
endproperty
endmodule
II-54
// i n t e r f a c e . s v
// i n t e r f a c e module
// t h i s c l a s s d e c l a r e s and d e f i n e s i n t e r f a c e b e t w e e n various blocks
b i t [`CHANNELS−1 : 0 ] r e q u e s t ; // r e q u e s t i n p u t t o RRB
l o g i c [`CHANNELS∗`WIDTH − 1 : 0 ] w e i g h t ; // w e i g h t i n p u t t o RRB
// modport f o r d r i v e r c l a s s
modport DRIVER ( i n p u t c l k ,
output r e s e t , r e q u e s t , w e i g h t ) ;
// modport f o r monitor c l a s s
modport MONITOR ( i n p u t c l k , g r a n t ) ;
// r e s e t c o n d i t i o n a s s e r t
property reset_state ;
@( p o s e d g e c l k ) r e s e t |−> g r a n t ==0;
endproperty
endinterface
II-55
// environment . s v
// environment c l a s s
// D e f i n e s a l l modules t o c r e a t e a t e s t environment
c l a s s environment ;
// s i n g l e r e q u e s t o r
requestor req ;
// c l a s s i n s t a n c e s
virtual intf_rrb i n t f ;
g e n e r a t o r gen ;
agent agt ;
d r i v e r drv ;
monitor mon ;
scoreboard scb ;
check chk ;
// e v e n t s
e v e n t e_drv_done ;
e v e n t e_mon_done ;
// d e f a u l t c o n s t r u c t o r
f u n c t i o n new ( v i r t u a l i n t f _ r r b i n t f ) ;
this . intf = intf ;
// i n t i a l i z e t r a n s a c t o r s
gen = new ( r e q ) ;
a g t = new ( gen ) ;
drv = new ( i n t f , agt , e_drv_done ) ;
mon = new ( i n t f , e_drv_done , e_mon_done ) ;
s c b = new ( ) ;
chk = new ( scb , agt , mon , e_mon_done , e_drv_done ) ;
e n d f u n c t i o n : new
e n d c l a s s : environment
II-56
// t o p L e v e l . s v
// t o p l e v e l SV t e s t module f o r RRB
module t o p L e v e l ( ) ;
// t e s t M o d u l e s t e s t M o d u l e s ( ) ;
reg clk = 0;
// c l o c k g e n e r a t o r
initial
f o r e v e r #(`CLOCK_PERIOD/ 2 ) c l k = ~ c l k ;
// i n t e r f a c e i n s t a n c e
intf_rrb i n t f ( clk ) ;
// DUT
RRBTOP #(
.CHANNELS(`CHANNELS) ,
.WIDTH(`WIDTH) ,
. WEIGHTLIMIT(`WEIGHTLIMIT)
)
top (
. r e s e t ( i n t f .RRB. r e s e t ) ,
. c l k ( i n t f .RRB. c l k ) ,
. r e q u e s t ( i n t f .RRB. r e q u e s t ) ,
. w e i g h t ( i n t f .RRB. w e i g h t ) ,
. g r a n t ( i n t f .RRB. g r a n t )
);
// t e s t c a s e
testcase test ( intf ) ;
endmodule
II-57
// t e s t . s v
// t e s t c a s e f o r RoundRobin A r b i t e r
program t e s t c a s e ( i n t f _ r r b i n t f ) ;
genvar i ;
// c o v e r a g e i n f o
c o v e r g r o u p din_cov@ ( p o s e d g e i n t f .RRB. c l k ) ;
r e q u e s t _ c o v e r a g e : c o v e r p o i n t i n t f .RRB. r e q u e s t ;
w e i g h t _ c o v e r a g e : c o v e r p o i n t i g n o r e F u n c t i o n ( i n t f .RRB. w e i g h t ) {
b i n s bin_1 = { 1 ' b1 } ;
}
// o p t i o n . p e r _ i n s t a n c e =1;
endgroup
// Function t o i g n o r e w e i g h t s l e s s than 3
integer n;
f u n c t i o n b i t i g n o r e F u n c t i o n ( l o g i c [`CHANNELS∗`WIDTH − 1 : 0 ]
weight ) ;
// $ d i s p l a y ( " w e i g h t = %h " , w e i g h t ) ;
f o r ( n = 0 ; n < `CHANNELS; n++)
begin
// $ d i s p l a y ( "N = %d " , n ) ;
// $ d i s p l a y ( "w c o v e r a g e t e s t : %h " , ( w e i g h t >> ( n∗`WIDTH) &
`WEIGHTMASK) ) ;
i f ( ( ( weight >>(n∗`WIDTH) ) & `WEIGHTMASK) <= 2 )
begin
// r e t u r n 0 ;
// $ d i s p l a y ( " r e t u r n i n g f a l s e " ) ;
end
end
// $ d i s p l a y ( " r e t u r n i n g t r u e " ) ;
return 1;
endfunction
c o v e r g r o u p dout_cov@ ( p o s e d g e i n t f .RRB. c l k ) ;
g r a n t _ c o v e r a g e : c o v e r p o i n t i n t f .RRB. g r a n t {
II-58
o p t i o n . p e r _ i n s t a n c e =1;
endgroup
// c o v e r a g e h a n d l e
din_cov din_covergroup = new ( ) ;
dout_cov dout_covergroup = new ( ) ;
// env o b j e c t ( i n t e r f a c e )
environment env = new ( i n t f ) ;
initial
begin
$ t i m e f o r m a t ( −9 ,2 , " ns " , 1 6 ) ;
$set_coverage_db_name ( " t e s t C o v " ) ;
// s t a r t c o n v e r a g e c o l l e c t i o n
din_covergroup . s t a r t ( ) ;
dout_covergroup . s t a r t ( ) ;
// r e s e t d u t
env . drv . r e s e t ( ) ;
// Test s t a r t e d
$ d i s p l a y ( "−−−−−Test ␣ s t a r t e d −−−−−" ) ;
// g e n e r a t e new t e s t v e c t o r s
env . a g t . g e n e r a t e _ r e q u e s t s ( ) ;
$ d i s p l a y ( "−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−" ) ;
env . mon . e v e n t _ l o g i c ( ) ;
env . chk . update_golden_data ( ) ;
env . chk . check_output ( ) ;
join_none
fork
// env . chk . c h e c k _ o u t p u t ( ) ;
join_none
@( p o s e d g e i n t f . DRIVER . c l k ) ;
// d r i v e t h e t e s t v e c t o r , w a i t f o r sum ( r e q u e s t ∗ w e i g h t ) , and
generate again
f o r ( i n t i = 0 ; i < `NUM_ITERATIONS; i ++)
begin
$ d i s p l a y ( " i t e r a t i o n ␣=␣%d " , i ) ;
fork
// send t h e t e s t v e c t o r s t o DUT
env . drv . drive_new_data ( ) ;
join
// g e n e r a t e new t e s t v e c t o r s ( r e q u e s t s )
env . a g t . g e n e r a t e _ r e q u e s t s ( ) ;
$ d i s p l a y ( "−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−" ) ;
// $ d i s p l a y ("% g j o i n " , $time ) ;
end
@( p o s e d g e intf . DRIVER . c l k ) ;
@( p o s e d g e intf . DRIVER . c l k ) ;
@( p o s e d g e intf . DRIVER . c l k ) ;
@( p o s e d g e intf . DRIVER . c l k ) ;
@( p o s e d g e intf . DRIVER . c l k ) ;
@( p o s e d g e intf . DRIVER . c l k ) ;
end
final
begin
// d i s p l a y s c o r e b o a r d r e s u l t s
env . s c b . d i s p l a y ( ) ;
// d i s p l a y c o v e r a g e r e s u l t s
$ d i s p l a y ( " Input ␣ r e q u e s t ␣ c o v e r a g e ␣=␣%e " , din_covergroup .
II-60
request_coverage . get_coverage ( ) ) ;
$ d i s p l a y ( " Input ␣ w e i g h t ␣ c o v e r a g e ␣=␣%e " , din_covergroup .
weight_coverage . get_coverage ( ) ) ;
$ d i s p l a y ( " Output ␣ g r a n t ␣ c o v e r a g e ␣=␣%e " , dout_covergroup .
grant_coverage . get_coverage ( ) ) ;
end
endprogram : t e s t c a s e