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