blob: 9028e10bbe6bdd278bed62aa0409d9ce88d9faf4 [file]
//
// -------------------------------------------------------------
// Copyright 2004-2008 Synopsys, Inc.
// All Rights Reserved Worldwide
//
// Licensed under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of
// the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in
// writing, software distributed under the License is
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See
// the License for the specific language governing
// permissions and limitations under the License.
// -------------------------------------------------------------
//
`ifndef RVM_RW__SV
`define RVM_RW__SV
`include "vmm.sv"
`ifndef VMM_RW_ADDR_WIDTH
`ifdef VMM_RAL_ADDR_WIDTH
`define VMM_RW_ADDR_WIDTH `VMM_RAL_ADDR_WIDTH
`else
`define VMM_RW_ADDR_WIDTH 64
`endif
`endif
`ifndef VMM_RW_DATA_WIDTH
`ifdef VMM_RAL_DATA_WIDTH
`define VMM_RW_DATA_WIDTH `VMM_RAL_DATA_WIDTH
`else
`define VMM_RW_DATA_WIDTH 64
`endif
`endif
class vmm_rw;
typedef enum {
READ,
WRITE,
EXPECT
} kind_e;
typedef enum {
IS_OK,
ERROR,
RETRY,
TIMEOUT,
`ifdef VMM_RAL_PIPELINED_ACCESS
PENDING,
`endif
HAS_X
} status_e;
endclass: vmm_rw
class vmm_rw_access extends `VMM_DATA;
static vmm_log log = new("vmm_rw_access", "class");
rand vmm_rw::kind_e kind;
rand bit [`VMM_RW_ADDR_WIDTH-1:0] addr;
rand logic [`VMM_RW_DATA_WIDTH-1:0] data;
rand int n_bits = `VMM_RW_DATA_WIDTH;
vmm_rw::status_e status;
constraint valid_vmm_rw_access {
n_bits > 0;
n_bits < `VMM_RW_DATA_WIDTH;
}
extern function new();
extern virtual function string psdisplay(string prefix = "");
endclass: vmm_rw_access
`vmm_channel(vmm_rw_access)
class vmm_rw_burst extends vmm_rw_access;
rand int unsigned n_beats;
rand bit [`VMM_RW_ADDR_WIDTH-1:0] incr_addr;
rand bit [`VMM_RW_ADDR_WIDTH-1:0] max_addr;
rand logic [`VMM_RW_DATA_WIDTH-1:0] data[];
vmm_data user_data;
constraint vmm_rw_burst_valid {
n_beats > 0;
max_addr >= addr;
if (kind == vmm_rw::WRITE || kind == vmm_rw::EXPECT) data.size() == n_beats;
else data.size() == 0;
}
constraint reasonable {
n_beats <= 1024;
incr_addr inside {0, 1, 2, 4, 8, 16, 32};
}
constraint linear {
incr_addr == 1;
max_addr == addr + n_beats - 1;
}
constraint fifo {
incr_addr == 0;
max_addr == addr;
}
constraint wrap {
incr_addr > 0;
max_addr < addr + (n_beats - 1)* incr_addr;
}
function new();
this.linear.constraint_mode(0);
this.fifo.constraint_mode(0);
this.wrap.constraint_mode(0);
endfunction: new
endclass: vmm_rw_burst
typedef class vmm_rw_xactor;
class vmm_rw_xactor_callbacks extends vmm_xactor_callbacks;
virtual task pre_single(vmm_rw_xactor xactor,
vmm_rw_access tr);
endtask
virtual task pre_burst(vmm_rw_xactor xactor,
vmm_rw_burst tr);
endtask
virtual task post_single(vmm_rw_xactor xactor,
vmm_rw_access tr);
endtask
virtual task post_burst(vmm_rw_xactor xactor,
vmm_rw_burst tr);
endtask
endclass: vmm_rw_xactor_callbacks
class vmm_rw_xactor extends `VMM_XACTOR;
typedef enum {BURST_DONE = 99990,
SINGLE_DONE} notifications_e;
vmm_rw_access_channel exec_chan;
extern function new(string name,
string inst,
int stream_id = -1,
vmm_rw_access_channel exec_chan = null);
extern protected virtual task execute_single(vmm_rw_access tr);
extern protected virtual task execute_burst(vmm_rw_burst tr);
extern protected virtual task main();
extern function void reset_xactor(vmm_xactor::reset_e rst_typ = SOFT_RST);
endclass: vmm_rw_xactor
function vmm_rw_access::new();
super.new(this.log);
endfunction: new
function string vmm_rw_access::psdisplay(string prefix = "");
string fmt;
$sformat(fmt, "%0dh", this.n_bits);
$sformat(psdisplay, {"%s%s @ 0x%h = %0d'h%", fmt, "\n"}, prefix,
kind.name(), addr, n_bits, data);
endfunction: psdisplay
function vmm_rw_xactor::new(string name,
string inst,
int stream_id = -1,
vmm_rw_access_channel exec_chan = null);
super.new(name, inst, stream_id);
if (exec_chan == null) exec_chan = new({name, " Input Channel"}, inst);
this.exec_chan = exec_chan;
this.log.is_above(this.exec_chan.log);
void'(this.notify.configure(BURST_DONE));
void'(this.notify.configure(SINGLE_DONE));
endfunction: new
task vmm_rw_xactor::execute_single(vmm_rw_access tr);
`vmm_fatal(this.log, "Undefined execute_single() method in vmm_rw_xactor extension");
endtask: execute_single
task vmm_rw_xactor::execute_burst(vmm_rw_burst tr);
bit [`VMM_RW_ADDR_WIDTH-1:0] addr;
int i;
addr = tr.addr;
i = 0;
tr.status = vmm_rw::IS_OK;
if (tr.kind == vmm_rw::READ) tr.data = new [tr.n_beats];
repeat (tr.n_beats) begin
vmm_rw_access s = new;
s.kind = tr.kind;
s.addr = addr;
if (s.kind != vmm_rw::READ) s.data = tr.data[i++];
this.execute_single(s);
if (s.kind == vmm_rw::READ) tr.data[i++] = s.data;
if (s.status != vmm_rw::IS_OK) begin
tr.status = s.status;
return;
end
addr += tr.incr_addr;
if (addr > tr.max_addr) addr = addr - tr.max_addr + tr.addr;
end
tr.status = vmm_rw::IS_OK;
endtask: execute_burst
task vmm_rw_xactor::main();
vmm_rw_access tr;
vmm_rw_burst br;
fork
super.main();
join_none
forever begin
this.wait_if_stopped_or_empty(this.exec_chan);
`ifdef VMM_RAL_PIPELINED_ACCESS
this.exec_chan.get(tr);
`else
this.exec_chan.activate(tr);
void'(this.exec_chan.start());
`endif
if ($cast(br, tr)) begin
`vmm_callback(vmm_rw_xactor_callbacks,
pre_burst(this, br));
this.execute_burst(br);
`vmm_callback(vmm_rw_xactor_callbacks,
post_burst(this, br));
this.notify.indicate(BURST_DONE, br);
end
else begin
`vmm_callback(vmm_rw_xactor_callbacks, pre_single(this, tr));
this.execute_single(tr);
`ifdef VMM_RAL_PIPELINED_ACCESS
if (tr.status == vmm_rw::PENDING) begin
fork
vmm_rw_access rw = tr;
begin
rw.notify.wait_for(vmm_data::ENDED);
`vmm_callback(vmm_rw_xactor_callbacks,
post_single(this, rw));
this.notify.indicate(SINGLE_DONE, rw);
end
join_none
end
`else
`vmm_callback(vmm_rw_xactor_callbacks,
post_single(this, tr));
this.notify.indicate(SINGLE_DONE, tr);
`endif
end
`ifndef VMM_RAL_PIPELINED_ACCESS
void'(this.exec_chan.complete());
void'(this.exec_chan.remove());
`endif
end
endtask: main
function void vmm_rw_xactor::reset_xactor(vmm_xactor::reset_e rst_typ= SOFT_RST);
vmm_rw_access tr;
super.reset_xactor(rst_typ);
// Force a completion of the transaction to avoid
// leaving the RAL model blocked
tr = this.exec_chan.active_slot();
if (tr != null) begin
tr.status = vmm_rw::RETRY;
void'(this.exec_chan.complete());
void'(this.exec_chan.remove());
end
this.exec_chan.flush();
endfunction: reset_xactor
`endif // RVM_RW__SV