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_access extends `VMM_XACTOR; 00024 vmm_ral::path_e default_path = vmm_ral::BFM; // Cannot be "DEFAULT" 00025 00026 protected vmm_ral_block_or_sys model; 00027 00028 protected vmm_rw_xactor rw_exec[string]; // One per domain 00029 00030 extern function new(); 00031 00032 extern function void set_model(vmm_ral_block_or_sys model); 00033 extern function vmm_ral_block_or_sys get_model(); 00034 extern function void add_xactor(vmm_rw_xactor xact, 00035 string domain = ""); 00036 00037 extern task write(output vmm_rw::status_e status, 00038 input bit [`VMM_RAL_ADDR_WIDTH-1:0] addr, 00039 input bit [`VMM_RAL_DATA_WIDTH-1:0] data, 00040 input int n_bits = `VMM_RAL_DATA_WIDTH, 00041 input string domain = "", 00042 input int data_id = -1, 00043 input int scenario_id = -1, 00044 input int stream_id = -1); 00045 00046 extern task read(output vmm_rw::status_e status, 00047 input bit [`VMM_RAL_ADDR_WIDTH-1:0] addr, 00048 output bit [`VMM_RAL_DATA_WIDTH-1:0] data, 00049 input int n_bits = `VMM_RAL_DATA_WIDTH, 00050 input string domain = "", 00051 input int data_id = -1, 00052 input int scenario_id = -1, 00053 input int stream_id = -1); 00054 00055 extern task burst_write(output vmm_rw::status_e status, 00056 input bit [`VMM_RAL_ADDR_WIDTH-1:0] start, 00057 input bit [`VMM_RAL_ADDR_WIDTH-1:0] incr, 00058 input bit [`VMM_RAL_ADDR_WIDTH-1:0] max, 00059 input bit [`VMM_RAL_DATA_WIDTH-1:0] data[], 00060 input vmm_data user = null, 00061 input int n_bits = `VMM_RAL_DATA_WIDTH, 00062 input string domain = "", 00063 input int data_id = -1, 00064 input int scenario_id = -1, 00065 input int stream_id = -1); 00066 00067 extern task burst_read(output vmm_rw::status_e status, 00068 input bit [`VMM_RAL_ADDR_WIDTH-1:0] start, 00069 input bit [`VMM_RAL_ADDR_WIDTH-1:0] incr, 00070 input bit [`VMM_RAL_ADDR_WIDTH-1:0] max, 00071 input int n_beats, 00072 output bit [`VMM_RAL_DATA_WIDTH-1:0] data[], 00073 input vmm_data user = null, 00074 input int n_bits = `VMM_RAL_DATA_WIDTH, 00075 input string domain = "", 00076 input int data_id = -1, 00077 input int scenario_id = -1, 00078 input int stream_id = -1); 00079 00080 extern virtual function bit set_by_name(input string name, 00081 input bit [`VMM_RAL_DATA_WIDTH-1:0] value); 00082 extern virtual function bit get_by_name(input string name, 00083 output bit [`VMM_RAL_DATA_WIDTH-1:0] value); 00084 00085 extern task write_by_name(output vmm_rw::status_e status, 00086 input string name, 00087 input bit [`VMM_RAL_DATA_WIDTH-1:0] data, 00088 input vmm_ral::path_e path = vmm_ral::DEFAULT, 00089 input string domain = "", 00090 input int data_id = -1, 00091 input int scenario_id = -1, 00092 input int stream_id = -1); 00093 00094 extern task read_by_name(output vmm_rw::status_e status, 00095 input string name, 00096 output bit [`VMM_RAL_DATA_WIDTH-1:0] data, 00097 input vmm_ral::path_e path = vmm_ral::DEFAULT, 00098 input string domain = "", 00099 input int data_id = -1, 00100 input int scenario_id = -1, 00101 input int stream_id = -1); 00102 00103 extern task write_mem_by_name(output vmm_rw::status_e status, 00104 input string name, 00105 input bit [`VMM_RAL_ADDR_WIDTH-1:0] offset, 00106 input bit [`VMM_RAL_DATA_WIDTH-1:0] data, 00107 input vmm_ral::path_e path = vmm_ral::DEFAULT, 00108 input string domain = "", 00109 input int data_id = -1, 00110 input int scenario_id = -1, 00111 input int stream_id = -1); 00112 00113 extern task read_mem_by_name(output vmm_rw::status_e status, 00114 input string name, 00115 input bit [`VMM_RAL_ADDR_WIDTH-1:0] offset, 00116 output bit [`VMM_RAL_DATA_WIDTH-1:0] data, 00117 input vmm_ral::path_e path = vmm_ral::DEFAULT, 00118 input string domain = "", 00119 input int data_id = -1, 00120 input int scenario_id = -1, 00121 input int stream_id = -1); 00122 00123 /*local*/ extern function int 00124 Xget_physical_addressesX(bit [`VMM_RAL_ADDR_WIDTH-1:0] base_addr, 00125 bit [`VMM_RAL_ADDR_WIDTH-1:0] mem_offset, 00126 int unsigned n_bytes, 00127 vmm_ral_block_or_sys in_block, 00128 string domain, 00129 ref bit [`VMM_RAL_ADDR_WIDTH-1:0] addr[]); 00130 endclass: vmm_ral_access 00131 00132 00133 function vmm_ral_access::new(); 00134 super.new("RVM RAL Access", "Main"); 00135 endfunction: new 00136 00137 00138 function void vmm_ral_access::set_model(vmm_ral_block_or_sys model); 00139 if (this.model != null) begin 00140 `vmm_error(this.log, "A RAL abstraction model has already been associated with this RAL access interface"); 00141 return; 00142 end 00143 00144 this.model = model; 00145 00146 // Register this RAL access object with the RAL model 00147 model.Xregister_ral_accessX(this); 00148 endfunction: set_model 00149 00150 00151 function vmm_ral_block_or_sys vmm_ral_access::get_model(); 00152 get_model = this.model; 00153 endfunction: get_model 00154 00155 00156 function void vmm_ral_access::add_xactor(vmm_rw_xactor xact, 00157 string domain); 00158 if (this.model == null) begin 00159 `vmm_error(this.log, "A RAL abstraction model has not yet been associated with this RAL access interface"); 00160 return; 00161 end 00162 00163 // Check if the specified domain matches a domain in the model 00164 begin 00165 string domains[]; 00166 bit found = 0; 00167 00168 model.get_domains(domains); 00169 foreach (domains[i]) begin 00170 if (domains[i] == domain) begin 00171 found = 1; 00172 break; 00173 end 00174 end 00175 if (!found) begin 00176 `vmm_error(this.log, $psprintf("Domain \"%s\" does not exist in RAL model", 00177 domain)); 00178 if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::ERROR_SEV)) begin 00179 string msg; 00180 this.log.text($psprintf("Domain \"%s\" does not exist in RAL model \"%s\"", 00181 domain, this.model.get_name())); 00182 msg = "Available domains are:"; 00183 foreach (domains[i]) begin 00184 $sformat(msg, "%s \"%s\"", msg, domains[i]); 00185 end 00186 this.log.text(msg); 00187 this.log.end_msg(); 00188 end 00189 return; 00190 end 00191 end 00192 00193 if (this.rw_exec.exists(domain)) begin 00194 `vmm_error(this.log, $psprintf("Transactor for domain \"%s\" already exists", 00195 domain)); 00196 end 00197 else begin 00198 this.rw_exec[domain] = xact; 00199 00200 // Make sure transactor is started 00201 xact.start_xactor(); 00202 end 00203 endfunction: add_xactor 00204 00205 00206 task vmm_ral_access::write(output vmm_rw::status_e status, 00207 input bit [`VMM_RAL_ADDR_WIDTH-1:0] addr, 00208 input bit [`VMM_RAL_DATA_WIDTH-1:0] data, 00209 input int n_bits, 00210 input string domain, 00211 input int data_id, 00212 input int scenario_id, 00213 input int stream_id); 00214 status = vmm_rw::ERROR; 00215 00216 if (!this.rw_exec.exists(domain)) begin 00217 `vmm_error(this.log, $psprintf("No transactor available to physically access domain \"%s\".", 00218 domain)); 00219 return; 00220 end 00221 00222 `vmm_trace(this.log, $psprintf("Writing 'h%h at 'h%h via domain \"%s\"...", 00223 data, addr, domain)); 00224 00225 begin 00226 vmm_rw_access rw = new; 00227 00228 rw.data_id = data_id; 00229 rw.scenario_id = scenario_id; 00230 rw.stream_id = stream_id; 00231 00232 rw.kind = vmm_rw::WRITE; 00233 rw.addr = addr; 00234 rw.data = data; 00235 rw.n_bits = n_bits; 00236 this.rw_exec[domain].exec_chan.put(rw); 00237 00238 status = rw.status; 00239 end 00240 endtask: write 00241 00242 00243 task vmm_ral_access::read(output vmm_rw::status_e status, 00244 input bit [`VMM_RAL_ADDR_WIDTH-1:0] addr, 00245 output bit [`VMM_RAL_DATA_WIDTH-1:0] data, 00246 input int n_bits, 00247 input string domain, 00248 input int data_id, 00249 input int scenario_id, 00250 input int stream_id); 00251 status = vmm_rw::ERROR; 00252 00253 if (!this.rw_exec.exists(domain)) begin 00254 `vmm_error(this.log, $psprintf("No transactor available to physically access domain \"%s\".", 00255 domain)); 00256 return; 00257 end 00258 00259 begin 00260 vmm_rw_access rw = new; 00261 00262 rw.data_id = data_id; 00263 rw.scenario_id = scenario_id; 00264 rw.stream_id = stream_id; 00265 00266 rw.kind = vmm_rw::READ; 00267 rw.addr = addr; 00268 rw.n_bits = n_bits; 00269 this.rw_exec[domain].exec_chan.put(rw); 00270 00271 data = rw.data; 00272 status = rw.status; 00273 end 00274 00275 `vmm_trace(this.log, $psprintf("Read 'h%h from 'h%h via domain \"%s\"...", 00276 data, addr, domain)); 00277 00278 endtask: read 00279 00280 00281 task vmm_ral_access::burst_write(output vmm_rw::status_e status, 00282 input bit [`VMM_RAL_ADDR_WIDTH-1:0] start, 00283 input bit [`VMM_RAL_ADDR_WIDTH-1:0] incr, 00284 input bit [`VMM_RAL_ADDR_WIDTH-1:0] max, 00285 input bit [`VMM_RAL_DATA_WIDTH-1:0] data[], 00286 input vmm_data user, 00287 input int n_bits, 00288 input string domain, 00289 input int data_id, 00290 input int scenario_id, 00291 input int stream_id); 00292 status = vmm_rw::ERROR; 00293 00294 if (!this.rw_exec.exists(domain)) begin 00295 `vmm_error(this.log, $psprintf("No transactor available to physically access domain \"%s\".", 00296 domain)); 00297 return; 00298 end 00299 00300 begin 00301 vmm_rw_burst rw = new; 00302 00303 rw.data_id = data_id; 00304 rw.scenario_id = scenario_id; 00305 rw.stream_id = stream_id; 00306 00307 rw.kind = vmm_rw::WRITE; 00308 rw.addr = start; 00309 rw.incr_addr = incr; 00310 rw.max_addr = max; 00311 rw.n_beats = data.size(); 00312 rw.n_bits = n_bits; 00313 rw.user_data = user; 00314 00315 rw.data = new [rw.n_beats]; 00316 foreach (data[i]) rw.data[i] = data[i]; 00317 00318 this.rw_exec[domain].exec_chan.put(rw); 00319 00320 status = rw.status; 00321 end 00322 00323 `vmm_trace(this.log, $psprintf("Burst-wrote %0d data from ['h%h+'h%h %%'h%h] via domain \"%s\"...", 00324 data.size(), start, incr, max, domain)); 00325 00326 endtask: burst_write 00327 00328 00329 task vmm_ral_access::burst_read(output vmm_rw::status_e status, 00330 input bit [`VMM_RAL_ADDR_WIDTH-1:0] start, 00331 input bit [`VMM_RAL_ADDR_WIDTH-1:0] incr, 00332 input bit [`VMM_RAL_ADDR_WIDTH-1:0] max, 00333 input int n_beats, 00334 output bit [`VMM_RAL_DATA_WIDTH-1:0] data[], 00335 input vmm_data user, 00336 input int n_bits, 00337 input string domain, 00338 input int data_id, 00339 input int scenario_id, 00340 input int stream_id); 00341 status = vmm_rw::ERROR; 00342 00343 if (!this.rw_exec.exists(domain)) begin 00344 `vmm_error(this.log, $psprintf("No transactor available to physically access domain \"%s\".", 00345 domain)); 00346 return; 00347 end 00348 00349 begin 00350 vmm_rw_burst rw = new; 00351 00352 rw.data_id = data_id; 00353 rw.scenario_id = scenario_id; 00354 rw.stream_id = stream_id; 00355 00356 rw.kind = vmm_rw::READ; 00357 rw.addr = start; 00358 rw.incr_addr = incr; 00359 rw.max_addr = max; 00360 rw.n_beats = n_beats; 00361 rw.n_bits = n_bits; 00362 rw.user_data = user; 00363 00364 this.rw_exec[domain].exec_chan.put(rw); 00365 00366 data = new [rw.data.size()]; 00367 foreach (data[i]) data[i] = rw.data[i]; 00368 status = rw.status; 00369 end 00370 00371 `vmm_trace(this.log, $psprintf("Burst-read %0d data from ['h%h+'h%h %%'h%h] via domain \"%s\"...", 00372 data.size(), start, incr, max, domain)); 00373 00374 endtask: burst_read 00375 00376 00377 function bit vmm_ral_access::set_by_name(string name, 00378 bit [`VMM_RAL_DATA_WIDTH-1:0] value); 00379 vmm_ral_reg rg; 00380 00381 set_by_name = 0; 00382 rg = this.model.get_reg_by_name(name); 00383 if (rg == null) return 0; 00384 00385 rg.set(value); 00386 set_by_name = 1; 00387 endfunction: set_by_name 00388 00389 00390 function bit vmm_ral_access::get_by_name(input string name, 00391 output bit [`VMM_RAL_DATA_WIDTH-1:0] value); 00392 vmm_ral_reg rg; 00393 00394 get_by_name = 0; 00395 rg = this.model.get_reg_by_name(name); 00396 if (rg == null) return 0; 00397 00398 value = rg.get(); 00399 get_by_name = 1; 00400 endfunction: get_by_name 00401 00402 00403 task vmm_ral_access::write_by_name(output vmm_rw::status_e status, 00404 input string name, 00405 input bit [`VMM_RAL_DATA_WIDTH-1:0] data, 00406 input vmm_ral::path_e path, 00407 input string domain, 00408 input int data_id, 00409 input int scenario_id, 00410 input int stream_id); 00411 vmm_ral_reg rg; 00412 00413 status = vmm_rw::ERROR; 00414 rg = this.model.get_reg_by_name(name); 00415 if (rg == null) return; 00416 00417 rg.write(status, data, path, domain, data_id, scenario_id, stream_id); 00418 endtask: write_by_name 00419 00420 00421 task vmm_ral_access::read_by_name(output vmm_rw::status_e status, 00422 input string name, 00423 output bit [`VMM_RAL_DATA_WIDTH-1:0] data, 00424 input vmm_ral::path_e path, 00425 input string domain, 00426 input int data_id, 00427 input int scenario_id, 00428 input int stream_id); 00429 vmm_ral_reg rg; 00430 00431 status = vmm_rw::ERROR; 00432 rg = this.model.get_reg_by_name(name); 00433 if (rg == null) return; 00434 00435 rg.read(status, data, path, domain, data_id, scenario_id, stream_id); 00436 endtask: read_by_name 00437 00438 00439 task vmm_ral_access::write_mem_by_name(output vmm_rw::status_e status, 00440 input string name, 00441 input bit [`VMM_RAL_ADDR_WIDTH-1:0] offset, 00442 input bit [`VMM_RAL_DATA_WIDTH-1:0] data, 00443 input vmm_ral::path_e path, 00444 input string domain, 00445 input int data_id, 00446 input int scenario_id, 00447 input int stream_id); 00448 vmm_ral_mem mem; 00449 00450 status = vmm_rw::ERROR; 00451 mem = this.model.get_mem_by_name(name); 00452 if (mem == null) return; 00453 00454 mem.write(status, offset, data, path, domain, data_id, scenario_id, stream_id); 00455 endtask: write_mem_by_name 00456 00457 00458 task vmm_ral_access::read_mem_by_name(output vmm_rw::status_e status, 00459 input string name, 00460 input bit [`VMM_RAL_ADDR_WIDTH-1:0] offset, 00461 output bit [`VMM_RAL_DATA_WIDTH-1:0] data, 00462 input vmm_ral::path_e path, 00463 input string domain, 00464 input int data_id, 00465 input int scenario_id, 00466 input int stream_id); 00467 vmm_ral_mem mem; 00468 00469 status = vmm_rw::ERROR; 00470 mem = this.model.get_mem_by_name(name); 00471 if (mem == null) return; 00472 00473 mem.read(status, offset, data, path, domain, data_id, scenario_id, stream_id); 00474 endtask: read_mem_by_name 00475 00476 00477 // 00478 // Identify the sequence of addresses that must be accessed physically 00479 // to access the specified number of bytes at the specified address 00480 // within the specified block or system. Returns the number of bytes 00481 // of valid data in each access. 00482 // 00483 // Returns a list of address in little endian order, with the granularity 00484 // of the top-level system 00485 // 00486 // A register is specified as a base address with mem_indx == 0. 00487 // A location within a memory is specified as an index from a base address. 00488 // 00489 function int vmm_ral_access::Xget_physical_addressesX(bit [`VMM_RAL_ADDR_WIDTH-1:0] base_addr, 00490 bit [`VMM_RAL_ADDR_WIDTH-1:0] mem_offset, 00491 int unsigned n_bytes, 00492 vmm_ral_block_or_sys in_block, 00493 string domain, 00494 ref bit [`VMM_RAL_ADDR_WIDTH-1:0] addr[]); 00495 int bus_width = in_block.get_n_bytes(domain); 00496 bit [`VMM_RAL_ADDR_WIDTH-1:0] local_addr[]; 00497 vmm_ral_block_or_sys parent = in_block.get_parent(); 00498 00499 addr = new [0]; 00500 00501 if (n_bytes <= 0) begin 00502 `vmm_fatal(this.log, $psprintf("Cannot access %0d bytes. Must be greater than 0", 00503 n_bytes)); 00504 return 0; 00505 end 00506 00507 // First, identify the addresses within the block/system 00508 if (n_bytes <= bus_width) begin 00509 local_addr = new [1]; 00510 local_addr[0] = base_addr + mem_offset; 00511 end else begin 00512 int n; 00513 00514 n = ((n_bytes-1) / bus_width) + 1; 00515 local_addr = new [n]; 00516 00517 base_addr = base_addr + mem_offset * n; 00518 00519 case (in_block.get_endian(domain)) 00520 vmm_ral::LITTLE_ENDIAN: begin 00521 foreach (local_addr[i]) begin 00522 local_addr[i] = base_addr + i; 00523 end 00524 end 00525 vmm_ral::BIG_ENDIAN: begin 00526 foreach (local_addr[i]) begin 00527 n--; 00528 local_addr[i] = base_addr + n; 00529 end 00530 end 00531 vmm_ral::LITTLE_FIFO: begin 00532 foreach (local_addr[i]) begin 00533 local_addr[i] = base_addr; 00534 end 00535 end 00536 vmm_ral::BIG_FIFO: begin 00537 foreach (local_addr[i]) begin 00538 local_addr[i] = base_addr; 00539 end 00540 end 00541 default: begin 00542 `vmm_error(this.log, $psprintf("Block has no specified endianness. Cannot access %0d bytes register via its %0d byte \"%s\" interface", 00543 n_bytes, in_block.get_n_bytes(domain), domain)); 00544 end 00545 endcase 00546 end 00547 00548 00549 // Then translate these addresses in the parent's space 00550 if (parent == null) begin 00551 // This is the top-most system/block! 00552 addr = new [local_addr.size()] (local_addr); 00553 end else begin 00554 bit [`VMM_RAL_ADDR_WIDTH-1:0] sys_addr[]; 00555 bit [`VMM_RAL_ADDR_WIDTH-1:0] base_addr; 00556 string up_domain; 00557 int w, k; 00558 00559 up_domain = in_block.get_parent_domain(domain); 00560 00561 // Scale the consecutive local address in the system's granularity 00562 if (bus_width < parent.get_n_bytes(up_domain)) k = 1; 00563 else k = ((bus_width-1) / parent.get_n_bytes(up_domain)) + 1; 00564 00565 base_addr = in_block.get_base_addr(domain); 00566 foreach (local_addr[i]) begin 00567 int n = addr.size(); 00568 00569 w = this.Xget_physical_addressesX(base_addr + local_addr[i] * k, 0, 00570 bus_width, parent, up_domain, 00571 sys_addr); 00572 00573 addr = new [n + sys_addr.size()] (addr); 00574 foreach (sys_addr[j]) begin 00575 addr[n+j] = sys_addr[j]; 00576 end 00577 end 00578 // The width of each access is the minimum of this block or the system's width 00579 if (w < bus_width) bus_width = w; 00580 end 00581 00582 Xget_physical_addressesX = bus_width; 00583 endfunction: Xget_physical_addressesX