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 `ifndef RVM_RW__SV 00024 `define RVM_RW__SV 00025 00026 `include "vmm.sv" 00027 00028 `ifndef VMM_RW_ADDR_WIDTH 00029 `ifdef VMM_RAL_ADDR_WIDTH 00030 `define VMM_RW_ADDR_WIDTH `VMM_RAL_ADDR_WIDTH 00031 `else 00032 `define VMM_RW_ADDR_WIDTH 64 00033 `endif 00034 `endif 00035 `ifndef VMM_RW_DATA_WIDTH 00036 `ifdef VMM_RAL_DATA_WIDTH 00037 `define VMM_RW_DATA_WIDTH `VMM_RAL_DATA_WIDTH 00038 `else 00039 `define VMM_RW_DATA_WIDTH 64 00040 `endif 00041 `endif 00042 00043 00044 class vmm_rw; 00045 typedef enum { 00046 READ, 00047 WRITE, 00048 EXPECT 00049 } kind_e; 00050 00051 typedef enum { 00052 IS_OK, 00053 ERROR, 00054 RETRY 00055 } status_e; 00056 endclass: vmm_rw 00057 00058 00059 class vmm_rw_access extends `VMM_DATA; 00060 static vmm_log log = new("vmm_rw_access", "class"); 00061 00062 rand vmm_rw::kind_e kind; 00063 00064 rand bit [`VMM_RW_ADDR_WIDTH-1:0] addr; 00065 rand logic [`VMM_RW_DATA_WIDTH-1:0] data; 00066 rand int n_bits = `VMM_RW_DATA_WIDTH; 00067 00068 vmm_rw::status_e status; 00069 00070 constraint valid_vmm_rw_access { 00071 n_bits > 0; 00072 n_bits < `VMM_RW_DATA_WIDTH; 00073 } 00074 00075 extern function new(); 00076 extern virtual function string psdisplay(string prefix = ""); 00077 endclass: vmm_rw_access 00078 `vmm_channel(vmm_rw_access) 00079 00080 00081 class vmm_rw_burst extends vmm_rw_access; 00082 rand int unsigned n_beats; 00083 rand bit [`VMM_RW_ADDR_WIDTH-1:0] incr_addr; 00084 rand bit [`VMM_RW_ADDR_WIDTH-1:0] max_addr; 00085 rand logic [`VMM_RW_DATA_WIDTH-1:0] data[]; 00086 vmm_data user_data; 00087 00088 constraint vmm_rw_burst_valid { 00089 n_beats > 0; 00090 max_addr >= addr; 00091 if (kind == vmm_rw::WRITE || kind == vmm_rw::EXPECT) data.size() == n_beats; 00092 else data.size() == 0; 00093 } 00094 00095 constraint reasonable { 00096 n_beats <= 1024; 00097 incr_addr inside {0, 1, 2, 4, 8, 16, 32}; 00098 } 00099 00100 constraint linear { 00101 incr_addr == 1; 00102 max_addr == addr + n_beats - 1; 00103 } 00104 00105 constraint fifo { 00106 incr_addr == 0; 00107 max_addr == addr; 00108 } 00109 00110 constraint wrap { 00111 incr_addr > 0; 00112 max_addr < addr + (n_beats - 1)* incr_addr; 00113 } 00114 00115 function new(); 00116 this.linear.constraint_mode(0); 00117 this.fifo.constraint_mode(0); 00118 this.wrap.constraint_mode(0); 00119 endfunction: new 00120 endclass: vmm_rw_burst 00121 00122 00123 typedef class vmm_rw_xactor; 00124 class vmm_rw_xactor_callbacks extends vmm_xactor_callbacks; 00125 virtual task pre_single(vmm_rw_xactor xactor, 00126 vmm_rw_access tr); 00127 endtask 00128 00129 virtual task pre_burst(vmm_rw_xactor xactor, 00130 vmm_rw_burst tr); 00131 endtask 00132 00133 virtual task post_single(vmm_rw_xactor xactor, 00134 vmm_rw_access tr); 00135 endtask 00136 00137 virtual task post_burst(vmm_rw_xactor xactor, 00138 vmm_rw_burst tr); 00139 endtask 00140 endclass: vmm_rw_xactor_callbacks 00141 00142 00143 class vmm_rw_xactor extends `VMM_XACTOR; 00144 typedef enum {BURST_DONE = 99990, 00145 SINGLE_DONE} notifications_e; 00146 00147 vmm_rw_access_channel exec_chan; 00148 00149 extern function new(string name, 00150 string instance, 00151 int stream_id = -1, 00152 vmm_rw_access_channel exec_chan = null); 00153 00154 extern protected virtual task execute_single(vmm_rw_access tr); 00155 extern protected virtual task execute_burst(vmm_rw_burst tr); 00156 00157 extern protected virtual task main(); 00158 extern function void reset_xactor(reset_e rst_typ = SOFT_RST); 00159 endclass: vmm_rw_xactor 00160 00161 00162 function vmm_rw_access::new(); 00163 super.new(this.log); 00164 endfunction: new 00165 00166 function string vmm_rw_access::psdisplay(string prefix); 00167 string fmt; 00168 $sformat(fmt, "%0dh", this.n_bits); 00169 $sformat(psdisplay, {"%s%s @ 0x%h = %0d'h%", fmt, "\n"}, prefix, 00170 kind.name(), addr, n_bits, data); 00171 endfunction: psdisplay 00172 00173 00174 function vmm_rw_xactor::new(string name, 00175 string instance, 00176 int stream_id, 00177 vmm_rw_access_channel exec_chan); 00178 super.new(name, instance, stream_id); 00179 00180 if (exec_chan == null) exec_chan = new({name, " Input Channel"}, instance); 00181 this.exec_chan = exec_chan; 00182 00183 this.log.is_above(this.exec_chan.log); 00184 00185 this.notify.configure(BURST_DONE); 00186 this.notify.configure(SINGLE_DONE); 00187 endfunction: new 00188 00189 00190 task vmm_rw_xactor::execute_single(vmm_rw_access tr); 00191 `vmm_fatal(this.log, "Undefined execute_single() method in vmm_rw_xactor extension"); 00192 endtask: execute_single 00193 00194 00195 task vmm_rw_xactor::execute_burst(vmm_rw_burst tr); 00196 bit [`VMM_RW_ADDR_WIDTH-1:0] addr; 00197 int i; 00198 00199 addr = tr.addr; 00200 i = 0; 00201 tr.status = vmm_rw::IS_OK; 00202 if (tr.kind == vmm_rw::READ) tr.data = new [tr.n_beats]; 00203 repeat (tr.n_beats) begin 00204 vmm_rw_access s = new; 00205 s.kind = tr.kind; 00206 s.addr = addr; 00207 if (s.kind != vmm_rw::READ) s.data = tr.data[i++]; 00208 this.execute_single(s); 00209 if (s.kind == vmm_rw::READ) tr.data[i++] = s.data; 00210 if (s.status != vmm_rw::IS_OK) begin 00211 tr.status = s.status; 00212 return; 00213 end 00214 00215 addr += tr.incr_addr; 00216 if (addr > tr.max_addr) addr = addr - tr.max_addr + tr.addr; 00217 end 00218 tr.status = vmm_rw::IS_OK; 00219 endtask: execute_burst 00220 00221 00222 task vmm_rw_xactor::main(); 00223 vmm_rw_access tr; 00224 vmm_rw_burst br; 00225 00226 fork 00227 super.main(); 00228 join_none 00229 00230 forever begin 00231 this.wait_if_stopped_or_empty(this.exec_chan); 00232 00233 this.exec_chan.activate(tr); 00234 this.exec_chan.start(); 00235 00236 if ($cast(br, tr)) begin 00237 `vmm_callback(vmm_rw_xactor_callbacks, 00238 pre_burst(this, br)); 00239 this.execute_burst(br); 00240 `vmm_callback(vmm_rw_xactor_callbacks, 00241 post_burst(this, br)); 00242 this.notify.indicate(BURST_DONE, br); 00243 end 00244 else begin 00245 `vmm_callback(vmm_rw_xactor_callbacks, pre_single(this, tr)); 00246 this.execute_single(tr); 00247 `vmm_callback(vmm_rw_xactor_callbacks, 00248 post_single(this, tr)); 00249 this.notify.indicate(SINGLE_DONE, tr); 00250 end 00251 00252 this.exec_chan.complete(); 00253 this.exec_chan.remove(); 00254 end 00255 endtask: main 00256 00257 00258 function void vmm_rw_xactor::reset_xactor(reset_e rst_typ); 00259 vmm_rw_access tr; 00260 00261 super.reset_xactor(rst_typ); 00262 00263 // Force a completion of the transaction to avoid 00264 // leaving the RAL model blocked 00265 tr = this.exec_chan.active_slot(); 00266 if (tr != null) begin 00267 tr.status = vmm_rw::RETRY; 00268 this.exec_chan.complete(); 00269 this.exec_chan.remove(); 00270 end 00271 this.exec_chan.flush(); 00272 endfunction: reset_xactor 00273 00274 `endif // RVM_RW__SV