OpenCores
URL https://opencores.org/ocsvn/uart2bus_testbench/uart2bus_testbench/trunk

Subversion Repositories uart2bus_testbench

[/] [uart2bus_testbench/] [trunk/] [tb/] [uvm_src/] [reg/] [uvm_reg.svh] - Blame information for rev 16

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 16 HanySalah
//
2
// -------------------------------------------------------------
3
//    Copyright 2004-2009 Synopsys, Inc.
4
//    Copyright 2010-2011 Mentor Graphics Corporation
5
//    Copyright 2010-2011 Cadence Design Systems, Inc.
6
//    All Rights Reserved Worldwide
7
//
8
//    Licensed under the Apache License, Version 2.0 (the
9
//    "License"); you may not use this file except in
10
//    compliance with the License.  You may obtain a copy of
11
//    the License at
12
//
13
//        http://www.apache.org/licenses/LICENSE-2.0
14
//
15
//    Unless required by applicable law or agreed to in
16
//    writing, software distributed under the License is
17
//    distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
18
//    CONDITIONS OF ANY KIND, either express or implied.  See
19
//    the License for the specific language governing
20
//    permissions and limitations under the License.
21
// -------------------------------------------------------------
22
//
23
 
24
typedef class uvm_reg_cbs;
25
typedef class uvm_reg_frontdoor;
26
 
27
//-----------------------------------------------------------------
28
// CLASS: uvm_reg
29
// Register abstraction base class
30
//
31
// A register represents a set of fields that are accessible
32
// as a single entity.
33
//
34
// A register may be mapped to one or more address maps,
35
// each with different access rights and policy.
36
//-----------------------------------------------------------------
37
virtual class uvm_reg extends uvm_object;
38
 
39
   local bit               m_locked;
40
   local uvm_reg_block     m_parent;
41
   local uvm_reg_file      m_regfile_parent;
42
   local int unsigned      m_n_bits;
43
   local int unsigned      m_n_used_bits;
44
   protected bit           m_maps[uvm_reg_map];
45
   protected uvm_reg_field m_fields[$];   // Fields in LSB to MSB order
46
   local int               m_has_cover;
47
   local int               m_cover_on;
48
   local semaphore         m_atomic;
49
   local process           m_process;
50
   local string            m_fname;
51
   local int               m_lineno;
52
   local bit               m_read_in_progress;
53
   local bit               m_write_in_progress;
54
   protected bit           m_update_in_progress;
55
   /*local*/ bit           m_is_busy;
56
   /*local*/ bit           m_is_locked_by_field;
57
   local uvm_reg_backdoor  m_backdoor;
58
 
59
   local static int unsigned m_max_size;
60
 
61
   local uvm_object_string_pool
62
       #(uvm_queue #(uvm_hdl_path_concat)) m_hdl_paths_pool;
63
 
64
   //----------------------
65
   // Group: Initialization
66
   //----------------------
67
 
68
   // Function: new
69
   //
70
   // Create a new instance and type-specific configuration
71
   //
72
   // Creates an instance of a register abstraction class with the specified
73
   // name.
74
   //
75
   // ~n_bits~ specifies the total number of bits in the register.
76
   // Not all bits need to be implemented.
77
   // This value is usually a multiple of 8.
78
   //
79
   // ~has_coverage~ specifies which functional coverage models are present in
80
   // the extension of the register abstraction class.
81
   // Multiple functional coverage models may be specified by adding their
82
   // symbolic names, as defined by the  type.
83
   //
84
   extern function new (string name="",
85
                        int unsigned n_bits,
86
                        int has_coverage);
87
 
88
 
89
   // Function: configure
90
   //
91
   // Instance-specific configuration
92
   //
93
   // Specify the parent block of this register.
94
   // May also set a parent register file for this register,
95
   //
96
   // If the register is implemented in a single HDL variable,
97
   // its name is specified as the ~hdl_path~.
98
   // Otherwise, if the register is implemented as a concatenation
99
   // of variables (usually one per field), then the HDL path
100
   // must be specified using the  or
101
   //  method.
102
   //
103
   extern function void configure (uvm_reg_block blk_parent,
104
                                   uvm_reg_file regfile_parent = null,
105
                                   string hdl_path = "");
106
 
107
 
108
   // Function: set_offset
109
   //
110
   // Modify the offset of the register
111
   //
112
   // The offset of a register within an address map is set using the
113
   //  method.
114
   // This method is used to modify that offset dynamically.
115
   //
116
   // Modifying the offset of a register will make the register model
117
   // diverge from the specification that was used to create it.
118
   //
119
   extern virtual function void set_offset (uvm_reg_map    map,
120
                                            uvm_reg_addr_t offset,
121
                                            bit            unmapped = 0);
122
 
123
   /*local*/ extern virtual function void set_parent (uvm_reg_block blk_parent,
124
                                                      uvm_reg_file regfile_parent);
125
   /*local*/ extern virtual function void add_field  (uvm_reg_field field);
126
   /*local*/ extern virtual function void add_map    (uvm_reg_map map);
127
 
128
   /*local*/ extern function void   Xlock_modelX;
129
 
130
 
131
   //---------------------
132
   // Group: Introspection
133
   //---------------------
134
 
135
   // Function: get_name
136
   //
137
   // Get the simple name
138
   //
139
   // Return the simple object name of this register.
140
   //
141
 
142
   // Function: get_full_name
143
   //
144
   // Get the hierarchical name
145
   //
146
   // Return the hierarchal name of this register.
147
   // The base of the hierarchical name is the root block.
148
   //
149
   extern virtual function string get_full_name();
150
 
151
 
152
   // Function: get_parent
153
   //
154
   // Get the parent block
155
   //
156
   extern virtual function uvm_reg_block get_parent ();
157
   extern virtual function uvm_reg_block get_block  ();
158
 
159
 
160
   // Function: get_regfile
161
   //
162
   // Get the parent register file
163
   //
164
   // Returns ~null~ if this register is instantiated in a block.
165
   //
166
   extern virtual function uvm_reg_file get_regfile ();
167
 
168
 
169
   // Function: get_n_maps
170
   //
171
   // Returns the number of address maps this register is mapped in
172
   //
173
   extern virtual function int get_n_maps ();
174
 
175
 
176
   // Function: is_in_map
177
   //
178
   // Returns 1 if this register is in the specified address ~map~
179
   //
180
   extern function bit is_in_map (uvm_reg_map map);
181
 
182
 
183
   // Function: get_maps
184
   //
185
   // Returns all of the address ~maps~ where this register is mapped
186
   //
187
   extern virtual function void get_maps (ref uvm_reg_map maps[$]);
188
 
189
 
190
   /*local*/ extern virtual function uvm_reg_map get_local_map   (uvm_reg_map map,
191
                                                                  string caller = "");
192
   /*local*/ extern virtual function uvm_reg_map get_default_map (string caller = "");
193
 
194
 
195
   // Function: get_rights
196
   //
197
   // Returns the accessibility ("RW, "RO", or "WO") of this register in the given ~map~.
198
   //
199
   // If no address map is specified and the register is mapped in only one
200
   // address map, that address map is used. If the register is mapped
201
   // in more than one address map, the default address map of the
202
   // parent block is used.
203
   //
204
   // Whether a register field can be read or written depends on both the field's
205
   // configured access policy (refer to ) and the register's
206
   // accessibility rights in the map being used to access the field.
207
   //
208
   // If an address map is specified and
209
   // the register is not mapped in the specified
210
   // address map, an error message is issued
211
   // and "RW" is returned.
212
   //
213
   extern virtual function string get_rights (uvm_reg_map map = null);
214
 
215
 
216
   // Function: get_n_bits
217
   //
218
   // Returns the width, in bits, of this register.
219
   //
220
   extern virtual function int unsigned get_n_bits ();
221
 
222
 
223
   // Function: get_n_bytes
224
   //
225
   // Returns the width, in bytes, of this register. Rounds up to
226
   // next whole byte if register is not a multiple of 8.
227
   //
228
   extern virtual function int unsigned get_n_bytes();
229
 
230
 
231
   // Function: get_max_size
232
   //
233
   // Returns the maximum width, in bits, of all registers.
234
   //
235
   extern static function int unsigned get_max_size();
236
 
237
 
238
   // Function: get_fields
239
   //
240
   // Return the fields in this register
241
   //
242
   // Fills the specified array with the abstraction class
243
   // for all of the fields contained in this register.
244
   // Fields are ordered from least-significant position to most-significant
245
   // position within the register.
246
   //
247
   extern virtual function void get_fields (ref uvm_reg_field fields[$]);
248
 
249
 
250
   // Function: get_field_by_name
251
   //
252
   // Return the named field in this register
253
   //
254
   // Finds a field with the specified name in this register
255
   // and returns its abstraction class.
256
   // If no fields are found, returns ~null~.
257
   //
258
   extern virtual function uvm_reg_field get_field_by_name(string name);
259
 
260
 
261
   /*local*/ extern function string Xget_fields_accessX(uvm_reg_map map);
262
 
263
 
264
   // Function: get_offset
265
   //
266
   // Returns the offset of this register
267
   //
268
   // Returns the offset of this register in an address ~map~.
269
   //
270
   // If no address map is specified and the register is mapped in only one
271
   // address map, that address map is used. If the register is mapped
272
   // in more than one address map, the default address map of the
273
   // parent block is used.
274
   //
275
   // If an address map is specified and
276
   // the register is not mapped in the specified
277
   // address map, an error message is issued.
278
   //
279
   extern virtual function uvm_reg_addr_t get_offset (uvm_reg_map map = null);
280
 
281
 
282
   // Function: get_address
283
   //
284
   // Returns the base external physical address of this register
285
   //
286
   // Returns the base external physical address of this register
287
   // if accessed through the specified address ~map~.
288
   //
289
   // If no address map is specified and the register is mapped in only one
290
   // address map, that address map is used. If the register is mapped
291
   // in more than one address map, the default address map of the
292
   // parent block is used.
293
   //
294
   // If an address map is specified and
295
   // the register is not mapped in the specified
296
   // address map, an error message is issued.
297
   //
298
   extern virtual function uvm_reg_addr_t get_address (uvm_reg_map map = null);
299
 
300
 
301
   // Function: get_addresses
302
   //
303
   // Identifies the external physical address(es) of this register
304
   //
305
   // Computes all of the external physical addresses that must be accessed
306
   // to completely read or write this register. The addressed are specified in
307
   // little endian order.
308
   // Returns the number of bytes transferred on each access.
309
   //
310
   // If no address map is specified and the register is mapped in only one
311
   // address map, that address map is used. If the register is mapped
312
   // in more than one address map, the default address map of the
313
   // parent block is used.
314
   //
315
   // If an address map is specified and
316
   // the register is not mapped in the specified
317
   // address map, an error message is issued.
318
   //
319
   extern virtual function int get_addresses (uvm_reg_map map = null,
320
                                              ref uvm_reg_addr_t addr[]);
321
 
322
 
323
 
324
   //--------------
325
   // Group: Access
326
   //--------------
327
 
328
 
329
   // Function: set
330
   //
331
   // Set the desired value for this register
332
   //
333
   // Sets the desired value of the fields in the register
334
   // to the specified value. Does not actually
335
   // set the value of the register in the design,
336
   // only the desired value in its corresponding
337
   // abstraction class in the RegModel model.
338
   // Use the  method to update the
339
   // actual register with the mirrored value or
340
   // the  method to set
341
   // the actual register and its mirrored value.
342
   //
343
   // Unless this method is used, the desired value is equal to
344
   // the mirrored value.
345
   //
346
   // Refer  for more details on the effect
347
   // of setting mirror values on fields with different
348
   // access policies.
349
   //
350
   // To modify the mirrored field values to a specific value,
351
   // and thus use the mirrored as a scoreboard for the register values
352
   // in the DUT, use the  method.
353
   //
354
   extern virtual function void set (uvm_reg_data_t  value,
355
                                     string          fname = "",
356
                                     int             lineno = 0);
357
 
358
 
359
   // Function: get
360
   //
361
   // Return the desired value of the fields in the register.
362
   //
363
   // Does not actually read the value
364
   // of the register in the design, only the desired value
365
   // in the abstraction class. Unless set to a different value
366
   // using the , the desired value
367
   // and the mirrored value are identical.
368
   //
369
   // Use the  or 
370
   // method to get the actual register value.
371
   //
372
   // If the register contains write-only fields, the desired/mirrored
373
   // value for those fields are the value last written and assumed
374
   // to reside in the bits implementing these fields.
375
   // Although a physical read operation would something different
376
   // for these fields,
377
   // the returned value is the actual content.
378
   //
379
   extern virtual function uvm_reg_data_t  get(string  fname = "",
380
                                               int     lineno = 0);
381
 
382
   // Function: get_mirrored_value
383
   //
384
   // Return the mirrored value of the fields in the register.
385
   //
386
   // Does not actually read the value
387
   // of the register in the design
388
   //
389
   // If the register contains write-only fields, the desired/mirrored
390
   // value for those fields are the value last written and assumed
391
   // to reside in the bits implementing these fields.
392
   // Although a physical read operation would something different
393
   // for these fields, the returned value is the actual content.
394
   //
395
   extern virtual function uvm_reg_data_t  get_mirrored_value(string  fname = "",
396
                                               int     lineno = 0);
397
 
398
 
399
   // Function: needs_update
400
   //
401
   // Returns 1 if any of the fields need updating
402
   //
403
   // See  for details.
404
   // Use the  to actually update the DUT register.
405
   //
406
   extern virtual function bit needs_update();
407
 
408
 
409
   // Function: reset
410
   //
411
   // Reset the desired/mirrored value for this register.
412
   //
413
   // Sets the desired and mirror value of the fields in this register
414
   // to the reset value for the specified reset ~kind~.
415
   // See  for more details.
416
   //
417
   // Also resets the semaphore that prevents concurrent access
418
   // to the register.
419
   // This semaphore must be explicitly reset if a thread accessing
420
   // this register array was killed in before the access
421
   // was completed
422
   //
423
   extern virtual function void reset(string kind = "HARD");
424
 
425
 
426
   // Function: get_reset
427
   //
428
   // Get the specified reset value for this register
429
   //
430
   // Return the reset value for this register
431
   // for the specified reset ~kind~.
432
   //
433
   extern virtual function uvm_reg_data_t
434
                             get_reset(string kind = "HARD");
435
 
436
 
437
   // Function: has_reset
438
   //
439
   // Check if any field in the register has a reset value specified
440
   // for the specified reset ~kind~.
441
   // If ~delete~ is TRUE, removes the reset value, if any.
442
   //
443
   extern virtual function bit has_reset(string kind = "HARD",
444
                                         bit    delete = 0);
445
 
446
 
447
   // Function: set_reset
448
   //
449
   // Specify or modify the reset value for this register
450
   //
451
   // Specify or modify the reset value for all the fields in the register
452
   // corresponding to the cause specified by ~kind~.
453
   //
454
   extern virtual function void
455
                       set_reset(uvm_reg_data_t value,
456
                                 string         kind = "HARD");
457
 
458
 
459
   // Task: write
460
   //
461
   // Write the specified value in this register
462
   //
463
   // Write ~value~ in the DUT register that corresponds to this
464
   // abstraction class instance using the specified access
465
   // ~path~.
466
   // If the register is mapped in more than one address map,
467
   // an address ~map~ must be
468
   // specified if a physical access is used (front-door access).
469
   // If a back-door access path is used, the effect of writing
470
   // the register through a physical access is mimicked. For
471
   // example, read-only bits in the registers will not be written.
472
   //
473
   // The mirrored value will be updated using the 
474
   // method.
475
   //
476
   extern virtual task write(output uvm_status_e      status,
477
                             input  uvm_reg_data_t    value,
478
                             input  uvm_path_e        path = UVM_DEFAULT_PATH,
479
                             input  uvm_reg_map       map = null,
480
                             input  uvm_sequence_base parent = null,
481
                             input  int               prior = -1,
482
                             input  uvm_object        extension = null,
483
                             input  string            fname = "",
484
                             input  int               lineno = 0);
485
 
486
 
487
   // Task: read
488
   //
489
   // Read the current value from this register
490
   //
491
   // Read and return ~value~ from the DUT register that corresponds to this
492
   // abstraction class instance using the specified access
493
   // ~path~.
494
   // If the register is mapped in more than one address map,
495
   // an address ~map~ must be
496
   // specified if a physical access is used (front-door access).
497
   // If a back-door access path is used, the effect of reading
498
   // the register through a physical access is mimicked. For
499
   // example, clear-on-read bits in the registers will be set to zero.
500
   //
501
   // The mirrored value will be updated using the 
502
   // method.
503
   //
504
   extern virtual task read(output uvm_status_e      status,
505
                            output uvm_reg_data_t    value,
506
                            input  uvm_path_e        path = UVM_DEFAULT_PATH,
507
                            input  uvm_reg_map       map = null,
508
                            input  uvm_sequence_base parent = null,
509
                            input  int               prior = -1,
510
                            input  uvm_object        extension = null,
511
                            input  string            fname = "",
512
                            input  int               lineno = 0);
513
 
514
 
515
   // Task: poke
516
   //
517
   // Deposit the specified value in this register
518
   //
519
   // Deposit the value in the DUT register corresponding to this
520
   // abstraction class instance, as-is, using a back-door access.
521
   //
522
   // Uses the HDL path for the design abstraction specified by ~kind~.
523
   //
524
   // The mirrored value will be updated using the 
525
   // method.
526
   //
527
   extern virtual task poke(output uvm_status_e      status,
528
                            input  uvm_reg_data_t    value,
529
                            input  string            kind = "",
530
                            input  uvm_sequence_base parent = null,
531
                            input  uvm_object        extension = null,
532
                            input  string            fname = "",
533
                            input  int               lineno = 0);
534
 
535
 
536
   // Task: peek
537
   //
538
   // Read the current value from this register
539
   //
540
   // Sample the value in the DUT register corresponding to this
541
   // abstraction class instance using a back-door access.
542
   // The register value is sampled, not modified.
543
   //
544
   // Uses the HDL path for the design abstraction specified by ~kind~.
545
   //
546
   // The mirrored value will be updated using the 
547
   // method.
548
   //
549
   extern virtual task peek(output uvm_status_e      status,
550
                            output uvm_reg_data_t    value,
551
                            input  string            kind = "",
552
                            input  uvm_sequence_base parent = null,
553
                            input  uvm_object        extension = null,
554
                            input  string            fname = "",
555
                            input  int               lineno = 0);
556
 
557
 
558
   // Task: update
559
   //
560
   // Updates the content of the register in the design to match the
561
   // desired value
562
   //
563
   // This method performs the reverse
564
   // operation of .
565
   // Write this register if the DUT register is out-of-date with the
566
   // desired/mirrored value in the abstraction class, as determined by
567
   // the  method.
568
   //
569
   // The update can be performed using the using the physical interfaces
570
   // (frontdoor) or  (backdoor) access.
571
   // If the register is mapped in multiple address maps and physical access
572
   // is used (front-door), an address ~map~ must be specified.
573
   //
574
   extern virtual task update(output uvm_status_e      status,
575
                              input  uvm_path_e        path = UVM_DEFAULT_PATH,
576
                              input  uvm_reg_map       map = null,
577
                              input  uvm_sequence_base parent = null,
578
                              input  int               prior = -1,
579
                              input  uvm_object        extension = null,
580
                              input  string            fname = "",
581
                              input  int               lineno = 0);
582
 
583
 
584
   // Task: mirror
585
   //
586
   // Read the register and update/check its mirror value
587
   //
588
   // Read the register and optionally compared the readback value
589
   // with the current mirrored value if ~check~ is .
590
   // The mirrored value will be updated using the 
591
   // method based on the readback value.
592
   //
593
   // The mirroring can be performed using the physical interfaces (frontdoor)
594
   // or  (backdoor).
595
   //
596
   // If ~check~ is specified as UVM_CHECK,
597
   // an error message is issued if the current mirrored value
598
   // does not match the readback value. Any field whose check has been
599
   // disabled with  will not be considered
600
   // in the comparison.
601
   //
602
   // If the register is mapped in multiple address maps and physical
603
   // access is used (front-door access), an address ~map~ must be specified.
604
   // If the register contains
605
   // write-only fields, their content is mirrored and optionally
606
   // checked only if a UVM_BACKDOOR
607
   // access path is used to read the register.
608
   //
609
   extern virtual task mirror(output uvm_status_e      status,
610
                              input uvm_check_e        check  = UVM_NO_CHECK,
611
                              input uvm_path_e         path = UVM_DEFAULT_PATH,
612
                              input uvm_reg_map        map = null,
613
                              input uvm_sequence_base  parent = null,
614
                              input int                prior = -1,
615
                              input  uvm_object        extension = null,
616
                              input string             fname = "",
617
                              input int                lineno = 0);
618
 
619
 
620
   // Function: predict
621
   //
622
   // Update the mirrored and desired value for this register.
623
   //
624
   // Predict the mirror (and desired) value of the fields in the register
625
   // based on the specified observed ~value~ on a specified address ~map~,
626
   // or based on a calculated value.
627
   // See  for more details.
628
   //
629
   // Returns TRUE if the prediction was successful for each field in the
630
   // register.
631
   //
632
   extern virtual function bit predict (uvm_reg_data_t    value,
633
                                        uvm_reg_byte_en_t be = -1,
634
                                        uvm_predict_e     kind = UVM_PREDICT_DIRECT,
635
                                        uvm_path_e        path = UVM_FRONTDOOR,
636
                                        uvm_reg_map       map = null,
637
                                        string            fname = "",
638
                                        int               lineno = 0);
639
 
640
 
641
   // Function: is_busy
642
   //
643
   // Returns 1 if register is currently being read or written.
644
   //
645
   extern function bit is_busy();
646
 
647
 
648
 
649
   /*local*/ extern function void Xset_busyX(bit busy);
650
 
651
   /*local*/ extern task XreadX (output uvm_status_e      status,
652
                                 output uvm_reg_data_t    value,
653
                                 input  uvm_path_e        path,
654
                                 input  uvm_reg_map       map,
655
                                 input  uvm_sequence_base parent = null,
656
                                 input  int               prior = -1,
657
                                 input  uvm_object        extension = null,
658
                                 input  string            fname = "",
659
                                 input  int               lineno = 0);
660
 
661
   /*local*/ extern task XatomicX(bit on);
662
 
663
   /*local*/ extern virtual function bit Xcheck_accessX
664
                                (input uvm_reg_item rw,
665
                                 output uvm_reg_map_info map_info,
666
                                 input string caller);
667
 
668
   /*local*/ extern function bit Xis_locked_by_fieldX();
669
 
670
 
671
   extern virtual function bit do_check(uvm_reg_data_t expected,
672
                                        uvm_reg_data_t actual,
673
                                        uvm_reg_map    map);
674
 
675
   extern virtual task do_write(uvm_reg_item rw);
676
 
677
   extern virtual task do_read(uvm_reg_item rw);
678
 
679
   extern virtual function void do_predict
680
                                (uvm_reg_item      rw,
681
                                 uvm_predict_e     kind = UVM_PREDICT_DIRECT,
682
                                 uvm_reg_byte_en_t be = -1);
683
   //-----------------
684
   // Group: Frontdoor
685
   //-----------------
686
 
687
   // Function: set_frontdoor
688
   //
689
   // Set a user-defined frontdoor for this register
690
   //
691
   // By default, registers are mapped linearly into the address space
692
   // of the address maps that instantiate them.
693
   // If registers are accessed using a different mechanism,
694
   // a user-defined access
695
   // mechanism must be defined and associated with
696
   // the corresponding register abstraction class
697
   //
698
   // If the register is mapped in multiple address maps, an address ~map~
699
   // must be specified.
700
   //
701
   extern function void set_frontdoor(uvm_reg_frontdoor ftdr,
702
                                      uvm_reg_map       map = null,
703
                                      string            fname = "",
704
                                      int               lineno = 0);
705
 
706
 
707
   // Function: get_frontdoor
708
   //
709
   // Returns the user-defined frontdoor for this register
710
   //
711
   // If ~null~, no user-defined frontdoor has been defined.
712
   // A user-defined frontdoor is defined
713
   // by using the  method.
714
   //
715
   // If the register is mapped in multiple address maps, an address ~map~
716
   // must be specified.
717
   //
718
   extern function uvm_reg_frontdoor get_frontdoor(uvm_reg_map map = null);
719
 
720
 
721
   //----------------
722
   // Group: Backdoor
723
   //----------------
724
 
725
 
726
   // Function: set_backdoor
727
   //
728
   // Set a user-defined backdoor for this register
729
   //
730
   // By default, registers are accessed via the built-in string-based
731
   // DPI routines if an HDL path has been specified using the
732
   //  or  method.
733
   //
734
   // If this default mechanism is not suitable (e.g. because
735
   // the register is not implemented in pure SystemVerilog)
736
   // a user-defined access
737
   // mechanism must be defined and associated with
738
   // the corresponding register abstraction class
739
   //
740
   // A user-defined backdoor is required if active update of the
741
   // mirror of this register abstraction class, based on observed
742
   // changes of the corresponding DUT register, is used.
743
   //
744
   extern function void set_backdoor(uvm_reg_backdoor bkdr,
745
                                     string          fname = "",
746
                                     int             lineno = 0);
747
 
748
 
749
   // Function: get_backdoor
750
   //
751
   // Returns the user-defined backdoor for this register
752
   //
753
   // If ~null~, no user-defined backdoor has been defined.
754
   // A user-defined backdoor is defined
755
   // by using the  method.
756
   //
757
   // If ~inherited~ is TRUE, returns the backdoor of the parent block
758
   // if none have been specified for this register.
759
   //
760
   extern function uvm_reg_backdoor get_backdoor(bit inherited = 1);
761
 
762
 
763
   // Function: clear_hdl_path
764
   //
765
   // Delete HDL paths
766
   //
767
   // Remove any previously specified HDL path to the register instance
768
   // for the specified design abstraction.
769
   //
770
   extern function void clear_hdl_path (string kind = "RTL");
771
 
772
 
773
   // Function: add_hdl_path
774
   //
775
   // Add an HDL path
776
   //
777
   // Add the specified HDL path to the register instance for the specified
778
   // design abstraction. This method may be called more than once for the
779
   // same design abstraction if the register is physically duplicated
780
   // in the design abstraction
781
   //
782
   // For example, the following register
783
   //
784
   //|        1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0
785
   //| Bits:  5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
786
   //|       +-+---+-------------+---+-------+
787
   //|       |A|xxx|      B      |xxx|   C   |
788
   //|       +-+---+-------------+---+-------+
789
   //
790
   // would be specified using the following literal value:
791
   //
792
   //| add_hdl_path('{ '{"A_reg", 15, 1},
793
   //|                 '{"B_reg",  6, 7},
794
   //|                 '{'C_reg",  0, 4} } );
795
   //
796
   // If the register is implemented using a single HDL variable,
797
   // The array should specify a single slice with its ~offset~ and ~size~
798
   // specified as -1. For example:
799
   //
800
   //| r1.add_hdl_path('{ '{"r1", -1, -1} });
801
   //
802
   extern function void add_hdl_path (uvm_hdl_path_slice slices[],
803
                                      string kind = "RTL");
804
 
805
 
806
   // Function: add_hdl_path_slice
807
   //
808
   // Append the specified HDL slice to the HDL path of the register instance
809
   // for the specified design abstraction.
810
   // If ~first~ is TRUE, starts the specification of a duplicate
811
   // HDL implementation of the register.
812
   //
813
   extern function void add_hdl_path_slice(string name,
814
                                           int offset,
815
                                           int size,
816
                                           bit first = 0,
817
                                           string kind = "RTL");
818
 
819
 
820
   // Function: has_hdl_path
821
   //
822
   // Check if a HDL path is specified
823
   //
824
   // Returns TRUE if the register instance has a HDL path defined for the
825
   // specified design abstraction. If no design abstraction is specified,
826
   // uses the default design abstraction specified for the parent block.
827
   //
828
   extern function bit has_hdl_path (string kind = "");
829
 
830
 
831
   // Function:  get_hdl_path
832
   //
833
   // Get the incremental HDL path(s)
834
   //
835
   // Returns the HDL path(s) defined for the specified design abstraction
836
   // in the register instance.
837
   // Returns only the component of the HDL paths that corresponds to
838
   // the register, not a full hierarchical path
839
   //
840
   // If no design abstraction is specified, the default design abstraction
841
   // for the parent block is used.
842
   //
843
   extern function void get_hdl_path (ref uvm_hdl_path_concat paths[$],
844
                                      input string kind = "");
845
 
846
 
847
   // Function:  get_hdl_path_kinds
848
   //
849
   // Get design abstractions for which HDL paths have been defined
850
   //
851
   extern function void get_hdl_path_kinds (ref string kinds[$]);
852
 
853
 
854
   // Function:  get_full_hdl_path
855
   //
856
   // Get the full hierarchical HDL path(s)
857
   //
858
   // Returns the full hierarchical HDL path(s) defined for the specified
859
   // design abstraction in the register instance.
860
   // There may be more than one path returned even
861
   // if only one path was defined for the register instance, if any of the
862
   // parent components have more than one path defined for the same design
863
   // abstraction
864
   //
865
   // If no design abstraction is specified, the default design abstraction
866
   // for each ancestor block is used to get each incremental path.
867
   //
868
   extern function void get_full_hdl_path (ref uvm_hdl_path_concat paths[$],
869
                                           input string kind = "",
870
                                           input string separator = ".");
871
 
872
 
873
   // Function: backdoor_read
874
   //
875
   // User-define backdoor read access
876
   //
877
   // Override the default string-based DPI backdoor access read
878
   // for this register type.
879
   // By default calls .
880
   //
881
   extern virtual task backdoor_read(uvm_reg_item rw);
882
 
883
 
884
   // Function: backdoor_write
885
   //
886
   // User-defined backdoor read access
887
   //
888
   // Override the default string-based DPI backdoor access write
889
   // for this register type.
890
   //
891
   extern virtual task backdoor_write(uvm_reg_item rw);
892
 
893
 
894
   // Function: backdoor_read_func
895
   //
896
   // User-defined backdoor read access
897
   //
898
   // Override the default string-based DPI backdoor access read
899
   // for this register type.
900
   //
901
   extern virtual function uvm_status_e backdoor_read_func(uvm_reg_item rw);
902
 
903
 
904
   // Function: backdoor_watch
905
   //
906
   // User-defined DUT register change monitor
907
   //
908
   // Watch the DUT register corresponding to this abstraction class
909
   // instance for any change in value and return when a value-change occurs.
910
   // This may be implemented a string-based DPI access if the simulation
911
   // tool provide a value-change callback facility. Such a facility does
912
   // not exists in the standard SystemVerilog DPI and thus no
913
   // default implementation for this method can be provided.
914
   //
915
   virtual task  backdoor_watch(); endtask
916
 
917
 
918
   //----------------
919
   // Group: Coverage
920
   //----------------
921
 
922
   // Function: include_coverage
923
   //
924
   // Specify which coverage model that must be included in
925
   // various block, register or memory abstraction class instances.
926
   //
927
   // The coverage models are specified by OR'ing or adding the
928
   //  coverage model identifiers corresponding to the
929
   // coverage model to be included.
930
   //
931
   // The scope specifies a hierarchical name or pattern identifying
932
   // a block, memory or register abstraction class instances.
933
   // Any block, memory or register whose full hierarchical name
934
   // matches the specified scope will have the specified functional
935
   // coverage models included in them.
936
   //
937
   // The scope can be specified as a POSIX regular expression
938
   // or simple pattern.
939
   // See  for more details.
940
   //
941
   //| uvm_reg::include_coverage("*", UVM_CVR_ALL);
942
   //
943
   // The specification of which coverage model to include in
944
   // which abstraction class is stored in a  resource in the
945
   //  resource database,
946
   // in the "uvm_reg::" scope namespace.
947
   //
948
   extern static function void include_coverage(string scope,
949
                                                uvm_reg_cvr_t models,
950
                                                uvm_object accessor = null);
951
 
952
   // Function: build_coverage
953
   //
954
   // Check if all of the specified coverage models must be built.
955
   //
956
   // Check which of the specified coverage model must be built
957
   // in this instance of the register abstraction class,
958
   // as specified by calls to .
959
   //
960
   // Models are specified by adding the symbolic value of individual
961
   // coverage model as defined in .
962
   // Returns the sum of all coverage models to be built in the
963
   // register model.
964
   //
965
   extern protected function uvm_reg_cvr_t build_coverage(uvm_reg_cvr_t models);
966
 
967
 
968
   // Function: add_coverage
969
   //
970
   // Specify that additional coverage models are available.
971
   //
972
   // Add the specified coverage model to the coverage models
973
   // available in this class.
974
   // Models are specified by adding the symbolic value of individual
975
   // coverage model as defined in .
976
   //
977
   // This method shall be called only in the constructor of
978
   // subsequently derived classes.
979
   //
980
   extern virtual protected function void add_coverage(uvm_reg_cvr_t models);
981
 
982
 
983
   // Function: has_coverage
984
   //
985
   // Check if register has coverage model(s)
986
   //
987
   // Returns TRUE if the register abstraction class contains a coverage model
988
   // for all of the models specified.
989
   // Models are specified by adding the symbolic value of individual
990
   // coverage model as defined in .
991
   //
992
   extern virtual function bit has_coverage(uvm_reg_cvr_t models);
993
 
994
 
995
   // Function: set_coverage
996
   //
997
   // Turns on coverage measurement.
998
   //
999
   // Turns the collection of functional coverage measurements on or off
1000
   // for this register.
1001
   // The functional coverage measurement is turned on for every
1002
   // coverage model specified using  symbolic
1003
   // identifiers.
1004
   // Multiple functional coverage models can be specified by adding
1005
   // the functional coverage model identifiers.
1006
   // All other functional coverage models are turned off.
1007
   // Returns the sum of all functional
1008
   // coverage models whose measurements were previously on.
1009
   //
1010
   // This method can only control the measurement of functional
1011
   // coverage models that are present in the register abstraction classes,
1012
   // then enabled during construction.
1013
   // See the  method to identify
1014
   // the available functional coverage models.
1015
   //
1016
   extern virtual function uvm_reg_cvr_t set_coverage(uvm_reg_cvr_t is_on);
1017
 
1018
 
1019
   // Function: get_coverage
1020
   //
1021
   // Check if coverage measurement is on.
1022
   //
1023
   // Returns TRUE if measurement for all of the specified functional
1024
   // coverage models are currently on.
1025
   // Multiple functional coverage models can be specified by adding the
1026
   // functional coverage model identifiers.
1027
   //
1028
   // See  for more details.
1029
   //
1030
   extern virtual function bit get_coverage(uvm_reg_cvr_t is_on);
1031
 
1032
 
1033
   // Function: sample
1034
   //
1035
   // Functional coverage measurement method
1036
   //
1037
   // This method is invoked by the register abstraction class
1038
   // whenever it is read or written with the specified ~data~
1039
   // via the specified address ~map~.
1040
   // It is invoked after the read or write operation has completed
1041
   // but before the mirror has been updated.
1042
   //
1043
   // Empty by default, this method may be extended by the
1044
   // abstraction class generator to perform the required sampling
1045
   // in any provided functional coverage model.
1046
   //
1047
   protected virtual function void sample(uvm_reg_data_t  data,
1048
                                          uvm_reg_data_t  byte_en,
1049
                                          bit             is_read,
1050
                                          uvm_reg_map     map);
1051
   endfunction
1052
 
1053
   // Function: sample_values
1054
   //
1055
   // Functional coverage measurement method for field values
1056
   //
1057
   // This method is invoked by the user
1058
   // or by the  method of the parent block
1059
   // to trigger the sampling
1060
   // of the current field values in the
1061
   // register-level functional coverage model.
1062
   //
1063
   // This method may be extended by the
1064
   // abstraction class generator to perform the required sampling
1065
   // in any provided field-value functional coverage model.
1066
   //
1067
   virtual function void sample_values();
1068
   endfunction
1069
 
1070
   /*local*/ function void XsampleX(uvm_reg_data_t  data,
1071
                                    uvm_reg_data_t  byte_en,
1072
                                    bit             is_read,
1073
                                    uvm_reg_map     map);
1074
      sample(data, byte_en, is_read, map);
1075
   endfunction
1076
 
1077
 
1078
   //-----------------
1079
   // Group: Callbacks
1080
   //-----------------
1081
   `uvm_register_cb(uvm_reg, uvm_reg_cbs)
1082
 
1083
 
1084
   // Task: pre_write
1085
   //
1086
   // Called before register write.
1087
   //
1088
   // If the specified data value, access ~path~ or address ~map~ are modified,
1089
   // the updated data value, access path or address map will be used
1090
   // to perform the register operation.
1091
   // If the ~status~ is modified to anything other than ,
1092
   // the operation is aborted.
1093
   //
1094
   // The registered callback methods are invoked after the invocation
1095
   // of this method.
1096
   // All register callbacks are executed before the corresponding
1097
   // field callbacks
1098
   //
1099
   virtual task pre_write(uvm_reg_item rw); endtask
1100
 
1101
 
1102
   // Task: post_write
1103
   //
1104
   // Called after register write.
1105
   //
1106
   // If the specified ~status~ is modified,
1107
   // the updated status will be
1108
   // returned by the register operation.
1109
   //
1110
   // The registered callback methods are invoked before the invocation
1111
   // of this method.
1112
   // All register callbacks are executed before the corresponding
1113
   // field callbacks
1114
   //
1115
   virtual task post_write(uvm_reg_item rw); endtask
1116
 
1117
 
1118
   // Task: pre_read
1119
   //
1120
   // Called before register read.
1121
   //
1122
   // If the specified access ~path~ or address ~map~ are modified,
1123
   // the updated access path or address map will be used to perform
1124
   // the register operation.
1125
   // If the ~status~ is modified to anything other than ,
1126
   // the operation is aborted.
1127
   //
1128
   // The registered callback methods are invoked after the invocation
1129
   // of this method.
1130
   // All register callbacks are executed before the corresponding
1131
   // field callbacks
1132
   //
1133
   virtual task pre_read(uvm_reg_item rw); endtask
1134
 
1135
 
1136
   // Task: post_read
1137
   //
1138
   // Called after register read.
1139
   //
1140
   // If the specified readback data or ~status~ is modified,
1141
   // the updated readback data or status will be
1142
   // returned by the register operation.
1143
   //
1144
   // The registered callback methods are invoked before the invocation
1145
   // of this method.
1146
   // All register callbacks are executed before the corresponding
1147
   // field callbacks
1148
   //
1149
   virtual task post_read(uvm_reg_item rw); endtask
1150
 
1151
 
1152
   extern virtual function void            do_print (uvm_printer printer);
1153
   extern virtual function string          convert2string();
1154
   extern virtual function uvm_object      clone      ();
1155
   extern virtual function void            do_copy    (uvm_object rhs);
1156
   extern virtual function bit             do_compare (uvm_object  rhs,
1157
                                                       uvm_comparer comparer);
1158
   extern virtual function void            do_pack    (uvm_packer packer);
1159
   extern virtual function void            do_unpack  (uvm_packer packer);
1160
 
1161
endclass: uvm_reg
1162
 
1163
 
1164
//------------------------------------------------------------------------------
1165
// IMPLEMENTATION
1166
//------------------------------------------------------------------------------
1167
 
1168
// new
1169
 
1170
function uvm_reg::new(string name="", int unsigned n_bits, int has_coverage);
1171
   super.new(name);
1172
   if (n_bits == 0) begin
1173
      `uvm_error("RegModel", $sformatf("Register \"%s\" cannot have 0 bits", get_name()));
1174
      n_bits = 1;
1175
   end
1176
   m_n_bits      = n_bits;
1177
   m_has_cover   = has_coverage;
1178
   m_atomic      = new(1);
1179
   m_n_used_bits = 0;
1180
   m_locked      = 0;
1181
   m_is_busy     = 0;
1182
   m_is_locked_by_field = 1'b0;
1183
   m_hdl_paths_pool = new("hdl_paths");
1184
 
1185
   if (n_bits > m_max_size)
1186
      m_max_size = n_bits;
1187
 
1188
endfunction: new
1189
 
1190
 
1191
// configure
1192
 
1193
function void uvm_reg::configure (uvm_reg_block blk_parent,
1194
                                  uvm_reg_file regfile_parent=null,
1195
                                  string hdl_path = "");
1196
   if (blk_parent == null) begin
1197
     `uvm_error("UVM/REG/CFG/NOBLK", {"uvm_reg::configure() called without a parent block for instance \"", get_name(), "\" of register type \"", get_type_name(), "\"."})
1198
     return;
1199
   end
1200
 
1201
   m_parent = blk_parent;
1202
   m_parent.add_reg(this);
1203
   m_regfile_parent = regfile_parent;
1204
   if (hdl_path != "")
1205
     add_hdl_path_slice(hdl_path, -1, -1);
1206
endfunction: configure
1207
 
1208
 
1209
// add_field
1210
 
1211
function void uvm_reg::add_field(uvm_reg_field field);
1212
   int offset;
1213
   int idx;
1214
 
1215
   if (m_locked) begin
1216
      `uvm_error("RegModel", "Cannot add field to locked register model");
1217
      return;
1218
   end
1219
 
1220
   if (field == null) `uvm_fatal("RegModel", "Attempting to register NULL field");
1221
 
1222
   // Store fields in LSB to MSB order
1223
   offset = field.get_lsb_pos();
1224
 
1225
   idx = -1;
1226
   foreach (m_fields[i]) begin
1227
      if (offset < m_fields[i].get_lsb_pos()) begin
1228
         int j = i;
1229
         m_fields.insert(j, field);
1230
         idx = i;
1231
         break;
1232
      end
1233
   end
1234
   if (idx < 0) begin
1235
      m_fields.push_back(field);
1236
      idx = m_fields.size()-1;
1237
   end
1238
 
1239
   m_n_used_bits += field.get_n_bits();
1240
 
1241
   // Check if there are too many fields in the register
1242
   if (m_n_used_bits > m_n_bits) begin
1243
      `uvm_error("RegModel",
1244
         $sformatf("Fields use more bits (%0d) than available in register \"%s\" (%0d)",
1245
            m_n_used_bits, get_name(), m_n_bits));
1246
   end
1247
 
1248
   // Check if there are overlapping fields
1249
   if (idx > 0) begin
1250
      if (m_fields[idx-1].get_lsb_pos() +
1251
          m_fields[idx-1].get_n_bits() > offset) begin
1252
         `uvm_error("RegModel", $sformatf("Field %s overlaps field %s in register \"%s\"",
1253
                                        m_fields[idx-1].get_name(),
1254
                                        field.get_name(), get_name()));
1255
      end
1256
   end
1257
   if (idx < m_fields.size()-1) begin
1258
      if (offset + field.get_n_bits() >
1259
          m_fields[idx+1].get_lsb_pos()) begin
1260
         `uvm_error("RegModel", $sformatf("Field %s overlaps field %s in register \"%s\"",
1261
                                        field.get_name(),
1262
                                        m_fields[idx+1].get_name(),
1263
                                      get_name()));
1264
      end
1265
   end
1266
endfunction: add_field
1267
 
1268
 
1269
// Xlock_modelX
1270
 
1271
function void uvm_reg::Xlock_modelX();
1272
   if (m_locked)
1273
     return;
1274
   m_locked = 1;
1275
endfunction
1276
 
1277
 
1278
//----------------------
1279
// Group- User Frontdoor
1280
//----------------------
1281
 
1282
// set_frontdoor
1283
 
1284
function void uvm_reg::set_frontdoor(uvm_reg_frontdoor ftdr,
1285
                                     uvm_reg_map       map = null,
1286
                                     string            fname = "",
1287
                                     int               lineno = 0);
1288
   uvm_reg_map_info map_info;
1289
   ftdr.fname = m_fname;
1290
   ftdr.lineno = m_lineno;
1291
   map = get_local_map(map, "set_frontdoor()");
1292
   if (map == null)
1293
     return;
1294
   map_info = map.get_reg_map_info(this);
1295
   if (map_info == null)
1296
      map.add_reg(this, -1, "RW", 1, ftdr);
1297
   else begin
1298
      map_info.frontdoor = ftdr;
1299
   end
1300
endfunction: set_frontdoor
1301
 
1302
 
1303
// get_frontdoor
1304
 
1305
function uvm_reg_frontdoor uvm_reg::get_frontdoor(uvm_reg_map map = null);
1306
   uvm_reg_map_info map_info;
1307
   map = get_local_map(map, "get_frontdoor()");
1308
   if (map == null)
1309
     return null;
1310
   map_info = map.get_reg_map_info(this);
1311
   return map_info.frontdoor;
1312
endfunction: get_frontdoor
1313
 
1314
 
1315
// set_backdoor
1316
 
1317
function void uvm_reg::set_backdoor(uvm_reg_backdoor bkdr,
1318
                                    string           fname = "",
1319
                                    int              lineno = 0);
1320
   bkdr.fname = fname;
1321
   bkdr.lineno = lineno;
1322
   if (m_backdoor != null &&
1323
       m_backdoor.has_update_threads()) begin
1324
      `uvm_warning("RegModel", "Previous register backdoor still has update threads running. Backdoors with active mirroring should only be set before simulation starts.");
1325
   end
1326
   m_backdoor = bkdr;
1327
endfunction: set_backdoor
1328
 
1329
 
1330
// get_backdoor
1331
 
1332
function uvm_reg_backdoor uvm_reg::get_backdoor(bit inherited = 1);
1333
 
1334
   if (m_backdoor == null && inherited) begin
1335
     uvm_reg_block blk = get_parent();
1336
     uvm_reg_backdoor bkdr;
1337
     while (blk != null) begin
1338
       bkdr = blk.get_backdoor();
1339
       if (bkdr != null) begin
1340
         m_backdoor = bkdr;
1341
         break;
1342
       end
1343
       blk = blk.get_parent();
1344
     end
1345
   end
1346
   return m_backdoor;
1347
endfunction: get_backdoor
1348
 
1349
 
1350
 
1351
// clear_hdl_path
1352
 
1353
function void uvm_reg::clear_hdl_path(string kind = "RTL");
1354
  if (kind == "ALL") begin
1355
    m_hdl_paths_pool = new("hdl_paths");
1356
    return;
1357
  end
1358
 
1359
  if (kind == "") begin
1360
     if (m_regfile_parent != null)
1361
        kind = m_regfile_parent.get_default_hdl_path();
1362
     else
1363
        kind = m_parent.get_default_hdl_path();
1364
  end
1365
 
1366
  if (!m_hdl_paths_pool.exists(kind)) begin
1367
    `uvm_warning("RegModel",{"Unknown HDL Abstraction '",kind,"'"})
1368
    return;
1369
  end
1370
 
1371
  m_hdl_paths_pool.delete(kind);
1372
endfunction
1373
 
1374
 
1375
// add_hdl_path
1376
 
1377
function void uvm_reg::add_hdl_path(uvm_hdl_path_slice slices[],
1378
                                    string kind = "RTL");
1379
    uvm_queue #(uvm_hdl_path_concat) paths = m_hdl_paths_pool.get(kind);
1380
    uvm_hdl_path_concat concat = new();
1381
 
1382
    concat.set(slices);
1383
    paths.push_back(concat);
1384
endfunction
1385
 
1386
 
1387
// add_hdl_path_slice
1388
 
1389
function void uvm_reg::add_hdl_path_slice(string name,
1390
                                          int offset,
1391
                                          int size,
1392
                                          bit first = 0,
1393
                                          string kind = "RTL");
1394
    uvm_queue #(uvm_hdl_path_concat) paths = m_hdl_paths_pool.get(kind);
1395
    uvm_hdl_path_concat concat;
1396
 
1397
    if (first || paths.size() == 0) begin
1398
       concat = new();
1399
       paths.push_back(concat);
1400
    end
1401
    else
1402
       concat = paths.get(paths.size()-1);
1403
 
1404
   concat.add_path(name, offset, size);
1405
endfunction
1406
 
1407
 
1408
// has_hdl_path
1409
 
1410
function bit  uvm_reg::has_hdl_path(string kind = "");
1411
  if (kind == "") begin
1412
     if (m_regfile_parent != null)
1413
        kind = m_regfile_parent.get_default_hdl_path();
1414
     else
1415
        kind = m_parent.get_default_hdl_path();
1416
  end
1417
 
1418
  return m_hdl_paths_pool.exists(kind);
1419
endfunction
1420
 
1421
 
1422
// get_hdl_path_kinds
1423
 
1424
function void uvm_reg::get_hdl_path_kinds (ref string kinds[$]);
1425
  string kind;
1426
  kinds.delete();
1427
  if (!m_hdl_paths_pool.first(kind))
1428
    return;
1429
  do
1430
    kinds.push_back(kind);
1431
  while (m_hdl_paths_pool.next(kind));
1432
endfunction
1433
 
1434
 
1435
// get_hdl_path
1436
 
1437
function void uvm_reg::get_hdl_path(ref uvm_hdl_path_concat paths[$],
1438
                                        input string kind = "");
1439
 
1440
  uvm_queue #(uvm_hdl_path_concat) hdl_paths;
1441
 
1442
  if (kind == "") begin
1443
     if (m_regfile_parent != null)
1444
        kind = m_regfile_parent.get_default_hdl_path();
1445
     else
1446
        kind = m_parent.get_default_hdl_path();
1447
  end
1448
 
1449
  if (!has_hdl_path(kind)) begin
1450
    `uvm_error("RegModel",
1451
       {"Register does not have hdl path defined for abstraction '",kind,"'"})
1452
    return;
1453
  end
1454
 
1455
  hdl_paths = m_hdl_paths_pool.get(kind);
1456
 
1457
  for (int i=0; i
1458
     paths.push_back(hdl_paths.get(i));
1459
  end
1460
 
1461
endfunction
1462
 
1463
 
1464
// get_full_hdl_path
1465
 
1466
function void uvm_reg::get_full_hdl_path(ref uvm_hdl_path_concat paths[$],
1467
                                         input string kind = "",
1468
                                         input string separator = ".");
1469
 
1470
   if (kind == "") begin
1471
      if (m_regfile_parent != null)
1472
         kind = m_regfile_parent.get_default_hdl_path();
1473
      else
1474
         kind = m_parent.get_default_hdl_path();
1475
   end
1476
 
1477
   if (!has_hdl_path(kind)) begin
1478
      `uvm_error("RegModel",
1479
         {"Register ",get_full_name()," does not have hdl path defined for abstraction '",kind,"'"})
1480
      return;
1481
   end
1482
 
1483
   begin
1484
      uvm_queue #(uvm_hdl_path_concat) hdl_paths = m_hdl_paths_pool.get(kind);
1485
      string parent_paths[$];
1486
 
1487
      if (m_regfile_parent != null)
1488
         m_regfile_parent.get_full_hdl_path(parent_paths, kind, separator);
1489
      else
1490
         m_parent.get_full_hdl_path(parent_paths, kind, separator);
1491
 
1492
      for (int i=0; i
1493
         uvm_hdl_path_concat hdl_concat = hdl_paths.get(i);
1494
 
1495
         foreach (parent_paths[j])  begin
1496
            uvm_hdl_path_concat t = new;
1497
 
1498
            foreach (hdl_concat.slices[k]) begin
1499
               if (hdl_concat.slices[k].path == "")
1500
                  t.add_path(parent_paths[j]);
1501
               else
1502
                  t.add_path({ parent_paths[j], separator, hdl_concat.slices[k].path },
1503
                             hdl_concat.slices[k].offset,
1504
                             hdl_concat.slices[k].size);
1505
            end
1506
            paths.push_back(t);
1507
         end
1508
      end
1509
   end
1510
endfunction
1511
 
1512
 
1513
// set_offset
1514
 
1515
function void uvm_reg::set_offset (uvm_reg_map    map,
1516
                                   uvm_reg_addr_t offset,
1517
                                   bit unmapped = 0);
1518
 
1519
   uvm_reg_map orig_map = map;
1520
 
1521
   if (m_maps.num() > 1 && map == null) begin
1522
      `uvm_error("RegModel",{"set_offset requires a non-null map when register '",
1523
                 get_full_name(),"' belongs to more than one map."})
1524
      return;
1525
   end
1526
 
1527
   map = get_local_map(map,"set_offset()");
1528
 
1529
   if (map == null)
1530
     return;
1531
 
1532
   map.m_set_reg_offset(this, offset, unmapped);
1533
endfunction
1534
 
1535
 
1536
// set_parent
1537
 
1538
function void uvm_reg::set_parent(uvm_reg_block blk_parent,
1539
                                      uvm_reg_file regfile_parent);
1540
  if (m_parent != null) begin
1541
     // ToDo: remove register from previous parent
1542
  end
1543
  m_parent = blk_parent;
1544
  m_regfile_parent = regfile_parent;
1545
endfunction
1546
 
1547
 
1548
// get_parent
1549
 
1550
function uvm_reg_block uvm_reg::get_parent();
1551
  return get_block();
1552
endfunction
1553
 
1554
 
1555
// get_regfile
1556
 
1557
function uvm_reg_file uvm_reg::get_regfile();
1558
   return m_regfile_parent;
1559
endfunction
1560
 
1561
 
1562
// get_full_name
1563
 
1564
function string uvm_reg::get_full_name();
1565
 
1566
   if (m_regfile_parent != null)
1567
      return {m_regfile_parent.get_full_name(), ".", get_name()};
1568
 
1569
   if (m_parent != null)
1570
      return {m_parent.get_full_name(), ".", get_name()};
1571
 
1572
   return get_name();
1573
endfunction: get_full_name
1574
 
1575
 
1576
// add_map
1577
 
1578
function void uvm_reg::add_map(uvm_reg_map map);
1579
  m_maps[map] = 1;
1580
endfunction
1581
 
1582
 
1583
// get_maps
1584
 
1585
function void uvm_reg::get_maps(ref uvm_reg_map maps[$]);
1586
   foreach (m_maps[map])
1587
     maps.push_back(map);
1588
endfunction
1589
 
1590
 
1591
// get_n_maps
1592
 
1593
function int uvm_reg::get_n_maps();
1594
   return m_maps.num();
1595
endfunction
1596
 
1597
 
1598
// is_in_map
1599
 
1600
function bit uvm_reg::is_in_map(uvm_reg_map map);
1601
   if (m_maps.exists(map))
1602
     return 1;
1603
   foreach (m_maps[l]) begin
1604
     uvm_reg_map local_map = l;
1605
     uvm_reg_map parent_map = local_map.get_parent_map();
1606
 
1607
     while (parent_map != null) begin
1608
       if (parent_map == map)
1609
         return 1;
1610
       parent_map = parent_map.get_parent_map();
1611
     end
1612
   end
1613
   return 0;
1614
endfunction
1615
 
1616
 
1617
 
1618
// get_local_map
1619
 
1620
function uvm_reg_map uvm_reg::get_local_map(uvm_reg_map map, string caller="");
1621
   if (map == null)
1622
     return get_default_map();
1623
   if (m_maps.exists(map))
1624
     return map;
1625
   foreach (m_maps[l]) begin
1626
     uvm_reg_map local_map=l;
1627
     uvm_reg_map parent_map = local_map.get_parent_map();
1628
 
1629
     while (parent_map != null) begin
1630
       if (parent_map == map)
1631
         return local_map;
1632
       parent_map = parent_map.get_parent_map();
1633
     end
1634
   end
1635
   `uvm_warning("RegModel",
1636
       {"Register '",get_full_name(),"' is not contained within map '",map.get_full_name(),"'",
1637
        (caller == "" ? "": {" (called from ",caller,")"}) })
1638
   return null;
1639
endfunction
1640
 
1641
 
1642
 
1643
// get_default_map
1644
 
1645
function uvm_reg_map uvm_reg::get_default_map(string caller="");
1646
 
1647
   // if reg is not associated with any map, return ~null~
1648
   if (m_maps.num() == 0) begin
1649
      `uvm_warning("RegModel",
1650
        {"Register '",get_full_name(),"' is not registered with any map",
1651
         (caller == "" ? "": {" (called from ",caller,")"})})
1652
      return null;
1653
   end
1654
 
1655
   // if only one map, choose that
1656
   if (m_maps.num() == 1) begin
1657
     uvm_reg_map map;
1658
     void'(m_maps.first(map));
1659
     return map;
1660
   end
1661
 
1662
   // try to choose one based on default_map in parent blocks.
1663
   foreach (m_maps[l]) begin
1664
     uvm_reg_map map = l;
1665
     uvm_reg_block blk = map.get_parent();
1666
     uvm_reg_map default_map = blk.get_default_map();
1667
     if (default_map != null) begin
1668
       uvm_reg_map local_map = get_local_map(default_map,"get_default_map()");
1669
       if (local_map != null)
1670
         return local_map;
1671
     end
1672
   end
1673
 
1674
   // if that fails, choose the first in this reg's maps
1675
 
1676
   begin
1677
     uvm_reg_map map;
1678
     void'(m_maps.first(map));
1679
     return map;
1680
   end
1681
 
1682
endfunction
1683
 
1684
 
1685
// get_rights
1686
 
1687
function string uvm_reg::get_rights(uvm_reg_map map = null);
1688
 
1689
   uvm_reg_map_info info;
1690
 
1691
   map = get_local_map(map,"get_rights()");
1692
 
1693
   if (map == null)
1694
     return "RW";
1695
 
1696
   info = map.get_reg_map_info(this);
1697
   return info.rights;
1698
 
1699
endfunction
1700
 
1701
 
1702
 
1703
// get_block
1704
 
1705
function uvm_reg_block uvm_reg::get_block();
1706
   get_block = m_parent;
1707
endfunction
1708
 
1709
 
1710
// get_offset
1711
 
1712
function uvm_reg_addr_t uvm_reg::get_offset(uvm_reg_map map = null);
1713
 
1714
   uvm_reg_map_info map_info;
1715
   uvm_reg_map orig_map = map;
1716
 
1717
   map = get_local_map(map,"get_offset()");
1718
 
1719
   if (map == null)
1720
     return -1;
1721
 
1722
   map_info = map.get_reg_map_info(this);
1723
 
1724
   if (map_info.unmapped) begin
1725
      `uvm_warning("RegModel", {"Register '",get_name(),
1726
                   "' is unmapped in map '",
1727
                   ((orig_map == null) ? map.get_full_name() : orig_map.get_full_name()),"'"})
1728
      return -1;
1729
   end
1730
 
1731
   return map_info.offset;
1732
 
1733
endfunction
1734
 
1735
 
1736
// get_addresses
1737
 
1738
function int uvm_reg::get_addresses(uvm_reg_map map=null, ref uvm_reg_addr_t addr[]);
1739
 
1740
   uvm_reg_map_info map_info;
1741
   uvm_reg_map system_map;
1742
   uvm_reg_map orig_map = map;
1743
 
1744
   map = get_local_map(map,"get_addresses()");
1745
 
1746
   if (map == null)
1747
     return -1;
1748
 
1749
   map_info = map.get_reg_map_info(this);
1750
 
1751
   if (map_info.unmapped) begin
1752
      `uvm_warning("RegModel", {"Register '",get_name(),
1753
                   "' is unmapped in map '",
1754
                   ((orig_map == null) ? map.get_full_name() : orig_map.get_full_name()),"'"})
1755
      return -1;
1756
   end
1757
 
1758
   addr = map_info.addr;
1759
   system_map = map.get_root_map();
1760
   return map.get_n_bytes();
1761
 
1762
endfunction
1763
 
1764
 
1765
// get_address
1766
 
1767
function uvm_reg_addr_t uvm_reg::get_address(uvm_reg_map map = null);
1768
   uvm_reg_addr_t  addr[];
1769
   void'(get_addresses(map,addr));
1770
   return addr[0];
1771
endfunction
1772
 
1773
 
1774
// get_n_bits
1775
 
1776
function int unsigned uvm_reg::get_n_bits();
1777
   return m_n_bits;
1778
endfunction
1779
 
1780
 
1781
// get_n_bytes
1782
 
1783
function int unsigned uvm_reg::get_n_bytes();
1784
   return ((m_n_bits-1) / 8) + 1;
1785
endfunction
1786
 
1787
 
1788
// get_max_size
1789
 
1790
function int unsigned uvm_reg::get_max_size();
1791
   return m_max_size;
1792
endfunction: get_max_size
1793
 
1794
 
1795
// get_fields
1796
 
1797
function void uvm_reg::get_fields(ref uvm_reg_field fields[$]);
1798
   foreach(m_fields[i])
1799
      fields.push_back(m_fields[i]);
1800
endfunction
1801
 
1802
 
1803
// get_field_by_name
1804
 
1805
function uvm_reg_field uvm_reg::get_field_by_name(string name);
1806
   foreach (m_fields[i])
1807
      if (m_fields[i].get_name() == name)
1808
         return m_fields[i];
1809
   `uvm_warning("RegModel", {"Unable to locate field '",name,
1810
                            "' in register '",get_name(),"'"})
1811
   return null;
1812
endfunction
1813
 
1814
 
1815
// Xget_field_accessX
1816
//
1817
// Returns "WO" if all of the fields in the registers are write-only
1818
// Returns "RO" if all of the fields in the registers are read-only
1819
// Returns "RW" otherwise.
1820
 
1821
function string uvm_reg::Xget_fields_accessX(uvm_reg_map map);
1822
   bit is_R;
1823
   bit is_W;
1824
 
1825
   foreach(m_fields[i]) begin
1826
      case (m_fields[i].get_access(map))
1827
       "RO",
1828
         "RC",
1829
         "RS":
1830
            is_R = 1;
1831
 
1832
       "WO",
1833
          "WOC",
1834
          "WOS",
1835
          "WO1":
1836
             is_W = 1;
1837
 
1838
       default:
1839
          return "RW";
1840
      endcase
1841
 
1842
      if (is_R && is_W) return "RW";
1843
   end
1844
 
1845
   case ({is_R, is_W})
1846
    2'b01: return "WO";
1847
    2'b10: return "RO";
1848
   endcase
1849
   return "RW";
1850
endfunction
1851
 
1852
 
1853
//---------
1854
// COVERAGE
1855
//---------
1856
 
1857
 
1858
// include_coverage
1859
 
1860
function void uvm_reg::include_coverage(string scope,
1861
                                        uvm_reg_cvr_t models,
1862
                                        uvm_object accessor = null);
1863
   uvm_reg_cvr_rsrc_db::set({"uvm_reg::", scope},
1864
                            "include_coverage",
1865
                            models, accessor);
1866
endfunction
1867
 
1868
 
1869
// build_coverage
1870
 
1871
function uvm_reg_cvr_t uvm_reg::build_coverage(uvm_reg_cvr_t models);
1872
   build_coverage = UVM_NO_COVERAGE;
1873
   void'(uvm_reg_cvr_rsrc_db::read_by_name({"uvm_reg::", get_full_name()},
1874
                                           "include_coverage",
1875
                                           build_coverage, this));
1876
   return build_coverage & models;
1877
endfunction: build_coverage
1878
 
1879
 
1880
// add_coverage
1881
 
1882
function void uvm_reg::add_coverage(uvm_reg_cvr_t models);
1883
   m_has_cover |= models;
1884
endfunction: add_coverage
1885
 
1886
 
1887
// has_coverage
1888
 
1889
function bit uvm_reg::has_coverage(uvm_reg_cvr_t models);
1890
   return ((m_has_cover & models) == models);
1891
endfunction: has_coverage
1892
 
1893
 
1894
// set_coverage
1895
 
1896
function uvm_reg_cvr_t uvm_reg::set_coverage(uvm_reg_cvr_t is_on);
1897
   if (is_on == uvm_reg_cvr_t'(UVM_NO_COVERAGE)) begin
1898
      m_cover_on = is_on;
1899
      return m_cover_on;
1900
   end
1901
 
1902
   m_cover_on = m_has_cover & is_on;
1903
 
1904
   return m_cover_on;
1905
endfunction: set_coverage
1906
 
1907
 
1908
// get_coverage
1909
 
1910
function bit uvm_reg::get_coverage(uvm_reg_cvr_t is_on);
1911
   if (has_coverage(is_on) == 0)
1912
      return 0;
1913
   return ((m_cover_on & is_on) == is_on);
1914
endfunction: get_coverage
1915
 
1916
 
1917
 
1918
//---------
1919
// ACCESS
1920
//---------
1921
 
1922
 
1923
// set
1924
 
1925
function void uvm_reg::set(uvm_reg_data_t  value,
1926
                           string          fname = "",
1927
                           int             lineno = 0);
1928
   // Split the value into the individual fields
1929
   m_fname = fname;
1930
   m_lineno = lineno;
1931
 
1932
   foreach (m_fields[i])
1933
      m_fields[i].set((value >> m_fields[i].get_lsb_pos()) &
1934
                       ((1 << m_fields[i].get_n_bits()) - 1));
1935
endfunction: set
1936
 
1937
 
1938
// predict
1939
 
1940
function bit uvm_reg::predict (uvm_reg_data_t    value,
1941
                               uvm_reg_byte_en_t be = -1,
1942
                               uvm_predict_e     kind = UVM_PREDICT_DIRECT,
1943
                               uvm_path_e        path = UVM_FRONTDOOR,
1944
                               uvm_reg_map       map = null,
1945
                               string            fname = "",
1946
                               int               lineno = 0);
1947
  uvm_reg_item rw = new;
1948
  rw.value[0] = value;
1949
  rw.path = path;
1950
  rw.map = map;
1951
  rw.fname = fname;
1952
  rw.lineno = lineno;
1953
  do_predict(rw, kind, be);
1954
  predict = (rw.status == UVM_NOT_OK) ? 0 : 1;
1955
endfunction: predict
1956
 
1957
 
1958
// do_predict
1959
 
1960
function void uvm_reg::do_predict(uvm_reg_item      rw,
1961
                                  uvm_predict_e     kind = UVM_PREDICT_DIRECT,
1962
                                  uvm_reg_byte_en_t be = -1);
1963
 
1964
   uvm_reg_data_t reg_value = rw.value[0];
1965
   m_fname = rw.fname;
1966
   m_lineno = rw.lineno;
1967
 
1968
if (rw.status ==UVM_IS_OK )
1969
   rw.status = UVM_IS_OK;
1970
 
1971
   if (m_is_busy && kind == UVM_PREDICT_DIRECT) begin
1972
      `uvm_warning("RegModel", {"Trying to predict value of register '",
1973
                  get_full_name(),"' while it is being accessed"})
1974
      rw.status = UVM_NOT_OK;
1975
      return;
1976
   end
1977
 
1978
   foreach (m_fields[i]) begin
1979
      rw.value[0] = (reg_value >> m_fields[i].get_lsb_pos()) &
1980
                                 ((1 << m_fields[i].get_n_bits())-1);
1981
      m_fields[i].do_predict(rw, kind, be>>(m_fields[i].get_lsb_pos()/8));
1982
   end
1983
 
1984
   rw.value[0] = reg_value;
1985
 
1986
endfunction: do_predict
1987
 
1988
 
1989
// get
1990
 
1991
function uvm_reg_data_t  uvm_reg::get(string  fname = "",
1992
                                      int     lineno = 0);
1993
   // Concatenate the value of the individual fields
1994
   // to form the register value
1995
   m_fname = fname;
1996
   m_lineno = lineno;
1997
 
1998
   get = 0;
1999
 
2000
   foreach (m_fields[i])
2001
      get |= m_fields[i].get() << m_fields[i].get_lsb_pos();
2002
endfunction: get
2003
 
2004
 
2005
// get_mirrored_value
2006
 
2007
function uvm_reg_data_t  uvm_reg::get_mirrored_value(string  fname = "",
2008
                                      int     lineno = 0);
2009
   // Concatenate the value of the individual fields
2010
   // to form the register value
2011
   m_fname = fname;
2012
   m_lineno = lineno;
2013
 
2014
   get_mirrored_value = 0;
2015
 
2016
   foreach (m_fields[i])
2017
      get_mirrored_value |= m_fields[i].get_mirrored_value() << m_fields[i].get_lsb_pos();
2018
endfunction: get_mirrored_value
2019
 
2020
 
2021
// reset
2022
 
2023
function void uvm_reg::reset(string kind = "HARD");
2024
   foreach (m_fields[i])
2025
      m_fields[i].reset(kind);
2026
   // Put back a key in the semaphore if it is checked out
2027
   // in case a thread was killed during an operation
2028
   void'(m_atomic.try_get(1));
2029
   m_atomic.put(1);
2030
   m_process = null;
2031
   Xset_busyX(0);
2032
endfunction: reset
2033
 
2034
 
2035
// get_reset
2036
 
2037
function uvm_reg_data_t uvm_reg::get_reset(string kind = "HARD");
2038
   // Concatenate the value of the individual fields
2039
   // to form the register value
2040
   get_reset = 0;
2041
 
2042
   foreach (m_fields[i])
2043
      get_reset |= m_fields[i].get_reset(kind) << m_fields[i].get_lsb_pos();
2044
endfunction: get_reset
2045
 
2046
 
2047
// has_reset
2048
 
2049
function bit uvm_reg::has_reset(string kind = "HARD",
2050
                                bit    delete = 0);
2051
 
2052
   has_reset = 0;
2053
   foreach (m_fields[i]) begin
2054
      has_reset |= m_fields[i].has_reset(kind, delete);
2055
      if (!delete && has_reset)
2056
        return 1;
2057
   end
2058
endfunction: has_reset
2059
 
2060
 
2061
// set_reset
2062
 
2063
function void uvm_reg::set_reset(uvm_reg_data_t value,
2064
                                 string         kind = "HARD");
2065
   foreach (m_fields[i]) begin
2066
      m_fields[i].set_reset(value >> m_fields[i].get_lsb_pos(), kind);
2067
   end
2068
endfunction: set_reset
2069
 
2070
 
2071
//-----------
2072
// BUS ACCESS
2073
//-----------
2074
 
2075
// needs_update
2076
 
2077
function bit uvm_reg::needs_update();
2078
   needs_update = 0;
2079
   foreach (m_fields[i]) begin
2080
      if (m_fields[i].needs_update()) begin
2081
         return 1;
2082
      end
2083
   end
2084
endfunction: needs_update
2085
 
2086
 
2087
// update
2088
 
2089
task uvm_reg::update(output uvm_status_e      status,
2090
                     input  uvm_path_e        path = UVM_DEFAULT_PATH,
2091
                     input  uvm_reg_map       map = null,
2092
                     input  uvm_sequence_base parent = null,
2093
                     input  int               prior = -1,
2094
                     input  uvm_object        extension = null,
2095
                     input  string            fname = "",
2096
                     input  int               lineno = 0);
2097
   uvm_reg_data_t upd;
2098
 
2099
   status = UVM_IS_OK;
2100
 
2101
   if (!needs_update()) return;
2102
 
2103
   // Concatenate the write-to-update values from each field
2104
   // Fields are stored in LSB or MSB order
2105
   upd = 0;
2106
   foreach (m_fields[i])
2107
      upd |= m_fields[i].XupdateX() << m_fields[i].get_lsb_pos();
2108
 
2109
   write(status, upd, path, map, parent, prior, extension, fname, lineno);
2110
endtask: update
2111
 
2112
 
2113
 
2114
// write
2115
 
2116
task uvm_reg::write(output uvm_status_e      status,
2117
                    input  uvm_reg_data_t    value,
2118
                    input  uvm_path_e        path = UVM_DEFAULT_PATH,
2119
                    input  uvm_reg_map       map = null,
2120
                    input  uvm_sequence_base parent = null,
2121
                    input  int               prior = -1,
2122
                    input  uvm_object        extension = null,
2123
                    input  string            fname = "",
2124
                    input  int               lineno = 0);
2125
 
2126
   // create an abstract transaction for this operation
2127
   uvm_reg_item rw;
2128
 
2129
   XatomicX(1);
2130
 
2131
   set(value);
2132
 
2133
   rw = uvm_reg_item::type_id::create("write_item",,get_full_name());
2134
   rw.element      = this;
2135
   rw.element_kind = UVM_REG;
2136
   rw.kind         = UVM_WRITE;
2137
   rw.value[0]     = value;
2138
   rw.path         = path;
2139
   rw.map          = map;
2140
   rw.parent       = parent;
2141
   rw.prior        = prior;
2142
   rw.extension    = extension;
2143
   rw.fname        = fname;
2144
   rw.lineno       = lineno;
2145
 
2146
   do_write(rw);
2147
 
2148
   status = rw.status;
2149
 
2150
   XatomicX(0);
2151
 
2152
endtask
2153
 
2154
 
2155
// do_write
2156
 
2157
task uvm_reg::do_write (uvm_reg_item rw);
2158
 
2159
   uvm_reg_cb_iter  cbs = new(this);
2160
   uvm_reg_map_info map_info;
2161
   uvm_reg_data_t   value;
2162
 
2163
   m_fname  = rw.fname;
2164
   m_lineno = rw.lineno;
2165
 
2166
   if (!Xcheck_accessX(rw,map_info,"write()"))
2167
     return;
2168
 
2169
   XatomicX(1);
2170
 
2171
   m_write_in_progress = 1'b1;
2172
 
2173
   rw.value[0] &= ((1 << m_n_bits)-1);
2174
   value = rw.value[0];
2175
 
2176
   rw.status = UVM_IS_OK;
2177
 
2178
   // PRE-WRITE CBS - FIELDS
2179
   begin : pre_write_callbacks
2180
      uvm_reg_data_t  msk;
2181
      int lsb;
2182
 
2183
      foreach (m_fields[i]) begin
2184
         uvm_reg_field_cb_iter cbs = new(m_fields[i]);
2185
         uvm_reg_field f = m_fields[i];
2186
         lsb = f.get_lsb_pos();
2187
         msk = ((1<
2188
         rw.value[0] = (value & msk) >> lsb;
2189
         f.pre_write(rw);
2190
         for (uvm_reg_cbs cb=cbs.first(); cb!=null; cb=cbs.next()) begin
2191
            rw.element = f;
2192
            rw.element_kind = UVM_FIELD;
2193
            cb.pre_write(rw);
2194
         end
2195
 
2196
         value = (value & ~msk) | (rw.value[0] << lsb);
2197
      end
2198
   end
2199
   rw.element = this;
2200
   rw.element_kind = UVM_REG;
2201
   rw.value[0] = value;
2202
 
2203
   // PRE-WRITE CBS - REG
2204
   pre_write(rw);
2205
   for (uvm_reg_cbs cb=cbs.first(); cb!=null; cb=cbs.next())
2206
      cb.pre_write(rw);
2207
 
2208
   if (rw.status != UVM_IS_OK) begin
2209
     m_write_in_progress = 1'b0;
2210
 
2211
     XatomicX(0);
2212
 
2213
     return;
2214
   end
2215
 
2216
   // EXECUTE WRITE...
2217
   case (rw.path)
2218
 
2219
      // ...VIA USER BACKDOOR
2220
      UVM_BACKDOOR: begin
2221
         uvm_reg_data_t final_val;
2222
         uvm_reg_backdoor bkdr = get_backdoor();
2223
 
2224
         value = rw.value[0];
2225
 
2226
         // Mimick the final value after a physical read
2227
         rw.kind = UVM_READ;
2228
         if (bkdr != null)
2229
           bkdr.read(rw);
2230
         else
2231
           backdoor_read(rw);
2232
 
2233
         if (rw.status == UVM_NOT_OK) begin
2234
           m_write_in_progress = 1'b0;
2235
           return;
2236
         end
2237
 
2238
         begin
2239
            foreach (m_fields[i]) begin
2240
               uvm_reg_data_t field_val;
2241
               int lsb = m_fields[i].get_lsb_pos();
2242
               int sz  = m_fields[i].get_n_bits();
2243
               field_val = m_fields[i].XpredictX((rw.value[0] >> lsb) & ((1<
2244
                                                 (value >> lsb) & ((1<
2245
                                                 rw.local_map);
2246
               final_val |= field_val << lsb;
2247
            end
2248
         end
2249
         rw.kind = UVM_WRITE;
2250
         rw.value[0] = final_val;
2251
 
2252
         if (bkdr != null)
2253
           bkdr.write(rw);
2254
         else
2255
           backdoor_write(rw);
2256
 
2257
         do_predict(rw, UVM_PREDICT_WRITE);
2258
      end
2259
 
2260
      UVM_FRONTDOOR: begin
2261
 
2262
         uvm_reg_map system_map = rw.local_map.get_root_map();
2263
 
2264
         m_is_busy = 1;
2265
 
2266
         // ...VIA USER FRONTDOOR
2267
         if (map_info.frontdoor != null) begin
2268
            uvm_reg_frontdoor fd = map_info.frontdoor;
2269
            fd.rw_info = rw;
2270
            if (fd.sequencer == null)
2271
              fd.sequencer = system_map.get_sequencer();
2272
            fd.start(fd.sequencer, rw.parent);
2273
         end
2274
 
2275
         // ...VIA BUILT-IN FRONTDOOR
2276
         else begin : built_in_frontdoor
2277
 
2278
            rw.local_map.do_write(rw);
2279
 
2280
         end
2281
 
2282
         m_is_busy = 0;
2283
 
2284
         if (system_map.get_auto_predict()) begin
2285
            uvm_status_e status;
2286
            if (rw.status != UVM_NOT_OK) begin
2287
               sample(value, -1, 0, rw.map);
2288
               m_parent.XsampleX(map_info.offset, 0, rw.map);
2289
            end
2290
 
2291
            status = rw.status; // do_predict will override rw.status, so we save it here
2292
            do_predict(rw, UVM_PREDICT_WRITE);
2293
            rw.status = status;
2294
         end
2295
      end
2296
 
2297
   endcase
2298
 
2299
   value = rw.value[0];
2300
 
2301
   // POST-WRITE CBS - REG
2302
   for (uvm_reg_cbs cb=cbs.first(); cb!=null; cb=cbs.next())
2303
      cb.post_write(rw);
2304
   post_write(rw);
2305
 
2306
   // POST-WRITE CBS - FIELDS
2307
   foreach (m_fields[i]) begin
2308
      uvm_reg_field_cb_iter cbs = new(m_fields[i]);
2309
      uvm_reg_field f = m_fields[i];
2310
 
2311
      rw.element = f;
2312
      rw.element_kind = UVM_FIELD;
2313
      rw.value[0] = (value >> f.get_lsb_pos()) & ((1<
2314
 
2315
      for (uvm_reg_cbs cb=cbs.first(); cb!=null; cb=cbs.next())
2316
         cb.post_write(rw);
2317
      f.post_write(rw);
2318
   end
2319
 
2320
   rw.value[0] = value;
2321
   rw.element = this;
2322
   rw.element_kind = UVM_REG;
2323
 
2324
   // REPORT
2325
   if (uvm_report_enabled(UVM_HIGH, UVM_INFO, "RegModel")) begin
2326
     string path_s,value_s;
2327
     if (rw.path == UVM_FRONTDOOR)
2328
       path_s = (map_info.frontdoor != null) ? "user frontdoor" :
2329
                                               {"map ",rw.map.get_full_name()};
2330
     else
2331
       path_s = (get_backdoor() != null) ? "user backdoor" : "DPI backdoor";
2332
 
2333
     value_s = $sformatf("=0x%0h",rw.value[0]);
2334
 
2335
      uvm_report_info("RegModel", {"Wrote register via ",path_s,": ",
2336
                                   get_full_name(),value_s}, UVM_HIGH);
2337
   end
2338
 
2339
   m_write_in_progress = 1'b0;
2340
 
2341
   XatomicX(0);
2342
 
2343
endtask: do_write
2344
 
2345
// read
2346
 
2347
task uvm_reg::read(output uvm_status_e      status,
2348
                   output uvm_reg_data_t    value,
2349
                   input  uvm_path_e        path = UVM_DEFAULT_PATH,
2350
                   input  uvm_reg_map       map = null,
2351
                   input  uvm_sequence_base parent = null,
2352
                   input  int               prior = -1,
2353
                   input  uvm_object        extension = null,
2354
                   input  string            fname = "",
2355
                   input  int               lineno = 0);
2356
   XatomicX(1);
2357
   XreadX(status, value, path, map, parent, prior, extension, fname, lineno);
2358
   XatomicX(0);
2359
endtask: read
2360
 
2361
 
2362
// XreadX
2363
 
2364
task uvm_reg::XreadX(output uvm_status_e      status,
2365
                     output uvm_reg_data_t    value,
2366
                     input  uvm_path_e        path,
2367
                     input  uvm_reg_map       map,
2368
                     input  uvm_sequence_base parent = null,
2369
                     input  int               prior = -1,
2370
                     input  uvm_object        extension = null,
2371
                     input  string            fname = "",
2372
                     input  int               lineno = 0);
2373
 
2374
   // create an abstract transaction for this operation
2375
   uvm_reg_item rw;
2376
   rw = uvm_reg_item::type_id::create("read_item",,get_full_name());
2377
   rw.element      = this;
2378
   rw.element_kind = UVM_REG;
2379
   rw.kind         = UVM_READ;
2380
   rw.value[0]     = 0;
2381
   rw.path         = path;
2382
   rw.map          = map;
2383
   rw.parent       = parent;
2384
   rw.prior        = prior;
2385
   rw.extension    = extension;
2386
   rw.fname        = fname;
2387
   rw.lineno       = lineno;
2388
 
2389
   do_read(rw);
2390
 
2391
   status = rw.status;
2392
   value = rw.value[0];
2393
 
2394
endtask: XreadX
2395
 
2396
 
2397
// do_read
2398
 
2399
task uvm_reg::do_read(uvm_reg_item rw);
2400
 
2401
   uvm_reg_cb_iter  cbs = new(this);
2402
   uvm_reg_map_info map_info;
2403
   uvm_reg_data_t   value;
2404
   uvm_reg_data_t   exp;
2405
 
2406
   m_fname   = rw.fname;
2407
   m_lineno  = rw.lineno;
2408
 
2409
   if (!Xcheck_accessX(rw,map_info,"read()"))
2410
     return;
2411
 
2412
   m_read_in_progress = 1'b1;
2413
 
2414
   rw.status = UVM_IS_OK;
2415
 
2416
   // PRE-READ CBS - FIELDS
2417
   foreach (m_fields[i]) begin
2418
      uvm_reg_field_cb_iter cbs = new(m_fields[i]);
2419
      uvm_reg_field f = m_fields[i];
2420
      rw.element = f;
2421
      rw.element_kind = UVM_FIELD;
2422
      m_fields[i].pre_read(rw);
2423
      for (uvm_reg_cbs cb=cbs.first(); cb!=null; cb=cbs.next())
2424
         cb.pre_read(rw);
2425
   end
2426
 
2427
   rw.element = this;
2428
   rw.element_kind = UVM_REG;
2429
 
2430
   // PRE-READ CBS - REG
2431
   pre_read(rw);
2432
   for (uvm_reg_cbs cb=cbs.first(); cb!=null; cb=cbs.next())
2433
      cb.pre_read(rw);
2434
 
2435
   if (rw.status != UVM_IS_OK) begin
2436
     m_read_in_progress = 1'b0;
2437
 
2438
     return;
2439
   end
2440
 
2441
   // EXECUTE READ...
2442
   case (rw.path)
2443
 
2444
      // ...VIA USER BACKDOOR
2445
      UVM_BACKDOOR: begin
2446
         uvm_reg_backdoor bkdr = get_backdoor();
2447
 
2448
         uvm_reg_map map = uvm_reg_map::backdoor();
2449
         if (map.get_check_on_read()) exp = get();
2450
 
2451
         if (bkdr != null)
2452
           bkdr.read(rw);
2453
         else
2454
           backdoor_read(rw);
2455
 
2456
         value = rw.value[0];
2457
 
2458
         // Need to clear RC fields, set RS fields and mask WO fields
2459
         if (rw.status != UVM_NOT_OK) begin
2460
 
2461
            uvm_reg_data_t wo_mask;
2462
 
2463
            foreach (m_fields[i]) begin
2464
               string acc = m_fields[i].get_access(uvm_reg_map::backdoor());
2465
               if (acc == "RC" ||
2466
                   acc == "WRC" ||
2467
                   acc == "WSRC" ||
2468
                   acc == "W1SRC" ||
2469
                   acc == "W0SRC") begin
2470
                  value &= ~(((1<
2471
                                          << m_fields[i].get_lsb_pos());
2472
               end
2473
               else if (acc == "RS" ||
2474
                        acc == "WRS" ||
2475
                        acc == "WCRS" ||
2476
                        acc == "W1CRS" ||
2477
                        acc == "W0CRS") begin
2478
                  value |= (((1<
2479
                                          << m_fields[i].get_lsb_pos());
2480
               end
2481
               else if (acc == "WO" ||
2482
                        acc == "WOC" ||
2483
                        acc == "WOS" ||
2484
                        acc == "WO1") begin
2485
                  wo_mask |= ((1<
2486
                                          << m_fields[i].get_lsb_pos();
2487
               end
2488
            end
2489
 
2490
            if (value != rw.value[0]) begin
2491
              uvm_reg_data_t saved;
2492
              saved = rw.value[0];
2493
              rw.value[0] = value;
2494
              if (bkdr != null)
2495
                 bkdr.write(rw);
2496
              else
2497
                 backdoor_write(rw);
2498
              rw.value[0] = saved;
2499
            end
2500
 
2501
            rw.value[0] &= ~wo_mask;
2502
 
2503
            if (map.get_check_on_read() &&
2504
               rw.status != UVM_NOT_OK) begin
2505
               void'(do_check(exp, rw.value[0], map));
2506
            end
2507
 
2508
            do_predict(rw, UVM_PREDICT_READ);
2509
         end
2510
      end
2511
 
2512
 
2513
      UVM_FRONTDOOR: begin
2514
 
2515
         uvm_reg_map system_map = rw.local_map.get_root_map();
2516
 
2517
         m_is_busy = 1;
2518
 
2519
         if (rw.local_map.get_check_on_read()) exp = get();
2520
 
2521
         // ...VIA USER FRONTDOOR
2522
         if (map_info.frontdoor != null) begin
2523
            uvm_reg_frontdoor fd = map_info.frontdoor;
2524
            fd.rw_info = rw;
2525
            if (fd.sequencer == null)
2526
              fd.sequencer = system_map.get_sequencer();
2527
            fd.start(fd.sequencer, rw.parent);
2528
         end
2529
 
2530
         // ...VIA BUILT-IN FRONTDOOR
2531
         else begin
2532
            rw.local_map.do_read(rw);
2533
         end
2534
 
2535
         m_is_busy = 0;
2536
 
2537
         if (system_map.get_auto_predict()) begin
2538
            uvm_status_e status;
2539
            if (rw.local_map.get_check_on_read() &&
2540
                rw.status != UVM_NOT_OK) begin
2541
               void'(do_check(exp, rw.value[0], system_map));
2542
            end
2543
 
2544
            if (rw.status != UVM_NOT_OK) begin
2545
               sample(rw.value[0], -1, 1, rw.map);
2546
               m_parent.XsampleX(map_info.offset, 1, rw.map);
2547
            end
2548
 
2549
            status = rw.status; // do_predict will override rw.status, so we save it here
2550
            do_predict(rw, UVM_PREDICT_READ);
2551
            rw.status = status;
2552
         end
2553
      end
2554
 
2555
   endcase
2556
 
2557
   value = rw.value[0]; // preserve
2558
 
2559
   // POST-READ CBS - REG
2560
   for (uvm_reg_cbs cb = cbs.first(); cb != null; cb = cbs.next())
2561
      cb.post_read(rw);
2562
   post_read(rw);
2563
 
2564
   // POST-READ CBS - FIELDS
2565
   foreach (m_fields[i]) begin
2566
      uvm_reg_field_cb_iter cbs = new(m_fields[i]);
2567
      uvm_reg_field f = m_fields[i];
2568
 
2569
      rw.element = f;
2570
      rw.element_kind = UVM_FIELD;
2571
      rw.value[0] = (value >> f.get_lsb_pos()) & ((1<
2572
 
2573
      for (uvm_reg_cbs cb=cbs.first(); cb!=null; cb=cbs.next())
2574
         cb.post_read(rw);
2575
      f.post_read(rw);
2576
   end
2577
 
2578
   rw.value[0] = value; // restore
2579
   rw.element = this;
2580
   rw.element_kind = UVM_REG;
2581
 
2582
   // REPORT
2583
   if (uvm_report_enabled(UVM_HIGH, UVM_INFO, "RegModel")) begin
2584
     string path_s,value_s;
2585
     if (rw.path == UVM_FRONTDOOR)
2586
       path_s = (map_info.frontdoor != null) ? "user frontdoor" :
2587
                                               {"map ",rw.map.get_full_name()};
2588
     else
2589
       path_s = (get_backdoor() != null) ? "user backdoor" : "DPI backdoor";
2590
 
2591
     value_s = $sformatf("=%0h",rw.value[0]);
2592
 
2593
      uvm_report_info("RegModel", {"Read  register via ",path_s,": ",
2594
                                   get_full_name(),value_s}, UVM_HIGH);
2595
   end
2596
 
2597
   m_read_in_progress = 1'b0;
2598
 
2599
endtask: do_read
2600
 
2601
 
2602
// Xcheck_accessX
2603
 
2604
function bit uvm_reg::Xcheck_accessX (input uvm_reg_item rw,
2605
                                      output uvm_reg_map_info map_info,
2606
                                      input string caller);
2607
 
2608
 
2609
   if (rw.path == UVM_DEFAULT_PATH)
2610
     rw.path = m_parent.get_default_path();
2611
 
2612
   if (rw.path == UVM_BACKDOOR) begin
2613
      if (get_backdoor() == null && !has_hdl_path()) begin
2614
         `uvm_warning("RegModel",
2615
            {"No backdoor access available for register '",get_full_name(),
2616
            "' . Using frontdoor instead."})
2617
         rw.path = UVM_FRONTDOOR;
2618
      end
2619
      else
2620
        rw.map = uvm_reg_map::backdoor();
2621
   end
2622
 
2623
 
2624
   if (rw.path != UVM_BACKDOOR) begin
2625
 
2626
     rw.local_map = get_local_map(rw.map,caller);
2627
 
2628
     if (rw.local_map == null) begin
2629
        `uvm_error(get_type_name(),
2630
           {"No transactor available to physically access register on map '",
2631
            rw.map.get_full_name(),"'"})
2632
        rw.status = UVM_NOT_OK;
2633
        return 0;
2634
     end
2635
 
2636
     map_info = rw.local_map.get_reg_map_info(this);
2637
 
2638
     if (map_info.frontdoor == null && map_info.unmapped) begin
2639
          `uvm_error("RegModel", {"Register '",get_full_name(),
2640
             "' unmapped in map '",
2641
             (rw.map==null)? rw.local_map.get_full_name():rw.map.get_full_name(),
2642
             "' and does not have a user-defined frontdoor"})
2643
          rw.status = UVM_NOT_OK;
2644
          return 0;
2645
     end
2646
 
2647
     if (rw.map == null)
2648
       rw.map = rw.local_map;
2649
   end
2650
   return 1;
2651
endfunction
2652
 
2653
 
2654
// is_busy
2655
 
2656
function bit uvm_reg::is_busy();
2657
   return m_is_busy;
2658
endfunction
2659
 
2660
 
2661
// Xset_busyX
2662
 
2663
function void uvm_reg::Xset_busyX(bit busy);
2664
   m_is_busy = busy;
2665
endfunction
2666
 
2667
 
2668
// Xis_loacked_by_fieldX
2669
 
2670
function bit uvm_reg::Xis_locked_by_fieldX();
2671
  return m_is_locked_by_field;
2672
endfunction
2673
 
2674
 
2675
// backdoor_write
2676
 
2677
task  uvm_reg::backdoor_write(uvm_reg_item rw);
2678
  uvm_hdl_path_concat paths[$];
2679
  bit ok=1;
2680
  get_full_hdl_path(paths,rw.bd_kind);
2681
  foreach (paths[i]) begin
2682
     uvm_hdl_path_concat hdl_concat = paths[i];
2683
     foreach (hdl_concat.slices[j]) begin
2684
        `uvm_info("RegMem", {"backdoor_write to ",
2685
                  hdl_concat.slices[j].path},UVM_DEBUG)
2686
 
2687
        if (hdl_concat.slices[j].offset < 0) begin
2688
           ok &= uvm_hdl_deposit(hdl_concat.slices[j].path,rw.value[0]);
2689
           continue;
2690
        end
2691
        begin
2692
           uvm_reg_data_t slice;
2693
           slice = rw.value[0] >> hdl_concat.slices[j].offset;
2694
           slice &= (1 << hdl_concat.slices[j].size)-1;
2695
           ok &= uvm_hdl_deposit(hdl_concat.slices[j].path, slice);
2696
        end
2697
     end
2698
  end
2699
  rw.status = (ok ? UVM_IS_OK : UVM_NOT_OK);
2700
endtask
2701
 
2702
 
2703
// backdoor_read
2704
 
2705
task  uvm_reg::backdoor_read (uvm_reg_item rw);
2706
  rw.status = backdoor_read_func(rw);
2707
endtask
2708
 
2709
 
2710
// backdoor_read_func
2711
 
2712
function uvm_status_e uvm_reg::backdoor_read_func(uvm_reg_item rw);
2713
  uvm_hdl_path_concat paths[$];
2714
  uvm_reg_data_t val;
2715
  bit ok=1;
2716
  get_full_hdl_path(paths,rw.bd_kind);
2717
  foreach (paths[i]) begin
2718
     uvm_hdl_path_concat hdl_concat = paths[i];
2719
     val = 0;
2720
     foreach (hdl_concat.slices[j]) begin
2721
        `uvm_info("RegMem", {"backdoor_read from %s ",
2722
               hdl_concat.slices[j].path},UVM_DEBUG)
2723
 
2724
        if (hdl_concat.slices[j].offset < 0) begin
2725
           ok &= uvm_hdl_read(hdl_concat.slices[j].path,val);
2726
           continue;
2727
        end
2728
        begin
2729
           uvm_reg_data_t slice;
2730
           int k = hdl_concat.slices[j].offset;
2731
 
2732
           ok &= uvm_hdl_read(hdl_concat.slices[j].path, slice);
2733
 
2734
           repeat (hdl_concat.slices[j].size) begin
2735
              val[k++] = slice[0];
2736
              slice >>= 1;
2737
           end
2738
        end
2739
     end
2740
 
2741
     val &= (1 << m_n_bits)-1;
2742
 
2743
     if (i == 0)
2744
        rw.value[0] = val;
2745
 
2746
     if (val != rw.value[0]) begin
2747
        `uvm_error("RegModel", $sformatf("Backdoor read of register %s with multiple HDL copies: values are not the same: %0h at path '%s', and %0h at path '%s'. Returning first value.",
2748
               get_full_name(),
2749
               rw.value[0], uvm_hdl_concat2string(paths[0]),
2750
               val, uvm_hdl_concat2string(paths[i])));
2751
        return UVM_NOT_OK;
2752
      end
2753
      `uvm_info("RegMem",
2754
         $sformatf("returned backdoor value 0x%0x",rw.value[0]),UVM_DEBUG);
2755
 
2756
  end
2757
 
2758
  rw.status = (ok) ? UVM_IS_OK : UVM_NOT_OK;
2759
  return rw.status;
2760
endfunction
2761
 
2762
 
2763
// poke
2764
 
2765
task uvm_reg::poke(output uvm_status_e      status,
2766
                   input  uvm_reg_data_t    value,
2767
                   input  string            kind = "",
2768
                   input  uvm_sequence_base parent = null,
2769
                   input  uvm_object        extension = null,
2770
                   input  string            fname = "",
2771
                   input  int               lineno = 0);
2772
 
2773
   uvm_reg_backdoor bkdr = get_backdoor();
2774
   uvm_reg_item rw;
2775
 
2776
   m_fname = fname;
2777
   m_lineno = lineno;
2778
 
2779
 
2780
   if (bkdr == null && !has_hdl_path(kind)) begin
2781
      `uvm_error("RegModel",
2782
        {"No backdoor access available to poke register '",get_full_name(),"'"})
2783
      status = UVM_NOT_OK;
2784
      return;
2785
   end
2786
 
2787
   if (!m_is_locked_by_field)
2788
     XatomicX(1);
2789
 
2790
   // create an abstract transaction for this operation
2791
   rw = uvm_reg_item::type_id::create("reg_poke_item",,get_full_name());
2792
   rw.element      = this;
2793
   rw.path         = UVM_BACKDOOR;
2794
   rw.element_kind = UVM_REG;
2795
   rw.kind         = UVM_WRITE;
2796
   rw.bd_kind      = kind;
2797
   rw.value[0]     = value & ((1 << m_n_bits)-1);
2798
   rw.parent       = parent;
2799
   rw.extension    = extension;
2800
   rw.fname        = fname;
2801
   rw.lineno       = lineno;
2802
 
2803
   if (bkdr != null)
2804
     bkdr.write(rw);
2805
   else
2806
     backdoor_write(rw);
2807
 
2808
   status = rw.status;
2809
 
2810
   `uvm_info("RegModel", $sformatf("Poked register \"%s\": 'h%h",
2811
                              get_full_name(), value),UVM_HIGH);
2812
 
2813
   do_predict(rw, UVM_PREDICT_WRITE);
2814
 
2815
   if (!m_is_locked_by_field)
2816
     XatomicX(0);
2817
endtask: poke
2818
 
2819
 
2820
// peek
2821
 
2822
task uvm_reg::peek(output uvm_status_e      status,
2823
                   output uvm_reg_data_t    value,
2824
                   input  string            kind = "",
2825
                   input  uvm_sequence_base parent = null,
2826
                   input  uvm_object        extension = null,
2827
                   input  string            fname = "",
2828
                   input  int               lineno = 0);
2829
 
2830
   uvm_reg_backdoor bkdr = get_backdoor();
2831
   uvm_reg_item rw;
2832
 
2833
   m_fname = fname;
2834
   m_lineno = lineno;
2835
 
2836
   if (bkdr == null && !has_hdl_path(kind)) begin
2837
      `uvm_error("RegModel",
2838
        $sformatf("No backdoor access available to peek register \"%s\"",
2839
                  get_full_name()));
2840
      status = UVM_NOT_OK;
2841
      return;
2842
   end
2843
 
2844
   if(!m_is_locked_by_field)
2845
      XatomicX(1);
2846
 
2847
   // create an abstract transaction for this operation
2848
   rw = uvm_reg_item::type_id::create("mem_peek_item",,get_full_name());
2849
   rw.element      = this;
2850
   rw.path         = UVM_BACKDOOR;
2851
   rw.element_kind = UVM_REG;
2852
   rw.kind         = UVM_READ;
2853
   rw.bd_kind      = kind;
2854
   rw.parent       = parent;
2855
   rw.extension    = extension;
2856
   rw.fname        = fname;
2857
   rw.lineno       = lineno;
2858
 
2859
   if (bkdr != null)
2860
     bkdr.read(rw);
2861
   else
2862
     backdoor_read(rw);
2863
 
2864
   status = rw.status;
2865
   value = rw.value[0];
2866
 
2867
   `uvm_info("RegModel", $sformatf("Peeked register \"%s\": 'h%h",
2868
                          get_full_name(), value),UVM_HIGH);
2869
 
2870
   do_predict(rw, UVM_PREDICT_READ);
2871
 
2872
   if (!m_is_locked_by_field)
2873
      XatomicX(0);
2874
endtask: peek
2875
 
2876
 
2877
// do_check
2878
function bit uvm_reg::do_check(input uvm_reg_data_t expected,
2879
                               input uvm_reg_data_t actual,
2880
                               uvm_reg_map          map);
2881
 
2882
   uvm_reg_data_t  dc = 0;
2883
 
2884
   foreach(m_fields[i]) begin
2885
      string acc = m_fields[i].get_access(map);
2886
      acc = acc.substr(0, 1);
2887
      if (m_fields[i].get_compare() == UVM_NO_CHECK ||
2888
          acc == "WO") begin
2889
         dc |= ((1 << m_fields[i].get_n_bits())-1)
2890
            << m_fields[i].get_lsb_pos();
2891
      end
2892
   end
2893
 
2894
   if ((actual|dc) === (expected|dc)) return 1;
2895
 
2896
   `uvm_error("RegModel", $sformatf("Register \"%s\" value read from DUT (0x%h) does not match mirrored value (0x%h)",
2897
                                    get_full_name(), actual, (expected ^ ('x & dc))));
2898
 
2899
   foreach(m_fields[i]) begin
2900
      string acc = m_fields[i].get_access(map);
2901
      acc = acc.substr(0, 1);
2902
      if (!(m_fields[i].get_compare() == UVM_NO_CHECK ||
2903
            acc == "WO")) begin
2904
         uvm_reg_data_t mask  = ((1 << m_fields[i].get_n_bits())-1);
2905
         uvm_reg_data_t val   = actual   >> m_fields[i].get_lsb_pos() & mask;
2906
         uvm_reg_data_t exp   = expected >> m_fields[i].get_lsb_pos() & mask;
2907
 
2908
         if (val !== exp) begin
2909
            `uvm_info("RegModel",
2910
                      $sformatf("Field %s (%s[%0d:%0d]) mismatch read=%0d'h%0h mirrored=%0d'h%0h ",
2911
                                m_fields[i].get_name(), get_full_name(),
2912
                                m_fields[i].get_lsb_pos() + m_fields[i].get_n_bits() - 1,
2913
                                m_fields[i].get_lsb_pos(),
2914
                                m_fields[i].get_n_bits(), val,
2915
                                m_fields[i].get_n_bits(), exp),
2916
                      UVM_NONE)
2917
         end
2918
      end
2919
   end
2920
 
2921
   return 0;
2922
endfunction
2923
 
2924
 
2925
// mirror
2926
 
2927
task uvm_reg::mirror(output uvm_status_e       status,
2928
                     input  uvm_check_e        check = UVM_NO_CHECK,
2929
                     input  uvm_path_e         path = UVM_DEFAULT_PATH,
2930
                     input  uvm_reg_map        map = null,
2931
                     input  uvm_sequence_base  parent = null,
2932
                     input  int                prior = -1,
2933
                     input  uvm_object         extension = null,
2934
                     input  string             fname = "",
2935
                     input  int                lineno = 0);
2936
   uvm_reg_data_t  v;
2937
   uvm_reg_data_t  exp;
2938
   uvm_reg_backdoor bkdr = get_backdoor();
2939
 
2940
   XatomicX(1);
2941
   m_fname = fname;
2942
   m_lineno = lineno;
2943
 
2944
 
2945
   if (path == UVM_DEFAULT_PATH)
2946
     path = m_parent.get_default_path();
2947
 
2948
   if (path == UVM_BACKDOOR && (bkdr != null || has_hdl_path()))
2949
     map = uvm_reg_map::backdoor();
2950
   else
2951
     map = get_local_map(map, "read()");
2952
 
2953
   if (map == null)
2954
     return;
2955
 
2956
   // Remember what we think the value is before it gets updated
2957
   if (check == UVM_CHECK)
2958
     exp = get_mirrored_value();
2959
 
2960
   XreadX(status, v, path, map, parent, prior, extension, fname, lineno);
2961
 
2962
   if (status == UVM_NOT_OK) begin
2963
      XatomicX(0);
2964
      return;
2965
   end
2966
 
2967
   if (check == UVM_CHECK) void'(do_check(exp, v, map));
2968
 
2969
   XatomicX(0);
2970
endtask: mirror
2971
 
2972
 
2973
// XatomicX
2974
 
2975
task uvm_reg::XatomicX(bit on);
2976
   process m_reg_process;
2977
   m_reg_process=process::self();
2978
 
2979
   if (on) begin
2980
     if (m_reg_process == m_process)
2981
       return;
2982
     m_atomic.get(1);
2983
     m_process = m_reg_process;
2984
   end
2985
   else begin
2986
      // Maybe a key was put back in by a spurious call to reset()
2987
      void'(m_atomic.try_get(1));
2988
      m_atomic.put(1);
2989
      m_process = null;
2990
   end
2991
endtask: XatomicX
2992
 
2993
 
2994
//-------------
2995
// STANDARD OPS
2996
//-------------
2997
 
2998
// convert2string
2999
 
3000
function string uvm_reg::convert2string();
3001
   string res_str;
3002
   string t_str;
3003
   bit with_debug_info;
3004
 
3005
   string prefix;
3006
 
3007
   $sformat(convert2string, "Register %s -- %0d bytes, mirror value:'h%h",
3008
            get_full_name(), get_n_bytes(),get());
3009
 
3010
   if (m_maps.num()==0)
3011
     convert2string = {convert2string, "  (unmapped)\n"};
3012
   else
3013
     convert2string = {convert2string, "\n"};
3014
   foreach (m_maps[map]) begin
3015
     uvm_reg_map parent_map = map;
3016
     int unsigned offset;
3017
     while (parent_map != null) begin
3018
       uvm_reg_map this_map = parent_map;
3019
       parent_map = this_map.get_parent_map();
3020
       offset = parent_map == null ? this_map.get_base_addr(UVM_NO_HIER) :
3021
                                     parent_map.get_submap_offset(this_map);
3022
       prefix = {prefix, "  "};
3023
       begin
3024
            uvm_endianness_e e = this_map.get_endian();
3025
            $sformat(convert2string,
3026
                "%sMapped in '%s' -- %d bytes, %s, offset 'h%0h\n",
3027
                prefix, this_map.get_full_name(), this_map.get_n_bytes(),
3028
                e.name(), offset);
3029
       end
3030
     end
3031
   end
3032
   prefix = "  ";
3033
   foreach(m_fields[i]) begin
3034
      $sformat(convert2string, "%s\n%s", convert2string,
3035
               m_fields[i].convert2string());
3036
   end
3037
 
3038
   if (m_read_in_progress == 1'b1) begin
3039
      if (m_fname != "" && m_lineno != 0)
3040
         $sformat(res_str, "%s:%0d ",m_fname, m_lineno);
3041
      convert2string = {convert2string, "\n", res_str,
3042
                        "currently executing read method"};
3043
   end
3044
   if ( m_write_in_progress == 1'b1) begin
3045
      if (m_fname != "" && m_lineno != 0)
3046
         $sformat(res_str, "%s:%0d ",m_fname, m_lineno);
3047
      convert2string = {convert2string, "\n", res_str,
3048
                        "currently executing write method"};
3049
   end
3050
 
3051
endfunction: convert2string
3052
 
3053
 
3054
// do_print
3055
 
3056
function void uvm_reg::do_print (uvm_printer printer);
3057
  uvm_reg_field f[$];
3058
  super.do_print(printer);
3059
  get_fields(f);
3060
  foreach(f[i]) printer.print_generic(f[i].get_name(),f[i].get_type_name(),-2,f[i].convert2string());
3061
endfunction
3062
 
3063
 
3064
 
3065
// clone
3066
 
3067
function uvm_object uvm_reg::clone();
3068
  `uvm_fatal("RegModel","RegModel registers cannot be cloned")
3069
  return null;
3070
endfunction
3071
 
3072
// do_copy
3073
 
3074
function void uvm_reg::do_copy(uvm_object rhs);
3075
  `uvm_fatal("RegModel","RegModel registers cannot be copied")
3076
endfunction
3077
 
3078
 
3079
// do_compare
3080
 
3081
function bit uvm_reg::do_compare (uvm_object  rhs,
3082
                                        uvm_comparer comparer);
3083
  `uvm_warning("RegModel","RegModel registers cannot be compared")
3084
  return 0;
3085
endfunction
3086
 
3087
 
3088
// do_pack
3089
 
3090
function void uvm_reg::do_pack (uvm_packer packer);
3091
  `uvm_warning("RegModel","RegModel registers cannot be packed")
3092
endfunction
3093
 
3094
 
3095
// do_unpack
3096
 
3097
function void uvm_reg::do_unpack (uvm_packer packer);
3098
  `uvm_warning("RegModel","RegModel registers cannot be unpacked")
3099
endfunction
3100
 
3101
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.