blob: 2fe174c3273f409776d7589b80e2a7f4cf1e2f9b [file] [log] [blame]
//
// -------------------------------------------------------------
// Copyright 2004-2011 Synopsys, Inc.
// Copyright 2011 Cadence Design Systems, 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.
// -------------------------------------------------------------
//
class wb_driver extends uvm_driver #(wb_cycle);
local int m_max_n_wss;
virtual wb_if.master sigs;
`uvm_component_utils(wb_driver)
function new(string name = "", uvm_component parent = null);
super.new(name, parent);
endfunction
function void bind_vitf(virtual wb_if.master sigs);
this.sigs = sigs;
endfunction
extern virtual task run_phase(uvm_phase phase);
extern protected virtual task read(input bit [63:0] addr,
output bit [63:0] data,
input bit [ 7:0] sel,
input bit [15:0] tgc,
input bit [15:0] tga,
output bit [15:0] tgd,
input bit lock,
output wb_cycle::status_e status);
extern protected virtual task write(input bit [63:0] addr,
input bit [63:0] data,
input bit [ 7:0] sel,
input bit [15:0] tgc,
input bit [15:0] tga,
input bit [15:0] tgd,
input bit lock,
output wb_cycle::status_e status);
extern task reset_wb(int cycles);
endclass: wb_driver
task wb_driver::run_phase(uvm_phase phase);
if (!uvm_config_int::get(this, "", "max_n_wss", this.m_max_n_wss)) begin
this.m_max_n_wss = 10;
end
this.sigs.mck.cyc <= 'b0;
this.sigs.mck.stb <= 'b0;
forever begin
wb_cycle tr;
seq_item_port.get_next_item(tr);
if (tr.m_next_cycle !== wb_cycle::CLASSIC ||
(tr.m_kind !== wb_cycle::READ && tr.m_kind != wb_cycle::WRITE )) begin
`uvm_error("WB_DRIVER", "Only single read/write classic cycles are supported");
tr.m_status = wb_cycle::ERR;
end
else begin
if (tr.m_reset) begin
this.reset_wb(tr.m_data);
end
else
case (tr.m_kind)
wb_cycle::READ : this.read(tr.m_addr, tr.m_data, tr.m_sel,
tr.m_tgc, tr.m_tga, tr.m_tgd, tr.m_lock,
tr.m_status);
wb_cycle::WRITE : this.write(tr.m_addr, tr.m_data, tr.m_sel,
tr.m_tgc, tr.m_tga, tr.m_tgd, tr.m_lock,
tr.m_status);
endcase
end
`uvm_info("WB_DRIVER", {"Transaction Completed:\n", tr.sprint()}, UVM_HIGH);
seq_item_port.item_done();
end
endtask: run_phase
task wb_driver::read(input bit [63:0] addr,
output bit [63:0] data,
input bit [ 7:0] sel,
input bit [15:0] tgc,
input bit [15:0] tga,
output bit [15:0] tgd,
input bit lock,
output wb_cycle::status_e status);
// Section 3.2.1 of Wishbone B3 Specification
@(this.sigs.mck);
// Edge 0
this.sigs.mck.adr <= addr;
this.sigs.mck.tga <= tga;
this.sigs.mck.we <= 1'b0;
this.sigs.mck.sel <= sel;
this.sigs.mck.cyc <= 1'b1;
this.sigs.mck.tgc <= tgc;
this.sigs.mck.stb <= 1'b1;
// Edge 1
status = wb_cycle::TIMEOUT ;
repeat (this.m_max_n_wss + 1) begin
// Wait states
@(this.sigs.mck);
case (1'b1)
this.sigs.mck.err: status = wb_cycle::ERR ;
this.sigs.mck.rty: status = wb_cycle::RTY ;
this.sigs.mck.ack: status = wb_cycle::ACK ;
default: continue;
endcase
break;
end
if (status == wb_cycle::TIMEOUT ) begin
`uvm_error("WB_DRIVER", "Timeout waiting for ACK_I, RTY_I or ERR_I");
end
data = this.sigs.mck.rdat;
tgd = this.sigs.mck.rtgd;
this.sigs.mck.lock <= lock;
this.sigs.mck.cyc <= lock;
endtask: read
task wb_driver::write(input bit [63:0] addr,
input bit [63:0] data,
input bit [ 7:0] sel,
input bit [15:0] tgc,
input bit [15:0] tga,
input bit [15:0] tgd,
input bit lock,
output wb_cycle::status_e status);
// Section 3.2.2 of Wishbone B3 Specification
@(this.sigs.mck);
// Edge 0
this.sigs.mck.adr <= addr;
this.sigs.mck.tga <= tga;
this.sigs.mck.wdat <= data;
this.sigs.mck.wtgd <= tgd;
this.sigs.mck.we <= 1'b1;
this.sigs.mck.sel <= sel;
this.sigs.mck.cyc <= 1'b1;
this.sigs.mck.tgc <= tgc;
this.sigs.mck.stb <= 1'b1;
// Edge 1
status = wb_cycle::TIMEOUT ;
repeat (this.m_max_n_wss + 1) begin
// Wait states
@(this.sigs.mck);
case (1'b1)
this.sigs.mck.err: status = wb_cycle::ERR ;
this.sigs.mck.rty: status = wb_cycle::RTY ;
this.sigs.mck.ack: status = wb_cycle::ACK ;
default: continue;
endcase
break;
end
if (status == wb_cycle::TIMEOUT ) begin
`uvm_error("WB_DRIVER", "Timeout waiting for ACK_I, RTY_I or ERR_I");
end
this.sigs.mck.lock <= lock;
this.sigs.mck.cyc <= lock;
endtask: write
task wb_driver::reset_wb(int cycles);
`uvm_info("WB_DRIVER", $sformatf("Resetting Wishbone for %0d cycles...", cycles), UVM_LOW);
this.sigs.sysck.rst <= 1;
repeat (cycles)
`ifdef QUESTA
@(posedge sigs.sysck);
`else
@(sigs.sysck);
`endif
this.sigs.sysck.rst <= 0;
endtask: reset_wb