VMM OpenSource - sv/RAL/vmm_rw.sv

sv/RAL/vmm_rw.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 `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