-
Notifications
You must be signed in to change notification settings - Fork 0
/
dist_chooser.sv
executable file
·125 lines (110 loc) · 4.39 KB
/
dist_chooser.sv
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
// ***********************************************************************
// File: dist_chooser.sv
// Author: bhunter
/* About:
Copyright (C) 2015 Brian P. Hunter
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*************************************************************************/
//****************************************************************************************
// class: dist_chooser_c
// Create an instance of this type, parameterized to the objects to be
// pulled out. Call add_item() for each of the different values to be
// pulled, along with the distribution weight. Once all weights have
// been set, call configure.
// Thereafter, when a new value is required, call get_next(), and a
// value of the parameter type will be chosen randomly.
class dist_chooser_c#(type TYPE=int) extends uvm_object;
`uvm_object_utils(cmn_pkg::dist_chooser_c#(TYPE))
//----------------------------------------------------------------------------------------
// Group: Fields
// var: weights
// All weights must be an integer, key is the TYPE
int unsigned weights[TYPE];
// var: values
// The list of TYPE from which to choose
TYPE values[$];
// var: all_weights
// All weights, as a list
int unsigned all_weights[$];
//----------------------------------------------------------------------------------------
// Group: Methods
// func: new
function new(string name="dist_chooser");
super.new(name);
endfunction : new
////////////////////////////////////////////
// func: add_item
// Merely adds to the weights variable
virtual function void add_item(int _weight,
TYPE _typ);
weights[_typ] = _weight;
all_weights.push_back(_weight);
endfunction : add_item
////////////////////////////////////////////
// func: configure
// Create the values list from which to choose
virtual function void configure();
int unsigned gcf = find_gcf_list(all_weights);
values.delete();
foreach(weights[idx]) begin
int unsigned rnum = weights[idx] / gcf;
repeat(rnum)
values.push_back(idx);
end
endfunction : configure
////////////////////////////////////////////
// func: find_gcf_list
// Find the gcf of a list of values. Do so via recursion, noting that
// gcf(a, b, c) = gcf(a, gcf(b, c))
// NOTE: This could be moved to a math_pkg
virtual function int unsigned find_gcf_list(ref int unsigned _list[$]);
case(_list.size())
0 : return 1;
1 : return _list[0];
2 : return find_gcf(_list[0], _list[1]);
default: begin
int unsigned rest_of_list[$] = _list[1:$];
return find_gcf(_list[0], find_gcf_list(rest_of_list));
end
endcase
endfunction : find_gcf_list
////////////////////////////////////////////
// func: find_gcf
// Find the gcf between two numbers
// NOTE: This could be moved to a math_pkg
virtual function int unsigned find_gcf(int unsigned _alpha,
int unsigned _beta);
int unsigned div = _alpha;
int unsigned rem = _beta;
int unsigned prev_rem;
while(rem != 0) begin
prev_rem = rem;
rem = div % rem;
div = prev_rem;
end
return prev_rem;
endfunction : find_gcf
////////////////////////////////////////////
// func: is_configured
// Returns true if the values queue has at least something in it
virtual function bit is_configured();
return(values.size() > 0);
endfunction : is_configured
////////////////////////////////////////////
// func: get_next
// Return a random choice based on the weights.
virtual function TYPE get_next();
int unsigned rand_idx;
assert(is_configured()) else
`cmn_fatal(("There is nothing to choose from."))
rand_idx = $urandom_range(values.size()-1);
return(values[rand_idx]);
endfunction : get_next
endclass : dist_chooser_c