-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathinstr_package.sv
261 lines (221 loc) · 9.63 KB
/
instr_package.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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
`default_nettype none
package instr_package;
// Enumerate all the opcodes
typedef enum bit [3:0] {ADD,iSUB,iAND,iOR,iXOR,iNOT,MOV,NOP,LD,ST,LDI, NU, BRZ,BRN,BRO,BRA} opcode_t;
localparam num_tests = 1000;
typedef bit [7:0] u_byte_t; // Unsigned byte
function void print_time_string(input string my_string);
$display("%0t: %0s", $time, my_string);
endfunction // print_time_string
class Instruction;
rand opcode_t opcode;
rand bit [2:0] target,first,second; // target, R1 and R2 of the opcode
rand var signed [11:0] branch_offset;
rand var signed [8:0] immediate; // Data returned by the 3rd memory access of a read
static bit [7:0] count = 0; // Count to keep track of the memory address
static string opcode_str; // To be able to view the instruction in the viewer.
bit [7:0] address; // Starting memory address for the Instruction
bit signed [11:0] address_sign_extended = 12'($signed(address));
constraint no_NU {(opcode != NU);}
constraint no_LDI_to_PC { !((opcode==LDI) && (target==7)); }
// Add more constraints here
constraint no_branch_to_outrange{
!((opcode==BRZ) && (((branch_offset-address_sign_extended)<0) || ((address_sign_extended+branch_offset)>255)));
!((opcode==BRN) && (((branch_offset-address_sign_extended)<0) || ((address_sign_extended+branch_offset)>255)));
!((opcode==BRO) && (((branch_offset-address_sign_extended)<0) || ((address_sign_extended+branch_offset)>255)));
!((opcode==BRA) && (((branch_offset-address_sign_extended)<0) || ((address_sign_extended+branch_offset)>255)));
}
constraint no_mov_to_r7{
!((opcode<=MOV) && (target==7));
}
constraint no_LD_to_r7{
!((opcode==LD) && (target==7));
}
/*
// ==============================constraints====================================
// no NU operation generated
constraint no_NU {(opcode != NU);}
// no target Register = reg7 (counter)
constraint no_ADD_to_PC { !((opcode==ADD) && (target==7)); }
constraint no_SUB_to_PC { !((opcode==iSUB) && (target==7)); }
constraint no_AND_to_PC { !((opcode==iAND) && (target==7)); }
constraint no_OR_to_PC { !((opcode==iOR) && (target==7)); }
constraint no_XOR_to_PC { !((opcode==iXOR) && (target==7)); }
constraint no_NOT_to_PC { !((opcode==iNOT) && (target==7)); }
constraint no_MOV_to_PC { !((opcode==MOV) && (target==7)); }
// no need for constraint on NOP
constraint no_LD_to_PC { !((opcode==LD) && (target==7)); }
constraint no_ST_to_PC { !((opcode==ST) && (second==7)); } // store address is second
constraint no_LDI_to_PC { !((opcode==LDI) && (target==7)); }
// no need for constraint for NU, BRZ, BRN, BRO, BRA
// address is always within range
constraint BRZ_PC_range { !((opcode==BRZ) && ((address + branch_offset) inside {[0:255]})); }
constraint BRN_PC_range { !((opcode==BRN) && ((address + branch_offset) inside {[0:255]})); }
constraint BRO_PC_range { !((opcode==BRO) && ((address + branch_offset) inside {[0:255]})); }
constraint BRA_PC_range { !((opcode==BRA) && ((address + branch_offset) inside {[0:255]})); }
*/
function void print_instruction;
// Print out the assembly instructions
if (opcode<iNOT)
$display("%0h: %s R%0h,R%0h,R%0h", address, opcode,target,first,second);
else if ((opcode == iNOT) || (opcode == MOV))
$display("%0h: %s R%0h,R%0h", address, opcode, target, first);
else if (opcode == LD)
$display("%0h: %s R%0h,<R%0h>", address, opcode, target, first);
else if (opcode == ST)
$display("%0h: %s <R%0h>,R%0h", address, opcode, first, second);
else if (opcode == LDI)
$display("%0h: %s R%0h, #%0h", address,opcode, target, immediate);
else
$display("%0h: %s #%0h", address, opcode, branch_offset);
endfunction // print_instruction
/*
function string Assemble();
string ret_value;
if (opcode<iNOT)
$sformat("%0h: %s R%0h,R%0h,R%0h", address, opcode,target,first,second);
else if ((opcode == iNOT) || (opcode == MOV))
$sformat("%0h: %s R%0h,R%0h", address, opcode, target, first);
else if (opcode == LD)
$sformat("%0h: %s R%0h,<R%0h>", address, opcode, target, first);
else if (opcode == ST)
$sformat("%0h: %s <R%0h>,R%0h", address, opcode, first, second);
else if (opcode == LDI)
$sformat("%0h: %s R%0h, #%0h", address,opcode, target, immediate);
else
$sformat("%0h: %s #%0h", address, opcode, branch_offset);
return ret_value;
endfunction
*/
function int Compile();
bit [15:0] ret_value;
ret_value=16'h7000; // NOP
if (opcode<iNOT) begin
ret_value[15:12]=opcode;
ret_value[11:9]=target;
ret_value[8:6]=first;
ret_value[5:3]=second;
end
else if ((opcode == iNOT) || (opcode == MOV)) begin
ret_value[15:12]=opcode;
ret_value[11:9]=target;
ret_value[8:6]=first;
end
else if (opcode == LD) begin
ret_value[15:12]=opcode;
ret_value[11:9]=target;
ret_value[8:6]=first;
end
else if (opcode == ST) begin
ret_value[15:12]=opcode;
ret_value[8:6]=first;
ret_value[5:3]=second;
end
else if (opcode == LDI) begin
ret_value[15:12]=opcode;
ret_value[11:9]=target;
ret_value[8:0]=immediate;
end
else begin
ret_value[15:12]=opcode;
ret_value[11:0]=branch_offset;
end
return ret_value;
endfunction
function new();
address = count++;
endfunction // new
function void post_randomize;
// Add directed tests here by overwriting instructions on selected target addresses
if (address==255) begin
opcode=BRA;
branch_offset=12'b0;
end
opcode_str = opcode.name;
endfunction
endclass
// Typedef a mailbox of type Instruction
typedef mailbox #(Instruction) instr_mbox;
// Handle to an instruction and old instruction
Instruction instr;
Instruction old_instr;
covergroup CovOpcode;
option.auto_bin_max = 256; // Don't restrict number of auto bins
type_option.merge_instances = 1; // to show bins
//All opcodes have been executed, except NU.
all_opcodes_executed: coverpoint instr.opcode{
bins opcodes[] = {ADD,iSUB,iAND,iOR,iXOR,iNOT,MOV,NOP,LD,ST,LDI, BRZ,BRN,BRO,BRA};}
// The source for every opcode must have been R0..R7
// First create a covergroup with opcodes that have a three fields
opcodes_with_three: coverpoint instr.opcode{
bins opcodes[] = {ADD,iSUB,iAND,iOR,iXOR};}
first: coverpoint instr.first;
second: coverpoint instr.second;
target: coverpoint instr.target;
all_opcodes_executed_x_target: cross opcodes_with_three, target;
/*
// The destination for every opcode must have been R0..R7
// first create a coverpoint with opcodes that have a dest field
opcodes_with_target: coverpoint instr.opcode{
bins opcodes[] = {ADD,iSUB,iAND,iOR,iXOR,iNOT,MOV,LD,LDI};}
dest: coverpoint instr.dest;
all_opcodes_executed_x_dest: cross opcodes_with_dest, dest;
*/
// Every instruction has been preceded and followed by every other instruction.
all_opcodes_executed_old: coverpoint old_instr.opcode{
bins old_opcodes[] = {ADD,iSUB,iAND,iOR,iXOR,iNOT,MOV,NOP,LD,ST,LDI, BRZ,BRN,BRO,BRA};}
all_permutations_opcodes: cross all_opcodes_executed_old, all_opcodes_executed;
// For opcodes that have both a three fields, all permutations
// of the three fields have been executed.
// First create a coverpoint with opcodes that have three fields
opcodes_with_three_fields: coverpoint instr.opcode{
bins opcodes[] = {ADD,iSUB,iAND,iOR,iXOR};}
all_opcodes_executed_x_three_fields: cross opcodes_with_three_fields, target, first, second;
opcode_with_two_fields: coverpoint instr.opcode{
bins opcodes[] = {iNOT,MOV};}
branch_instructions: coverpoint instr.opcode{
bins opcodes[] = { BRZ,BRN,BRO,BRA};}
load_instructions: coverpoint instr.opcode{
bins opcodes[] = { LD,LDI };}
store_instructions: coverpoint instr.opcode{
bins opcodes[] = { ST };}
/*
// All memory locations have been written.
// First create a coverpoint with opcodes WR only
// Then a coverpoint of memory_location
opcodes_wr: coverpoint instr.opcode{
bins opcodes[] = {WR};}
memory_loc: coverpoint instr.memory_location;
all_mem_written: cross opcodes_wr, memory_loc;
// All memory locations have been read by a RD instruction.
opcodes_rd: coverpoint instr.opcode{
bins opcodes[] = {RD};}
all_mem_read: cross opcodes_rd, memory_loc;
*/
endgroup // CovOpcode
// Abstract driver callback class.
virtual class Driver_cbs;
pure virtual task post_tx(Instruction cb_instr);
endclass // Driver_cbs
// Callback to collect coverage
class Driver_cbs_cover extends Driver_cbs;
// Handle to covergroup
CovOpcode cov;
function new();
this.cov = new();
old_instr = new();
endfunction // new
virtual task post_tx(Instruction cb_instr);
// Copy instruction passed to task to instr for collecting coverage.
instr = cb_instr;
cov.sample();
old_instr = instr; // copy to old instruction
if ((cov.all_opcodes_executed.get_coverage() == 100) &&
(cov.all_opcodes_executed_x_three_fields.get_coverage() == 100) &&
(cov.all_permutations_opcodes.get_coverage() == 100)) begin
print_time_string("All coverage requirements complete");
$finish;
end
endtask // pre_tx
endclass // Driver_cbs
endpackage