Add different slave modes to mem_if

This commit is contained in:
Florian Zaruba 2017-05-08 17:02:59 +02:00
parent ba56248f18
commit fc6f5356fb
11 changed files with 91 additions and 39 deletions

View file

@ -8,7 +8,7 @@ library = work
top_level = core_tb
test_top_level = core_tb
# test targets
tests = alu scoreboard fifo mem_arbiter store_queue lsu
tests = alu scoreboard fifo mem_arbiter store_queue lsu core
# UVM agents
agents = include/ariane_pkg.svh $(wildcard tb/agents/*/*.sv)
# path to interfaces
@ -68,7 +68,7 @@ $(tests):
# Optimize top level
vopt${questa_version} ${compile_flag} $@_tb -o $@_tb_optimized +acc -check_synthesis
# vsim${questa_version} $@_tb_optimized
# vsim${questa_version} +UVM_TESTNAME=$@_test -coverage -classdebug $@_tb_optimized
# vsim${questa_version} -c +UVM_TESTNAME=$@_test -coverage -classdebug $@_tb_optimized
vsim${questa_version} +UVM_TESTNAME=$@_test +uvm_set_action="*,_ALL_,UVM_ERROR,UVM_DISPLAY|UVM_STOP" -c -coverage -classdebug -do "coverage save -onexit $@.ucdb; run -a; quit -code [coverage attribute -name TESTSTATUS -concise]" $@_tb_optimized
build-moore:

View file

@ -14,8 +14,13 @@
// University of Bologna.
package mem_if_agent_pkg;
// configure the slave memory interface
// 1. either as a slave with random grant response
// 2. as a master interface making random data requests
// 3. as a slave with no grant randomization
// 4. replay data
typedef enum {
SLAVE, MASTER
SLAVE, SLAVE_REPLAY, SLAVE_NO_RANDOM, MASTER
} mem_if_config;
// Mode of request either read or write
typedef enum {

View file

@ -20,7 +20,8 @@ class mem_if_driver extends uvm_driver #(mem_if_seq_item);
// Virtual Interface
virtual mem_if fu;
// create a 4 kB memory
logic [7:0] rmem [4096];
//---------------------
// Data Members
//---------------------
@ -31,41 +32,47 @@ class mem_if_driver extends uvm_driver #(mem_if_seq_item);
super.new(name, parent);
endfunction
task read_mem(logic [64:0] address, string path);
$readmemh(path, rmem, address);
$display("Read instruction memory file @%0h from %s", address, path);
endtask : read_mem
task run_phase(uvm_phase phase);
mem_if_seq_item cmd;
// --------------
// Slave Port
// --------------
// this driver is configured as a SLAVE
if (m_cfg.mem_if_config == SLAVE) begin
// we serve all requests from the memory file we store in our configuration object
// --------------
// Slave Port
// --------------
logic [7:0] imem [400];
if (m_cfg.mem_if_config inside {SLAVE, SLAVE_REPLAY, SLAVE_NO_RANDOM}) begin
logic [63:0] address [$];
logic [63:0] addr;
logic slave_data_gnt;
semaphore lock = new(1);
slave_data_gnt = 1'b1;
// we serve all requests from the memory file we store in our configuration object
// read memory file
// TODO: get the filename and address from plusarg
if (m_cfg.mem_if_config inside {SLAVE, SLAVE_NO_RANDOM}) begin
read_mem(64'b0, "add_test.v");
end
// grant process is combinatorial
fork
slave_gnt: begin
fu.mck.data_gnt <= 1'b1;
forever begin
// @(fu.mck);
// wait until we got a valid request
// randomize grant delay - the grant may come in the same clock cycle
repeat ($urandom_range(0,3)) @(fu.mck);
fu.mck.data_gnt <= 1'b1;
repeat ($urandom_range(0,3)) @(fu.mck);
fu.mck.data_gnt <= 1'b0;
// now set the grant to one
// if the request is still here go for it
// end else begin
// fu.mck.data_gnt <= 1'b0;
// slave_data_gnt = 1'b0;
// end
// do we have another request?
// we don't to give random grants
// instead we always grant immediately
if (m_cfg.mem_if_config != SLAVE_NO_RANDOM) begin
forever begin
// randomize grant delay - the grant may come in the same clock cycle
repeat ($urandom_range(0,3)) @(fu.mck);
fu.mck.data_gnt <= 1'b1;
repeat ($urandom_range(0,3)) @(fu.mck);
fu.mck.data_gnt <= 1'b0;
end
end
end
slave_serve: begin
@ -84,10 +91,24 @@ class mem_if_driver extends uvm_driver #(mem_if_seq_item);
// we an wait a couple of cycles here
// but at least one
lock.get(1);
repeat ($urandom_range(1,3)) @(fu.mck);
// we give the rvalid in the next cycle if didn't request randomization
if (m_cfg.mem_if_config != SLAVE_NO_RANDOM)
repeat ($urandom_range(1,3)) @(fu.mck);
fu.mck.data_rvalid <= 1'b1;
addr = address.pop_front();
fu.mck.data_rdata <= addr;
// simply replay the address on the data port
if (m_cfg.mem_if_config == SLAVE_REPLAY)
fu.mck.data_rdata <= addr;
else begin
// read from memory
fu.mck.data_rdata <= {
rmem[$unsigned(addr + 3)],
rmem[$unsigned(addr + 2)],
rmem[$unsigned(addr + 1)],
rmem[$unsigned(addr + 0)]
};
end
lock.put(1);
end else
fu.mck.data_rvalid <= 1'b0;
@ -102,11 +123,11 @@ class mem_if_driver extends uvm_driver #(mem_if_seq_item);
join_none
// although no other option exist lets be specific about its purpose
// this is a master interface
// -> this is a master interface
// --------------
// Master Port
// --------------
end else if (m_cfg.mem_if_config == MASTER) begin
// --------------
// Master Port
// --------------
// request a read
// initial statements, sane resets
fu.sck.data_req <= 1'b0;

View file

@ -79,7 +79,7 @@ class mem_if_monitor extends uvm_component;
cmd.be = be.pop_front();
cmd.data = fu.pck.data_rdata;
// was this from a master or slave agent monitor?
cmd.isSlaveAnswer = (m_cfg.mem_if_config == SLAVE) ? 1'b1 : 1'b0;
cmd.isSlaveAnswer = (m_cfg.mem_if_config inside {SLAVE, SLAVE_REPLAY, SLAVE_NO_RANDOM}) ? 1'b1 : 1'b0;
// export the item via the analysis port
$cast(cloned_item, cmd.clone());
m_ap.write(cloned_item);

View file

@ -16,7 +16,7 @@ module core_tb;
logic clk_i;
logic rst_ni;
mem_if #(.DATA_WIDTH(32)) instr_if(clk_i);
mem_if instr_if(clk_i);
mem_if data_if(clk_i);
debug_if debug_if();
core_if core_if(clk_i);
@ -35,10 +35,10 @@ module core_tb;
.instr_if_address_o ( instr_if.address ),
.instr_if_data_req_o ( instr_if.data_req ),
.instr_if_data_be_o ( instr_if.data_be ),
.instr_if_data_be_o ( instr_if.data_be[3:0] ),
.instr_if_data_gnt_i ( instr_if.data_gnt & instr_if.data_req ),
.instr_if_data_rvalid_i ( instr_if.data_rvalid ),
.instr_if_data_rdata_i ( instr_if.data_rdata ),
.instr_if_data_rdata_i ( instr_if.data_rdata[31:0] ),
.data_if_address_o ( data_if.address ),
.data_if_data_wdata_o ( data_if.data_wdata ),
@ -81,6 +81,7 @@ module core_tb;
program testbench (core_if core_if, mem_if instr_if);
initial begin
uvm_config_db #(virtual core_if)::set(null, "uvm_test_top", "core_if", core_if);
uvm_config_db #(virtual mem_if )::set(null, "uvm_test_top", "instr_mem_if", instr_if);
// print the topology
uvm_top.enable_print_topology = 1;
// Start UVM test

View file

@ -23,6 +23,8 @@ class core_env extends uvm_env;
// Data Members
//------------------------------------------
core_if_agent m_core_if_agent;
mem_if_agent m_mem_if_instr_agent;
core_if_sequencer m_core_if_sequencer;
core_env_config m_cfg;
//------------------------------------------
@ -45,6 +47,15 @@ class core_env extends uvm_env;
m_cfg.m_core_if_agent_config);
m_core_if_agent = core_if_agent::type_id::create("m_core_if_agent", this);
uvm_config_db #(core_if_agent_config)::set(this, "m_core_if_agent*",
"core_if_agent_config",
m_cfg.m_core_if_agent_config);
// get instruction memory interface
m_mem_if_instr_agent = mem_if_agent::type_id::create("m_mem_if_instr_agent", this);
uvm_config_db #(mem_if_agent_config)::set(this, "m_mem_if_instr_agent*",
"mem_if_agent_config",
m_cfg.m_instr_if_agent_config);
// Get sequencer
m_core_if_sequencer = core_if_sequencer::type_id::create("m_core_if_sequencer", this);

View file

@ -21,9 +21,11 @@ class core_env_config extends uvm_object;
// a functional unit master interface
virtual core_if m_core_if;
virtual mem_if m_instr_mem_if;
// an agent config
core_if_agent_config m_core_if_agent_config;
mem_if_agent_config m_instr_if_agent_config;
endclass : core_env_config

View file

@ -19,6 +19,7 @@ package core_env_pkg;
`include "uvm_macros.svh"
// Testbench related imports
import core_if_agent_pkg::*;
import mem_if_agent_pkg::*;
// Includes for the config for the environment
`include "core_env_config.svh"
// Includes the environment

View file

@ -18,8 +18,9 @@ package core_lib_pkg;
// Standard UVM import & include:
import uvm_pkg::*;
`include "uvm_macros.svh"
// Import the memory interface agent
// Import the core and memory interface agent
import core_if_agent_pkg::*;
import mem_if_agent_pkg::*;
// ------------------------------------------------
// Environment which will be instantiated
// ------------------------------------------------

View file

@ -38,7 +38,7 @@ class core_test_base extends uvm_test;
// ---------------------
// functional unit interface
core_if_agent_config m_core_if_cfg;
mem_if_agent_config m_instr_mem_if_cfg;
//------------------------------------------
// Methods
//------------------------------------------
@ -57,12 +57,22 @@ class core_test_base extends uvm_test;
// create agent core_if configuration
m_core_if_cfg = core_if_agent_config::type_id::create("m_core_if_cfg");
m_env_cfg.m_core_if_agent_config = m_core_if_cfg;
m_instr_mem_if_cfg = mem_if_agent_config::type_id::create("m_instr_mem_if_cfg");
// configure the instruction interface as a slave device
m_instr_mem_if_cfg.mem_if_config = SLAVE_NO_RANDOM;
m_env_cfg.m_instr_if_agent_config = m_instr_mem_if_cfg;
// get core_if virtual interfaces
// get master interface DB
if (!uvm_config_db #(virtual core_if)::get(this, "", "core_if", m_core_if_cfg.m_vif))
`uvm_fatal("VIF CONFIG", "Cannot get() interface core_if from uvm_config_db. Have you set() it?")
m_env_cfg.m_core_if = m_core_if_cfg.m_vif;
uvm_config_db #(int)::dump();
if (!uvm_config_db #(virtual mem_if)::get(this, "", "instr_mem_if", m_instr_mem_if_cfg.fu))
`uvm_fatal("VIF CONFIG", "Cannot get() interface mem_if from uvm_config_db. Have you set() it?")
m_env_cfg.m_instr_mem_if = m_instr_mem_if_cfg.fu;
// create environment
uvm_config_db #(core_env_config)::set(this, "*", "core_env_config", m_env_cfg);

View file

@ -57,7 +57,7 @@ class mem_arbiter_test_base extends uvm_test;
// create a slave configuration
m_cfg_slave = mem_if_agent_config::type_id::create("m_cfg_slave");
m_env_cfg.m_mem_if_slave_agent = m_cfg_slave;
m_env_cfg.m_mem_if_slave_agent.mem_if_config = SLAVE;
m_env_cfg.m_mem_if_slave_agent.mem_if_config = SLAVE_REPLAY;
// create agent memory master configuration
m_cfg_masters[0] = mem_if_agent_config::type_id::create("m_cfg_master0");