Add dcache interface as an agent

This commit is contained in:
Florian Zaruba 2017-05-29 14:46:32 +02:00
parent f081730042
commit 91a887da47
10 changed files with 498 additions and 17 deletions

View file

@ -0,0 +1,64 @@
// Author: Florian Zaruba, ETH Zurich
// Date: 29.05.2017
// Description: DCache interface
//
// Copyright (C) 2017 ETH Zurich, University of Bologna
// All rights reserved.
//
// This code is under development and not yet released to the public.
// Until it is released, the code is under the copyright of ETH Zurich and
// the University of Bologna, and may contain confidential and/or unpublished
// work. Any reuse/redistribution is strictly forbidden without written
// permission from ETH Zurich.
//
// Bug fixes and contributions will eventually be released under the
// SolderPad open hardware license in the context of the PULP platform
// (http://www.pulp-platform.org), under the copyright of ETH Zurich and the
// University of Bologna.
//
// Guard statement proposed by "Easier UVM" (doulos)
`ifndef DCACHE_IF_SV
`define DCACHE_IF_SV
interface dcache_if
(
input clk
);
wire [11:0] address_index; // Index portion of address
wire [43:0] address_tag; // Tag portion of the address
wire [63:0] data_wdata; // Data to be written
wire data_req; // Requests read data
wire data_gnt; // Request has been granted, signals can be changed as
// soon as request has been granted
wire kill_req; // Request to kill the previous request
wire tag_valid; // The tag (or kill request) is valid
wire data_rvalid; // Read data is valid
wire [63:0] data_rdata; // Read data
wire data_we; // Write enable
wire [7:0] data_be; // Byte enable
clocking mck @(posedge clk);
input address_index, address_tag, data_wdata, data_we, data_req, kill_req, tag_valid, data_be;
output data_rvalid, data_rdata, data_gnt;
endclocking
// Memory interface configured as slave
clocking sck @(posedge clk);
output address_index, address_tag, data_wdata, data_we, data_req, kill_req, tag_valid, data_be;
input data_rvalid, data_rdata, data_gnt;
endclocking
clocking pck @(posedge clk);
// default input #1ns output #1ns;
input address_index, address_tag, data_wdata, data_req, data_we, data_be, kill_req, tag_valid,
data_gnt, data_rvalid, data_rdata;
endclocking
modport master (
clocking mck
);
modport slave (
clocking sck
);
endinterface
`endif

View file

@ -0,0 +1,57 @@
// Author: Florian Zaruba, ETH Zurich
// Date: 29.05.2017
// Description: Main agent object dcache_if. Builds and instantiates the appropriate
// subcomponents like the monitor, driver etc. all based on the
// agent configuration object.
// Copyright (C) 2017 ETH Zurich, University of Bologna
// All rights reserved.
// This code is under development and not yet released to the public.
// Until it is released, the code is under the copyright of ETH Zurich and
// the University of Bologna, and may contain confidential and/or unpublished
// work. Any reuse/redistribution is strictly forbidden without written
// permission from ETH Zurich.
// Bug fixes and contributions will eventually be released under the
// SolderPad open hardware license in the context of the PULP platform
// (http://www.pulp-platform.org), under the copyright of ETH Zurich and the
// University of Bologna.
class dcache_if_agent extends uvm_component;
// UVM Factory Registration Macro
`uvm_component_utils(dcache_if_agent)
//------------------------------------------
// Data Members
//------------------------------------------
dcache_if_agent_config m_cfg;
//------------------------------------------
// Component Members
//------------------------------------------
uvm_analysis_port #(dcache_if_seq_item) ap;
dcache_if_driver m_driver;
dcache_if_monitor m_monitor;
dcache_if_sequencer m_sequencer;
//------------------------------------------
// Methods
//------------------------------------------
// Standard UVM Methods:
function new(string name = "dcache_if_agent", uvm_component parent = null);
super.new(name, parent);
endfunction : new
function void build_phase(uvm_phase phase);
if (!uvm_config_db #(dcache_if_agent_config)::get(this, "", "dcache_if_agent_config", m_cfg) )
`uvm_fatal("CONFIG_LOAD", "Cannot get() configuration dcache_if_agent_config from uvm_config_db. Have you set() it?")
m_driver = dcache_if_driver::type_id::create("m_driver", this);
m_sequencer = dcache_if_sequencer::type_id::create("m_sequencer", this);
m_monitor = dcache_if_monitor::type_id::create("m_monitor", this);
endfunction : build_phase
function void connect_phase(uvm_phase phase);
m_driver.seq_item_port.connect(m_sequencer.seq_item_export);
// m_monitor.ap.connect(m_cov_monitor.analysis_port)
m_driver.m_cfg = m_cfg;
m_monitor.m_cfg = m_cfg;
endfunction: connect_phase
endclass : dcache_if_agent

View file

@ -0,0 +1,37 @@
// Author: Florian Zaruba, ETH Zurich
// Date: 29.05.2017
// Description: Agent configuration object dcache_if
// Copyright (C) 2017 ETH Zurich, University of Bologna
// All rights reserved.
// This code is under development and not yet released to the public.
// Until it is released, the code is under the copyright of ETH Zurich and
// the University of Bologna, and may contain confidential and/or unpublished
// work. Any reuse/redistribution is strictly forbidden without written
// permission from ETH Zurich.
// Bug fixes and contributions will eventually be released under the
// SolderPad open hardware license in the context of the PULP platform
// (http://www.pulp-platform.org), under the copyright of ETH Zurich and the
// University of Bologna.
class dcache_if_agent_config extends uvm_object;
// UVM Factory Registration Macro
`uvm_object_utils(dcache_if_agent_config)
// Virtual Interface
virtual dcache_if m_vif;
//------------------------------------------
// Data Members
//------------------------------------------
// Is the agent active or passive
uvm_active_passive_enum active = UVM_ACTIVE;
// Standard UVM Methods:
function new(string name = "dcache_if_agent_config");
super.new(name);
endfunction : new
endclass : dcache_if_agent_config

View file

@ -0,0 +1,37 @@
// Author: Florian Zaruba, ETH Zurich
// Date: 29.05.2017
// Description: dcache_if_agent package - compile unit
// Copyright (C) 2017 ETH Zurich, University of Bologna
// All rights reserved.
// This code is under development and not yet released to the public.
// Until it is released, the code is under the copyright of ETH Zurich and
// the University of Bologna, and may contain confidential and/or unpublished
// work. Any reuse/redistribution is strictly forbidden without written
// permission from ETH Zurich.
// Bug fixes and contributions will eventually be released under the
// SolderPad open hardware license in the context of the PULP platform
// (http://www.pulp-platform.org), under the copyright of ETH Zurich and the
// University of Bologna.
package dcache_if_agent_pkg;
// UVM Import
import uvm_pkg::*;
`include "uvm_macros.svh"
// Sequence item to model transactions
`include "dcache_if_seq_item.svh"
// Agent configuration object
`include "dcache_if_agent_config.svh"
// Driver
`include "dcache_if_driver.svh"
// Coverage monitor
// `include "dcache_if_coverage_monitor.svh"
// Monitor that includes analysis port
`include "dcache_if_monitor.svh"
// Sequencer
`include "dcache_if_sequencer.svh"
// Main agent
`include "dcache_if_agent.svh"
// Sequence
`include "dcache_if_sequence.svh"
endpackage: dcache_if_agent_pkg

View file

@ -0,0 +1,47 @@
// Author: Florian Zaruba, ETH Zurich
// Date: 29.05.2017
// Description: Driver for interface dcache_if
// Copyright (C) 2017 ETH Zurich, University of Bologna
// All rights reserved.
// This code is under development and not yet released to the public.
// Until it is released, the code is under the copyright of ETH Zurich and
// the University of Bologna, and may contain confidential and/or unpublished
// work. Any reuse/redistribution is strictly forbidden without written
// permission from ETH Zurich.
// Bug fixes and contributions will eventually be released under the
// SolderPad open hardware license in the context of the PULP platform
// (http://www.pulp-platform.org), under the copyright of ETH Zurich and the
// University of Bologna.
class dcache_if_driver extends uvm_driver #(dcache_if_seq_item);
// UVM Factory Registration Macro
`uvm_component_utils(dcache_if_driver)
// Virtual Interface
virtual dcache_if m_vif;
//---------------------
// Data Members
//---------------------
dcache_if_agent_config m_cfg;
// Standard UVM Methods:
function new(string name = "dcache_if_driver", uvm_component parent = null);
super.new(name, parent);
endfunction
task run_phase(uvm_phase phase);
dcache_if_seq_item cmd;
seq_item_port.get_next_item(cmd);
seq_item_port.item_done();
endtask : run_phase
function void build_phase(uvm_phase phase);
if (!uvm_config_db #(dcache_if_agent_config)::get(this, "", "dcache_if_agent_config", m_cfg) )
`uvm_fatal("CONFIG_LOAD", "Cannot get() configuration dcache_if_agent_config from uvm_config_db. Have you set() it?")
m_vif = m_cfg.m_vif;
endfunction: build_phase
endclass : dcache_if_driver

View file

@ -0,0 +1,62 @@
// Author: Florian Zaruba, ETH Zurich
// Date: 29.05.2017
// Description: dcache_if Monitor, monitors the DUT's pins and writes out
// appropriate sequence items as defined for this particular dut
//
// Copyright (C) 2017 ETH Zurich, University of Bologna
// All rights reserved.
// This code is under development and not yet released to the public.
// Until it is released, the code is under the copyright of ETH Zurich and
// the University of Bologna, and may contain confidential and/or unpublished
// work. Any reuse/redistribution is strictly forbidden without written
// permission from ETH Zurich.
// Bug fixes and contributions will eventually be released under the
// SolderPad open hardware license in the context of the PULP platform
// (http://www.pulp-platform.org), under the copyright of ETH Zurich and the
// University of Bologna.
class dcache_if_monitor extends uvm_component;
// UVM Factory Registration Macro
`uvm_component_utils(dcache_if_monitor)
// analysis port
uvm_analysis_port #(dcache_if_seq_item) m_ap;
// Virtual Interface
virtual dcache_if m_vif;
//---------------------
// Data Members
//---------------------
dcache_if_agent_config m_cfg;
// Standard UVM Methods:
function new(string name = "dcache_if_driver", uvm_component parent = null);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
if (!uvm_config_db #(dcache_if_agent_config)::get(this, "", "dcache_if_agent_config", m_cfg) )
`uvm_fatal("CONFIG_LOAD", "Cannot get() configuration dcache_if_agent_config from uvm_config_db. Have you set() it?")
m_ap = new("m_ap", this);
endfunction: build_phase
function void connect_phase(uvm_phase phase);
// connect virtual interface
m_vif = m_cfg.m_vif;
endfunction
task run_phase(uvm_phase phase);
dcache_if_seq_item cmd = dcache_if_seq_item::type_id::create("cmd");
dcache_if_seq_item cloned_item;
$cast(cloned_item, cmd.clone());
m_ap.write(cloned_item);
endtask : run_phase
endclass : dcache_if_monitor

View file

@ -0,0 +1,89 @@
// Author: Florian Zaruba, ETH Zurich
// Date: 29.05.2017
// Description: dcache_if Sequence item
//
// Copyright (C) 2017 ETH Zurich, University of Bologna
// All rights reserved.
// This code is under development and not yet released to the public.
// Until it is released, the code is under the copyright of ETH Zurich and
// the University of Bologna, and may contain confidential and/or unpublished
// work. Any reuse/redistribution is strictly forbidden without written
// permission from ETH Zurich.
// Bug fixes and contributions will eventually be released under the
// SolderPad open hardware license in the context of the PULP platform
// (http://www.pulp-platform.org), under the copyright of ETH Zurich and the
// University of Bologna.
class dcache_if_seq_item extends uvm_sequence_item;
// UVM Factory Registration Macro
`uvm_object_utils(dcache_if_seq_item)
//------------------------------------------
// Data Members (Outputs rand, inputs non-rand)
//------------------------------------------
// TODO: set data members
//------------------------------------------
// Methods
//------------------------------------------
// Standard UVM Methods:
function new(string name = "dcache_if_seq_item");
super.new(name);
endfunction
function void do_copy(uvm_object rhs);
dcache_if_seq_item rhs_;
if(!$cast(rhs_, rhs)) begin
`uvm_fatal("do_copy", "cast of rhs object failed")
end
super.do_copy(rhs);
// Copy over data members:
// e.g.:
// operator = rhs_.operator;
endfunction:do_copy
function bit do_compare(uvm_object rhs, uvm_comparer comparer);
dcache_if_seq_item rhs_;
if(!$cast(rhs_, rhs)) begin
`uvm_error("do_copy", "cast of rhs object failed")
return 0;
end
// TODO
return super.do_compare(rhs, comparer); // && operator == rhs_.operator
endfunction:do_compare
function string convert2string();
string s;
$sformat(s, "%s\n", super.convert2string());
// Convert to string function reusing s:
// TODO
// $sformat(s, "%s\n operator\n", s, operator);
return s;
endfunction:convert2string
function void do_print(uvm_printer printer);
if(printer.knobs.sprint == 0) begin
$display(convert2string());
end
else begin
printer.m_string = convert2string();
end
endfunction:do_print
function void do_record(uvm_recorder recorder);
super.do_record(recorder);
// Use the record macros to record the item fields:
// TODO
// `uvm_record_field("operator", operator)
endfunction:do_record
endclass : dcache_if_seq_item

View file

@ -0,0 +1,53 @@
// Author: Florian Zaruba, ETH Zurich
// Date: 29.05.2017
// Description: dcache_if sequence consisting of dcache_if_sequence_items
//
// Copyright (C) 2017 ETH Zurich, University of Bologna
// All rights reserved.
// This code is under development and not yet released to the public.
// Until it is released, the code is under the copyright of ETH Zurich and
// the University of Bologna, and may contain confidential and/or unpublished
// work. Any reuse/redistribution is strictly forbidden without written
// permission from ETH Zurich.
// Bug fixes and contributions will eventually be released under the
// SolderPad open hardware license in the context of the PULP platform
// (http://www.pulp-platform.org), under the copyright of ETH Zurich and the
// University of Bologna.
class dcache_if_sequence extends uvm_sequence #(dcache_if_seq_item);
// UVM Factory Registration Macro
`uvm_object_utils(dcache_if_sequence)
//-----------------------------------------------
// Data Members (Outputs rand, inputs non-rand)
//-----------------------------------------------
//------------------------------------------
// Constraints
//------------------------------------------
//------------------------------------------
// Methods
//------------------------------------------
// Standard UVM Methods:
function new(string name = "dcache_if_sequence");
super.new(name);
endfunction
task body;
dcache_if_seq_item req;
begin
req = dcache_if_seq_item::type_id::create("req");
start_item(req);
assert(req.randomize());
finish_item(req);
end
endtask:body
endclass : dcache_if_sequence

View file

@ -0,0 +1,29 @@
// Author: Florian Zaruba, ETH Zurich
// Date: 29.05.2017
// Description: dcache_if Sequencer for dcache_if_sequence_item
//
// Copyright (C) 2017 ETH Zurich, University of Bologna
// All rights reserved.
// This code is under development and not yet released to the public.
// Until it is released, the code is under the copyright of ETH Zurich and
// the University of Bologna, and may contain confidential and/or unpublished
// work. Any reuse/redistribution is strictly forbidden without written
// permission from ETH Zurich.
// Bug fixes and contributions will eventually be released under the
// SolderPad open hardware license in the context of the PULP platform
// (http://www.pulp-platform.org), under the copyright of ETH Zurich and the
// University of Bologna.
class dcache_if_sequencer extends uvm_sequencer #(dcache_if_seq_item);
// UVM Factory Registration Macro
`uvm_component_utils(dcache_if_sequencer)
// Standard UVM Methods:
function new(string name="dcache_if_sequencer", uvm_component parent = null);
super.new(name, parent);
endfunction
endclass: dcache_if_sequencer

View file

@ -26,8 +26,8 @@ module mem_arbiter_tb;
logic rst_ni, clk;
mem_if master[3](clk);
mem_if slave(clk);
dcache_if master[3](clk);
dcache_if slave(clk);
// super hack in assigning the wire a value
// we need to keep all interface signals as wire as
// the simulator does not now if this interface will be used
@ -42,23 +42,29 @@ module mem_arbiter_tb;
.rst_ni ( rst_ni ),
.flush_i ( 1'b0 ),
.address_index_o ( slave.address ),
.address_index_o ( slave.address_index ),
.address_tag_o ( slave.address_tag ),
.data_wdata_o ( slave.data_wdata ),
.data_req_o ( slave.data_req ),
.data_we_o ( slave.data_we ),
.data_be_o ( slave.data_be ),
.tag_valid_o ( slave.tag_valid ),
.kill_req_o ( slave.kill_req ),
.data_gnt_i ( slave.data_req & slave.data_gnt ),
.data_rvalid_i ( slave.data_rvalid ),
.data_rdata_i ( slave.data_rdata ),
.address_index_i ( {master[2].address, master[1].address, master[0].address} ),
.data_wdata_i ( {master[2].data_wdata, master[1].data_wdata, master[0].data_wdata} ),
.data_req_i ( {master[2].data_req, master[1].data_req, master[0].data_req} ),
.data_we_i ( {master[2].data_we, master[1].data_we, master[0].data_we} ),
.data_be_i ( {master[2].data_be, master[1].data_be, master[0].data_be} ),
.data_gnt_o ( {master[2].data_gnt, master[1].data_gnt, master[0].data_gnt} ),
.data_rvalid_o ( {master[2].data_rvalid, master[1].data_rvalid, master[0].data_rvalid} ),
.data_rdata_o ( {master[2].data_rdata, master[1].data_rdata, master[0].data_rdata} )
.address_index_i ( {master[2].address_index, master[1].address_index, master[0].address_index} ),
.address_tag_i ( {master[2].address_tag, master[1].address_tag, master[0].address_tag} ),
.data_wdata_i ( {master[2].data_wdata, master[1].data_wdata, master[0].data_wdata} ),
.data_req_i ( {master[2].data_req, master[1].data_req, master[0].data_req} ),
.data_we_i ( {master[2].data_we, master[1].data_we, master[0].data_we} ),
.data_be_i ( {master[2].data_be, master[1].data_be, master[0].data_be} ),
.tag_valid_i ( {master[2].tag_valid, master[1].tag_valid, master[0].tag_valid} ),
.kill_req_i ( {master[2].kill_req, master[1].kill_req, master[0].kill_req} ),
.data_gnt_o ( {master[2].data_gnt, master[1].data_gnt, master[0].data_gnt} ),
.data_rvalid_o ( {master[2].data_rvalid, master[1].data_rvalid, master[0].data_rvalid} ),
.data_rdata_o ( {master[2].data_rdata, master[1].data_rdata, master[0].data_rdata} )
);
initial begin
@ -72,17 +78,17 @@ module mem_arbiter_tb;
#10ns clk = ~clk;
end
program testbench (mem_if master[3], mem_if slave);
program testbench (dcache_if master[3], dcache_if slave);
initial begin
// register the memory interface
uvm_config_db #(virtual mem_if)::set(null, "uvm_test_top", "mem_if_slave", slave);
uvm_config_db #(virtual mem_if)::set(null, "uvm_test_top", "mem_if_master0", master[0]);
uvm_config_db #(virtual mem_if)::set(null, "uvm_test_top", "mem_if_master1", master[1]);
uvm_config_db #(virtual mem_if)::set(null, "uvm_test_top", "mem_if_master2", master[2]);
// uvm_config_db #(virtual mem_if)::set(null, "uvm_test_top", "mem_if_slave", slave);
// uvm_config_db #(virtual mem_if)::set(null, "uvm_test_top", "mem_if_master0", master[0]);
// uvm_config_db #(virtual mem_if)::set(null, "uvm_test_top", "mem_if_master1", master[1]);
// uvm_config_db #(virtual mem_if)::set(null, "uvm_test_top", "mem_if_master2", master[2]);
// print the topology
uvm_top.enable_print_topology = 1;
// Start UVM test
run_test();
// run_test();
end
endprogram