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 void'(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 void'(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 = `VMM_RAL_DATA_WIDTH,
00210 input string domain = "",
00211 input int data_id = -1,
00212 input int scenario_id = -1,
00213 input int stream_id = -1);
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 = `VMM_RAL_DATA_WIDTH,
00247 input string domain = "",
00248 input int data_id = -1,
00249 input int scenario_id = -1,
00250 input int stream_id = -1);
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 = null,
00287 input int n_bits = `VMM_RAL_DATA_WIDTH,
00288 input string domain = "",
00289 input int data_id = -1,
00290 input int scenario_id = -1,
00291 input int stream_id = -1);
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 = null,
00336 input int n_bits = `VMM_RAL_DATA_WIDTH,
00337 input string domain = "",
00338 input int data_id = -1,
00339 input int scenario_id = -1,
00340 input int stream_id = -1);
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 = vmm_ral::DEFAULT,
00407 input string domain = "",
00408 input int data_id = -1,
00409 input int scenario_id = -1,
00410 input int stream_id = -1);
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 = vmm_ral::DEFAULT,
00425 input string domain = "",
00426 input int data_id = -1,
00427 input int scenario_id = -1,
00428 input int stream_id = -1);
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 = vmm_ral::DEFAULT,
00444 input string domain = "",
00445 input int data_id = -1,
00446 input int scenario_id = -1,
00447 input int stream_id =-1);
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 = vmm_ral::DEFAULT,
00463 input string domain = "",
00464 input int data_id = -1,
00465 input int scenario_id = -1,
00466 input int stream_id = -1);
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