VMM OpenSource - sv/RAL/vmm_ral_tests.sv

sv/RAL/vmm_ral_tests.sv expanded source

00001 // 
00002 // -------------------------------------------------------------
00003 //    Copyright 2004-2008 Synopsys, Inc.
00004 //    All Rights Reserved Worldwide
00005 // 
00006 //    Licensed under the Apache License, Version 2.0 (the
00007 //    "License"); you may not use this file except in
00008 //    compliance with the License.  You may obtain a copy of
00009 //    the License at
00010 // 
00011 //        http://www.apache.org/licenses/LICENSE-2.0
00012 // 
00013 //    Unless required by applicable law or agreed to in
00014 //    writing, software distributed under the License is
00015 //    distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
00016 //    CONDITIONS OF ANY KIND, either express or implied.  See
00017 //    the License for the specific language governing
00018 //    permissions and limitations under the License.
00019 // -------------------------------------------------------------
00020 // 
00021 
00022 
00023 class vmm_ral_tests;
00024 
00025    extern `VMM_STATIC_M task hw_reset(vmm_ral_block blk,
00026                                       string        domain,
00027                                       vmm_log       log);
00028 
00029    extern `VMM_STATIC_M task bit_bash(vmm_ral_block blk,
00030                                       string        domain,
00031                                       vmm_log              log);
00032 
00033    extern `VMM_STATIC_M task mem_walk(vmm_ral_block blk,
00034                                       string        domain,
00035                                       vmm_log       log);
00036 
00037    extern `VMM_STATIC_M task reg_access(vmm_ral_block blk,
00038                                         vmm_log       log);
00039 
00040    extern `VMM_STATIC_M task mem_access(vmm_ral_block blk,
00041                                         vmm_log       log);
00042 
00043    extern `VMM_STATIC_M task shared_access(vmm_ral_block blk,
00044                                            vmm_log       log);
00045 
00046 
00047    extern local `VMM_STATIC_M task bash_kth_bit(vmm_log                       log,
00048                                                 vmm_ral_reg                   regs,
00049                                                 int                           k,
00050                                                 vmm_ral::access_e             mode,
00051                                                 string                        domain,
00052                                                 bit [`VMM_RAL_DATA_WIDTH-1:0] wo_mask);
00053 endclass: vmm_ral_tests
00054 
00055 
00056 task vmm_ral_tests::hw_reset(vmm_ral_block blk,
00057                              string        domain,
00058                              vmm_log       log);
00059    vmm_ral_reg regs[];
00060 
00061    // Iterate over all registers, checking the reset values
00062    blk.get_registers(regs, domain);
00063    foreach (regs[i]) begin
00064       string domains[];
00065 
00066       // Registers with some attributes are not to be tested
00067       if (regs[i].get_attribute("NO_RAL_TESTS") != "" ||
00068 	  regs[i].get_attribute("NO_HW_RESET_TEST") != "") continue;
00069 	
00070       // Registers may be accessible from multiple physical interfaces (domains)
00071       regs[i].get_domains(domains);
00072 
00073       // Verify the initial (reset) value in each domain
00074       foreach (domains[j]) begin
00075          vmm_rw::status_e status;
00076          bit [`VMM_RAL_DATA_WIDTH-1:0] v;
00077       
00078          `vmm_note(log, $psprintf("Verifying reset value of register %s in domain \"%s\"...",
00079                                   regs[i].get_fullname(), domains[j]));
00080 
00081          regs[i].mirror(status, vmm_ral::VERB, vmm_ral::BFM, domains[j]);
00082          if (status != vmm_rw::IS_OK) begin
00083             `vmm_error(log, $psprintf("Status was %s when reading reset value of register \"%s\" through domain \"%s\".",
00084                                       status.name(), regs[i].get_fullname(), domains[j]));
00085          end
00086       end
00087    end
00088 endtask: hw_reset
00089 
00090 
00091 
00092 task vmm_ral_tests::bit_bash(vmm_ral_block blk,
00093                              string        domain,
00094                              vmm_log       log);
00095    vmm_ral_reg regs[];
00096 
00097    // Iterate over all registers, trying to modify read-only bits
00098    // and making sure read-write bits can be set and cleared
00099    blk.get_registers(regs, domain);
00100    foreach (regs[i]) begin
00101       vmm_ral_field fields[];
00102       vmm_ral::access_e mode[`VMM_RAL_DATA_WIDTH];
00103       string domains[];
00104       bit [`VMM_RAL_DATA_WIDTH-1:0] wo_mask;
00105       bit [`VMM_RAL_DATA_WIDTH-1:0] reset_val;
00106       int n_bits;
00107 
00108       // Registers with some attributes are not to be tested
00109       if (regs[i].get_attribute("NO_RAL_TESTS") != "" ||
00110 	  regs[i].get_attribute("NO_BIT_BASH_TEST") != "") continue;
00111 	
00112       n_bits = regs[i].get_n_bytes() * 8;
00113 
00114       // Let's see what kind of bits we have...
00115       regs[i].get_fields(fields);
00116 
00117       // Registers may be accessible from multiple physical interfaces (domains)
00118       regs[i].get_domains(domains);
00119 
00120       // Bash the bits in the register via each domain
00121       foreach (domains[j]) begin
00122          vmm_rw::status_e status;
00123          bit [`VMM_RAL_DATA_WIDTH-1:0] val, exp, v, other;
00124          int next_lsb;
00125 
00126          next_lsb = 0;
00127          wo_mask = '1;
00128          foreach (fields[k]) begin
00129             int lsb, w;
00130 
00131             lsb = fields[k].get_lsb_pos_in_register();
00132             w   = fields[k].get_n_bits();
00133 
00134             // Any unused bits on the right side of the LSB?
00135             while (next_lsb < lsb) begin
00136                mode[next_lsb++] = vmm_ral::RO;
00137             end
00138 
00139             repeat (w) begin
00140                mode[next_lsb] = fields[k].get_access(domains[j]);
00141                if (mode[next_lsb] == vmm_ral::WO) wo_mask[next_lsb] = 1'b0;
00142                next_lsb++;
00143             end
00144          end
00145          // Any unused bits on the left side of the MSB?
00146          while (next_lsb < 64) begin
00147             mode[next_lsb++] = vmm_ral::RO;
00148          end
00149 
00150          `vmm_note(log, $psprintf("Verifying bits in register %s in domain \"%s\"...",
00151                                   regs[i].get_fullname(), domains[j]));
00152 
00153          // The mirror still contains initial value
00154          reset_val = regs[i].get();
00155 
00156          // But the mirrored value of any WO bits will read back
00157          // as all zeroes via the frontdoor...
00158          reset_val &= wo_mask;
00159 
00160          regs[i].read(status, val, vmm_ral::BFM, domains[j]);
00161          if (status != vmm_rw::IS_OK) begin
00162             `vmm_error(log, $psprintf("Status was %s when reading register \"%s\" through domain \"%s\".",
00163                                       status, regs[i].get_fullname(), domains[j]));
00164          end
00165 
00166          if (val !== reset_val) begin
00167             `vmm_error(log, $psprintf("Initial value of register \"%s\" ('h%h) not %s ('h%h)",
00168                                       regs[i].get_fullname(), val,
00169                                       (j == 0) ? "reset value" : "as expected",
00170                                       reset_val));
00171          end
00172 
00173          // Bash the kth bit
00174          other = 0;
00175          for (int k = 0; k < n_bits; k++) begin
00176 
00177             // Cannot test unpredictable bit behavior
00178             if (mode[k] >= vmm_ral::DC) begin
00179                other[k] = 1;
00180                continue;
00181             end
00182 
00183             bash_kth_bit(log, regs[i], k, mode[k], domains[j], wo_mask);
00184          end
00185 
00186          // Write the complement of the reset value
00187          // Except in the "OTHER" and "USERx" bits
00188          val = reset_val ^ ~other;
00189          
00190          regs[i].write(status, val, vmm_ral::BFM, domains[j]);
00191          if (status != vmm_rw::IS_OK) begin
00192             `vmm_error(log, $psprintf("Status was %s when writing to register \"%s\" through domain \"%s\".",
00193                                       status, regs[i].get_fullname(), domains[j]));
00194          end
00195    
00196          exp = regs[i].get() & wo_mask;
00197          regs[i].read(status, v, vmm_ral::BFM, domains[j]);
00198          if (status != vmm_rw::IS_OK) begin
00199             `vmm_error(log, $psprintf("Status was %s when reading register \"%s\" through domain \"%s\".",
00200                                       status, regs[i].get_fullname(), domains[j]));
00201          end
00202    
00203          if (v !== exp) begin
00204             `vmm_error(log, $psprintf("Writing 'h%h to register \"%s\" with initial value 'h%h yielded 'h%h instead of 'h%h",
00205                                       val, regs[i].get_fullname(), reset_val, v, exp));
00206          end
00207       end
00208    end
00209 endtask: bit_bash
00210 
00211 
00212 task vmm_ral_tests::bash_kth_bit(vmm_log                       log,
00213                                  vmm_ral_reg                   regs,
00214                                  int                           k,
00215                                  vmm_ral::access_e             mode,
00216                                  string                        domain,
00217                                  bit [`VMM_RAL_DATA_WIDTH-1:0] wo_mask);
00218    vmm_rw::status_e status;
00219    bit [`VMM_RAL_DATA_WIDTH-1:0] val, exp, v;
00220    bit bit_val;
00221 
00222    `vmm_note(log, $psprintf("...Bashing %s bit #%0d", mode.name(), k));
00223 
00224    repeat (2) begin
00225       val = regs.get();
00226       v   = val;
00227       exp = val;
00228       val[k] = ~val[k];
00229       bit_val = val[k];
00230 
00231       regs.write(status, val, vmm_ral::BFM, domain);
00232       if (status != vmm_rw::IS_OK) begin
00233          `vmm_error(log, $psprintf("Status was %s when writing to register \"%s\" through domain \"%s\".",
00234                                    status, regs.get_fullname(), domain));
00235       end
00236 
00237       exp = regs.get() & wo_mask;
00238       regs.read(status, val, vmm_ral::BFM, domain);
00239       if (status != vmm_rw::IS_OK) begin
00240          `vmm_error(log, $psprintf("Status was %s when reading register \"%s\" through domain \"%s\".",
00241                                    status, regs.get_fullname(), domain));
00242       end
00243    
00244       if (val !== exp) begin
00245          `vmm_error(log, $psprintf("Writing a %b in bit #%0d of register \"%s\" with initial value 'h%h yielded 'h%h instead of 'h%h",
00246                                    bit_val, k, regs.get_fullname(), v, val, exp));
00247       end
00248    end
00249 endtask: bash_kth_bit
00250 
00251 
00252 task vmm_ral_tests::mem_walk(vmm_ral_block blk,
00253                              string        domain,
00254                              vmm_log       log);
00255    vmm_ral_mem mems[];
00256 
00257    // Walk over all RW memories
00258    blk.get_memories(mems, domain);
00259    foreach (mems[i]) begin
00260       vmm_ral::access_e mode;
00261       string domains[];
00262       int n_bits;
00263 
00264       // Memories with some attributes are not to be tested
00265       if (mems[i].get_attribute("NO_RAL_TESTS") != "" ||
00266 	  mems[i].get_attribute("NO_MEM_WALK_TEST") != "") continue;
00267 	
00268       n_bits = mems[i].get_n_bits();
00269 
00270       // Memories may be accessible from multiple physical interfaces (domains)
00271       mems[i].get_domains(domains);
00272 
00273       // Walk the memory via each domain
00274       foreach (domains[j]) begin
00275          vmm_rw::status_e status;
00276          bit [`VMM_RAL_DATA_WIDTH-1:0] val, exp, v;
00277    
00278          // Only deal with RW memories
00279          if (mems[i].get_access(domains[j]) != vmm_ral::RW) continue;
00280 
00281          `vmm_note(log, $psprintf("Walking memory %s in domain \"%s\"...",
00282                                   mems[i].get_fullname(), domains[j]));
00283 
00284          // The walking process is, for address k:
00285          // - Write ~k
00286          // - Read k-1 and expect ~(k-1) if k > 0
00287          // - Write k-1 at k-1
00288          // - Read k and expect ~k if k == last address
00289          for (int k = 0; k < mems[i].get_size(); k++) begin
00290             mems[i].write(status, k, ~k, vmm_ral::BFM, domains[j]);
00291             if (status != vmm_rw::IS_OK) begin
00292                `vmm_error(log, $psprintf("Status was %s when writing \"%s[%0d]\" through domain \"%s\".",
00293                                          status.name(), mems[i].get_fullname(), k, domains[j]));
00294             end
00295 
00296             if (k > 0) begin
00297                mems[i].read(status, k-1, val, vmm_ral::BFM, domains[j]);
00298                if (status != vmm_rw::IS_OK) begin
00299                   `vmm_error(log, $psprintf("Status was %s when reading \"%s[%0d]\" through domain \"%s\".",
00300                                             status.name(), mems[i].get_fullname(), k, domains[j]));
00301                end
00302                else begin
00303                   exp = ~(k-1) & ((1'b1<<n_bits)-1);
00304                   if (val !== exp) begin
00305                      `vmm_error(log, $psprintf("\"%s[%0d-1]\" read back as 'h%h instead of 'h%h.",
00306                                                mems[i].get_fullname(), k, val, exp));
00307 
00308                   end
00309                end
00310 
00311                mems[i].write(status, k-1, k-1, vmm_ral::BFM, domains[j]);
00312                if (status != vmm_rw::IS_OK) begin
00313                   `vmm_error(log, $psprintf("Status was %s when writing \"%s[%0d-1]\" through domain \"%s\".",
00314                                             status.name(), mems[i].get_fullname(), k, domains[j]));
00315                end
00316             end
00317 
00318             if (k == mems[i].get_size() - 1) begin
00319                mems[i].read(status, k, val, vmm_ral::BFM, domains[j]);
00320                if (status != vmm_rw::IS_OK) begin
00321                   `vmm_error(log, $psprintf("Status was %s when reading \"%s[%0d]\" through domain \"%s\".",
00322                                             status.name(), mems[i].get_fullname(), k, domains[j]));
00323                end
00324                else begin
00325                   exp = ~(k) & ((1'b1<<n_bits)-1);
00326                   if (val !== exp) begin
00327                      `vmm_error(log, $psprintf("\"%s[%0d]\" read back as 'h%h instead of 'h%h.",
00328                                                mems[i].get_fullname(), k, val, exp));
00329 
00330                   end
00331                end
00332             end
00333          end
00334       end
00335    end
00336 endtask: mem_walk
00337 
00338 
00339 task vmm_ral_tests::reg_access(vmm_ral_block blk,
00340                                vmm_log       log);
00341    vmm_ral_reg regs[];
00342    bit skip_reg = 0;
00343 
00344    // Iterate over all registers, checking accesses
00345    blk.get_registers(regs);
00346    foreach (regs[i]) begin
00347       string domains[];
00348 
00349       // Registers with some attributes are not to be tested
00350       if (regs[i].get_attribute("NO_RAL_TESTS") != "" ||
00351 	  regs[i].get_attribute("NO_REG_ACCESS_TEST") != "") continue;
00352 
00353       // Can only deal with registers with backdoor access
00354       if (regs[i].get_backdoor() == null) begin
00355          `vmm_warning(log, $psprintf("Register \"%s\" does not have a backdoor mechanism available",
00356                                      regs[i].get_fullname()));
00357          continue;
00358       end
00359 
00360       // Registers may be accessible from multiple physical interfaces (domains)
00361       regs[i].get_domains(domains);
00362 
00363       // Cannot test access if register contains RO or OTHER fields
00364       begin
00365          vmm_ral_field fields[];
00366          regs[i].get_fields(fields);
00367          foreach (fields[j]) begin
00368             foreach (domains[k]) begin
00369                if (fields[j].get_access(domains[k]) == vmm_ral::RO) begin
00370                   `vmm_warning(log, $psprintf("Register \"%s\" has RO bits",
00371                                               regs[i].get_fullname()));
00372                   skip_reg = 1; break;
00373                end
00374                if (fields[j].get_access(domains[k]) >= vmm_ral::OTHER) begin
00375                   `vmm_warning(log, $psprintf("Register \"%s\" has OTHER or USER bits",
00376                                               regs[i].get_fullname()));
00377                   skip_reg = 1; break;
00378                end
00379             end
00380             if (skip_reg == 1) break;
00381          end
00382          if (skip_reg == 1) begin
00383             skip_reg = 0;
00384             continue;
00385          end
00386       end
00387 
00388       // Access each register:
00389       // - Write complement of reset value via front door
00390       // - Read value via backdoor and compare against mirror
00391       // - Write reset value via backdoor
00392       // - Read via front door and compare against mirror
00393       foreach (domains[j]) begin
00394          vmm_rw::status_e status;
00395          bit [`VMM_RAL_DATA_WIDTH-1:0] v, exp;
00396       
00397          `vmm_note(log, $psprintf("Verifying access of register %s in domain \"%s\"...",
00398                                   regs[i].get_fullname(), domains[j]));
00399 
00400          v = regs[i].get();
00401 
00402          regs[i].write(status, ~v, vmm_ral::BFM, domains[j]);
00403          if (status != vmm_rw::IS_OK) begin
00404             `vmm_error(log, $psprintf("Status was %s when writing \"%s\" through domain \"%s\".",
00405                                       status.name(), regs[i].get_fullname(), domains[j]));
00406          end
00407 
00408          regs[i].mirror(status, vmm_ral::VERB, vmm_ral::BACKDOOR);
00409          if (status != vmm_rw::IS_OK) begin
00410             `vmm_error(log, $psprintf("Status was %s when reading reset value of register \"%s\" through backdoor.",
00411                                       status.name(), regs[i].get_fullname()));
00412          end
00413 
00414          regs[i].write(status, v, vmm_ral::BACKDOOR, domains[j]);
00415          if (status != vmm_rw::IS_OK) begin
00416             `vmm_error(log, $psprintf("Status was %s when writing \"%s\" through backdoor.",
00417                                       status.name(), regs[i].get_fullname()));
00418          end
00419 
00420          regs[i].mirror(status, vmm_ral::VERB, vmm_ral::BFM, domains[j]);
00421          if (status != vmm_rw::IS_OK) begin
00422             `vmm_error(log, $psprintf("Status was %s when reading reset value of register \"%s\" through domain \"%s\".",
00423                                       status.name(), regs[i].get_fullname(), domains[j]));
00424          end
00425       end
00426    end
00427 endtask: reg_access
00428 
00429 
00430 task vmm_ral_tests::mem_access(vmm_ral_block blk,
00431                                vmm_log       log);
00432    vmm_ral_mem mems[];
00433 
00434    // Access each location in all memories
00435    blk.get_memories(mems);
00436    foreach (mems[i]) begin
00437       vmm_ral::access_e mode;
00438       string domains[];
00439       int n_bits;
00440 
00441       // Memories with some attributes are not to be tested
00442       if (mems[i].get_attribute("NO_RAL_TESTS") != "" ||
00443 	  mems[i].get_attribute("NO_MEM_ACCESS_TEST") != "") continue;
00444 
00445       // Can only deal with memories with backdoor access
00446       if (mems[i].get_backdoor() == null) begin
00447          `vmm_warning(log, $psprintf("Memory \"%s\" does not have a backdoor mechanism available",
00448                                      mems[i].get_fullname()));
00449          continue;
00450       end
00451 
00452       n_bits = mems[i].get_n_bits();
00453 
00454       // Memories may be accessible from multiple physical interfaces (domains)
00455       mems[i].get_domains(domains);
00456 
00457       // Walk the memory via each domain
00458       foreach (domains[j]) begin
00459          vmm_rw::status_e status;
00460          bit [`VMM_RAL_DATA_WIDTH-1:0] val, exp, v;
00461       
00462          `vmm_note(log, $psprintf("Accessing memory %s in domain \"%s\"...\n",
00463                                   mems[i].get_fullname(), domains[j]));
00464 
00465          mode = mems[i].get_access(domains[j]);
00466 
00467          // The access process is, for address k:
00468          // - Write random value via front door
00469          // - Read via backdoor and expect same random value if RW
00470          // - Write complement of random value via back door
00471          // - Read via front door and expect inverted random value
00472          for (int k = 0; k < mems[i].get_size(); k++) begin
00473             val = $random & ((1'b1<<n_bits)-1);
00474             if (mode == vmm_ral::RO) begin
00475                mems[i].peek(status, k, exp);
00476                if (status != vmm_rw::IS_OK) begin
00477                   `vmm_error(log, $psprintf("Status was %s when reading \"%s[%0d]\" through backdoor.",
00478                                             status.name(), mems[i].get_fullname(), k));
00479                end
00480             end
00481             else exp = val;
00482 
00483             mems[i].write(status, k, val, vmm_ral::BFM, domains[j]);
00484             if (status != vmm_rw::IS_OK) begin
00485                `vmm_error(log, $psprintf("Status was %s when writing \"%s[%0d]\" through domain \"%s\".",
00486                                          status.name(), mems[i].get_fullname(), k, domains[j]));
00487             end
00488 
00489             val = 'x;
00490             mems[i].peek(status, k, val);
00491             if (status != vmm_rw::IS_OK) begin
00492                `vmm_error(log, $psprintf("Status was %s when reading \"%s[%0d]\" through backdoor.",
00493                                          status.name(), mems[i].get_fullname(), k));
00494             end
00495             else begin
00496                if (val !== exp) begin
00497                   `vmm_error(log, $psprintf("Backdoor \"%s[%0d]\" read back as 'h%h instead of 'h%h.",
00498                                             mems[i].get_fullname(), k, val, exp));
00499                end
00500             end
00501 
00502             exp = ~exp & ((1'b1<<n_bits)-1);
00503             mems[i].poke(status, k, exp);
00504             if (status != vmm_rw::IS_OK) begin
00505                `vmm_error(log, $psprintf("Status was %s when writing \"%s[%0d-1]\" through backdoor.",
00506                                          status.name(), mems[i].get_fullname(), k));
00507             end
00508 
00509             mems[i].read(status, k, val, vmm_ral::BFM, domains[j]);
00510             if (status != vmm_rw::IS_OK) begin
00511                `vmm_error(log, $psprintf("Status was %s when reading \"%s[%0d]\" through domain \"%s\".",
00512                                          status.name(), mems[i].get_fullname(), k, domains[j]));
00513             end
00514             else begin
00515                if (mode == vmm_ral::WO) begin
00516                   if (val !== '0) begin
00517                      `vmm_error(log, $psprintf("Front door \"%s[%0d]\" read back as 'h%h instead of 'h%h.",
00518                                                mems[i].get_fullname(), k, val, 0));
00519                   end
00520                end
00521                else begin
00522                   if (val !== exp) begin
00523                      `vmm_error(log, $psprintf("Front door \"%s[%0d]\" read back as 'h%h instead of 'h%h.",
00524                                                mems[i].get_fullname(), k, val, exp));
00525                   end
00526                end
00527             end
00528          end
00529       end
00530    end
00531 endtask: mem_access
00532 
00533 
00534 task vmm_ral_tests::shared_access(vmm_ral_block blk,
00535                                   vmm_log       log);
00536    vmm_ral_reg regs[];
00537    vmm_ral_mem mems[];
00538 
00539    // Iterate over all registers, looking for shared registers
00540    blk.get_registers(regs);
00541    foreach (regs[i]) begin
00542       string domains[];
00543       vmm_ral_field fields[];
00544       bit [`VMM_RAL_DATA_WIDTH-1:0] other_mask;
00545       bit [`VMM_RAL_DATA_WIDTH-1:0] wo_mask[];
00546 
00547       // Registers with some attributes are not to be tested
00548       if (regs[i].get_attribute("NO_RAL_TESTS") != "" ||
00549 	  regs[i].get_attribute("NO_SHARED_ACCESS_TEST") != "") continue;
00550 
00551       // Only look at shared registers
00552       if (regs[i].get_n_domains() < 2) continue;
00553       regs[i].get_domains(domains);
00554 
00555       // Let's see what kind of bits we have...
00556       regs[i].get_fields(fields);
00557 
00558       // Identify unpredictable bits and the ones we shouldn't change
00559       other_mask = 0;
00560       foreach (fields[k]) begin
00561          int lsb, w;
00562 
00563          lsb = fields[k].get_lsb_pos_in_register();
00564          w   = fields[k].get_n_bits();
00565 
00566          if (fields[k].get_access(domains[0]) >= vmm_ral::OTHER) begin
00567             repeat (w) begin
00568                other_mask[lsb++] = 1'b1;
00569             end
00570          end
00571       end
00572 
00573       // WO bits will always readback as 0's but the mirror
00574       // with return what is supposed to have been written
00575       // so we cannot use the mirror-check function
00576       wo_mask = new [domains.size()];
00577       foreach (domains[j]) begin
00578          bit [`VMM_RAL_DATA_WIDTH-1:0] wo;
00579          wo = 0;
00580          foreach (fields[k]) begin
00581             int lsb, w;
00582 
00583             lsb = fields[k].get_lsb_pos_in_register();
00584             w   = fields[k].get_n_bits();
00585 
00586             if (fields[k].get_access(domains[j]) == vmm_ral::WO) begin
00587                repeat (w) begin
00588                   wo[lsb++] = 1'b1;
00589                end
00590             end
00591          end
00592          wo_mask[j] = wo;
00593       end
00594 
00595       // Try to write through each domain
00596       foreach (domains[j]) begin
00597          vmm_rw::status_e status;
00598          bit [`VMM_RAL_DATA_WIDTH-1:0] prev, v;
00599 
00600          // The mirror should contain the initial value
00601          prev = regs[i].get();
00602 
00603          // Write a random value, except in those "don't touch" fields
00604          v = ({$random, $random} & ~other_mask) | (prev & other_mask);
00605 
00606          `vmm_note(log, $psprintf("Writing register %s via domain \"%s\"...",
00607                                   regs[i].get_fullname(), domains[j]));
00608 
00609          `vmm_debug(log, $psprintf("Writing 'h%h over 'h%h", v, prev));
00610 
00611          regs[i].write(status, v, vmm_ral::BFM, domains[j]);
00612          if (status != vmm_rw::IS_OK) begin
00613             `vmm_error(log, $psprintf("Status was %s when writing register \"%s\" through domain \"%s\".",
00614                                       status.name(), regs[i].get_fullname(), domains[j]));
00615          end
00616 
00617          foreach (domains[k]) begin
00618             bit [`VMM_RAL_DATA_WIDTH-1:0] actual, exp;
00619 
00620             `vmm_note(log, $psprintf("Reading register %s via domain \"%s\"...",
00621                                      regs[i].get_fullname(), domains[k]));
00622 
00623             // Was it what we expected?
00624             exp = regs[i].get() & ~wo_mask[k];
00625 
00626             regs[i].read(status, actual, vmm_ral::BFM, domains[k]);
00627             if (status != vmm_rw::IS_OK) begin
00628                `vmm_error(log, $psprintf("Status was %s when reading register \"%s\" through domain \"%s\".",
00629                                          status.name(), regs[i].get_fullname(), domains[k]));
00630             end
00631 
00632             `vmm_debug(log, $psprintf("Read 'h%h, expecting 'h%h",
00633                                       actual, exp));
00634 
00635             if (actual !== exp) begin
00636                `vmm_error(log, $psprintf("Register \"%s\" through domain \"%s\" is 'h%h instead of 'h%h after writing 'h%h via domain \"%s\" over 'h%h.",
00637                                          regs[i].get_fullname(), domains[k],
00638                                          actual, exp, v, domains[j], prev));
00639             end
00640          end
00641       end
00642    end
00643    
00644    // Iterate over all memories, looking for shared ones
00645    blk.get_memories(mems);
00646    foreach (mems[i]) begin
00647       string domains[];
00648       int read_from = -1;
00649 
00650       // Memories with some attributes are not to be tested
00651       if (mems[i].get_attribute("NO_RAL_TESTS") != "" ||
00652 	  mems[i].get_attribute("NO_SHARED_ACCESS_TEST") != "") continue;
00653 
00654       // Only look at shared memories
00655       if (mems[i].get_n_domains() < 2) continue;
00656       mems[i].get_domains(domains);
00657 
00658       // We need at least a backdoor or a domain that can read
00659       // the shared memory
00660       if (mems[i].get_backdoor() == null) begin
00661          foreach (domains[j]) begin
00662             vmm_ral::access_e right;
00663             right = mems[i].get_access(domains[j]);
00664             if (right == vmm_ral::RW ||
00665                 right == vmm_ral::RO) begin
00666                read_from = j;
00667                break;
00668             end
00669          end
00670          if (read_from < 0) begin
00671             `vmm_warning(mems[i].log, "Memory cannot be read from any domains or backdoor. Shared access not verified.");
00672             continue;
00673          end
00674       end
00675 
00676       // Try to write through each domain
00677       foreach (domains[j]) begin
00678 
00679          `vmm_note(log, $psprintf("Writing shared memory \"%s\" via domain \"%s\".",
00680                                   mems[i].get_fullname(), domains[j]));
00681 
00682          // All addresses
00683          for (int offset = 0; offset < mems[i].get_size(); offset++) begin
00684             vmm_rw::status_e status;
00685             bit [`VMM_RAL_DATA_WIDTH-1:0] prev, v;
00686             
00687             // Read the initial value
00688             if (mems[i].get_backdoor() != null) begin
00689                mems[i].peek(status, offset, prev);
00690                if (status != vmm_rw::IS_OK) begin
00691                   `vmm_error(log, $psprintf("Status was %s when reading initial value of \"%s\"[%0d] through backdoor.",
00692                                             status.name(), mems[i].get_fullname(), offset));
00693                end
00694             end
00695             else begin
00696                mems[i].read(status, offset, prev, vmm_ral::BFM, domains[read_from]);
00697                if (status != vmm_rw::IS_OK) begin
00698                   `vmm_error(log, $psprintf("Status was %s when reading initial value of \"%s\"[%0d] through domain \"%s\".",
00699                                             status.name(), mems[i].get_fullname(),
00700                                             offset, domains[read_from]));
00701                end
00702             end
00703             
00704             
00705             // Write a random value,
00706             v = {$random, $random};
00707             
00708             mems[i].write(status, offset, v, vmm_ral::BFM, domains[j]);
00709             if (status != vmm_rw::IS_OK) begin
00710                `vmm_error(log, $psprintf("Status was %s when writing \"%s\"[%0d] through domain \"%s\".",
00711                                          status.name(), mems[i].get_fullname(), offset, domains[j]));
00712             end
00713             
00714             // Read back from all other domains
00715             foreach (domains[k]) begin
00716                bit [`VMM_RAL_DATA_WIDTH-1:0] actual, exp;
00717 
00718                mems[i].read(status, offset, actual, vmm_ral::BFM, domains[k]);
00719                if (status != vmm_rw::IS_OK) begin
00720                   `vmm_error(log, $psprintf("Status was %s when reading %s[%0d] through domain \"%s\".",
00721                                          status.name(), mems[i].get_fullname(), offset, domains[k]));
00722                end
00723 
00724                // Was it what we expected?
00725                exp = v;
00726                if (mems[i].get_access(domains[j]) == vmm_ral::RO) begin
00727                   exp = prev;
00728                end
00729                if (mems[i].get_access(domains[k]) == vmm_ral::WO) begin
00730                   exp = 0;
00731                end
00732                // Trim to number of bits
00733                exp &= (1 << mems[i].get_n_bits()) - 1;
00734                if (actual !== exp) begin
00735                   `vmm_error(log, $psprintf("%s[%0d] through domain \"%s\" is 'h%h instead of 'h%h after writing 'h%h via domain \"%s\" over 'h%h.",
00736                                          mems[i].get_fullname(), offset, domains[k],
00737                                          actual, exp, v, domains[j], prev));
00738                end
00739             end
00740          end
00741       end
00742    end
00743 endtask: shared_access