EDA Playground lets you type in and run HDL code (using a selection of free and commercial simulators and synthesizers).
It's great for learning HDLs, it's great for testing out unfamiliar things and it's great for sharing code.
You can start typing straight away. But to run your code, you'll need to sign or log in. Logging in with a Google account gives you access to all non-commercial simulators and some commercial simulators:
To run commercial simulators, you need to register and log in with a username and password. Registration is free, and only pre-approved email's will have access to the commercial simulators.
208
`include "uvm_macros.svh"
import uvm_pkg::*;
//////////////////////transaction class//////////////////////
class transaction extends uvm_sequence_item;
`uvm_object_utils( transaction )
bit [7 : 0] paddr;
bit [7 : 0] pwdata;
bit pwrite;
bit [7 : 0] prdata;
function new(string name = "transaction");
super.new(name);
endfunction
/***constraint c_paddr {
paddr inside {8'hF0, 8'hE0, 8'hE1, 8'hE2, 8'hE3, 8'hD0, 8'hD1, 8'hD2, 8'hD3};
}***/
/*** constraint c_paddr {
paddr inside {8'hF0};
} ***/
endclass
//////////////////////Driver//////////////////////
class driver extends uvm_driver #(transaction);
`uvm_component_utils(driver)
virtual top_if vif;
transaction tr;
function new(string name = "driver", uvm_component parent = null);
super.new(name, parent);
endfunction
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
if(!uvm_config_db#(virtual top_if)::get(this, "", "vif", vif))
`uvm_error("DRV", "Error getting Interface Handle")
endfunction
/////write data to dut -> psel -> pen
virtual task write();
vif.presetn <=0;
#5 vif.presetn <=1;
@(posedge vif.pclk);
vif.paddr <= tr.paddr;
vif.pwdata <= tr.pwdata;
vif.pwrite <= 1'b1;
vif.psel <= 1'b1;
@(posedge vif.pclk);
vif.penable <= 1'b1;
//@(posedge vif.pclk);
//vif.pwrite <= 1'b1;
`uvm_info("DRV", $sformatf("Mode :Write | WDATA : %0d ADDR : %0d", vif.pwdata, vif.paddr), UVM_NONE);
@(posedge vif.pclk);
vif.psel <= 1'b0;
vif.penable <= 1'b0;
endtask
////read data from dut
virtual task read();
@(posedge vif.pclk);
vif.paddr <= tr.paddr;
vif.pwrite <= 1'b0;
vif.psel <= 1'b1;
@(posedge vif.pclk);
vif.penable <= 1'b1;
//@(posedge vif.pclk);
//vif.pwrite <= 1'b0;
@(posedge vif.pclk);
vif.psel <= 1'b0;
vif.penable <= 1'b0;
tr.prdata = vif.prdata;
`uvm_info("DRV", $sformatf("Mode :Read | WDATA : %0d ADDR : %0d RDATA : %0d", vif.pwdata, vif.paddr, vif.prdata), UVM_NONE);
endtask
/////////////////////////////////////////
virtual task run_phase (uvm_phase phase);
bit [7:0] data;
vif.presetn <= 1'b1;
vif.psel <= 0;
vif.penable <= 0;
vif.pwrite <= 0;
vif.paddr <= 0;
vif.pwdata <= 0;
forever begin
seq_item_port.get_next_item (tr);
if (tr.pwrite)
begin
write();
end
else
begin
read();
end
seq_item_port.item_done ();
end
endtask
endclass
//////////////////////Monitor//////////////////////
class monitor extends uvm_monitor;
`uvm_component_utils( monitor )
uvm_analysis_port #(transaction) mon_ap;
virtual top_if vif;
function new(string name="my_monitor", uvm_component parent);
super.new(name, parent);
endfunction : new
virtual function void build_phase(uvm_phase phase);
super.build_phase (phase);
mon_ap = new("mon_ap", this);
if(! uvm_config_db#(virtual top_if)::get (this, "", "vif", vif))
`uvm_error("DRV", "Error getting Interface Handle")
endfunction : build_phase
virtual task run_phase(uvm_phase phase);
fork
forever begin
@(posedge vif.pclk);
if(vif.psel && vif.penable && vif.presetn) begin
transaction tr = transaction::type_id::create("tr");
tr.paddr = vif.paddr;
tr.pwrite = vif.pwrite;
if (vif.pwrite)
begin
tr.pwdata = vif.pwdata;
@(posedge vif.pclk);
`uvm_info("MON", $sformatf("Mode : Write | WDATA : %0d ADDR : %0d", vif.pwdata, vif.paddr), UVM_NONE);
end
else
begin
@(posedge vif.pclk);
tr.prdata = vif.prdata;
`uvm_info("MON", $sformatf("Mode : Read | WDATA : %0d ADDR : %0d RDATA : %0d", vif.pwdata, vif.paddr, vif.prdata), UVM_NONE);
end
mon_ap.write(tr);
end
end
join_none
endtask
endclass
//////////////////////scoreboard//////////////////////
class sco extends uvm_scoreboard;
`uvm_component_utils(sco)
uvm_analysis_imp#(transaction,sco) recv;
bit [7:0] arr [1024];
bit [7:0] temp,check;
function new(input string inst = "sco", uvm_component parent = null);
super.new(inst,parent);
endfunction
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
recv = new("recv", this);
endfunction
virtual function void write(transaction tr);
if(tr.pwrite == 1'b1)
begin
arr[tr.paddr] = tr.pwdata;
`uvm_info("SCO", $sformatf("DATA Stored | Addr : %0d Data :%0d", tr.paddr, tr.pwdata), UVM_NONE)
end
else
begin
temp = arr[tr.paddr];
if( temp == tr.prdata)
`uvm_info("SCO", $sformatf("Test Passed -> Addr : %0d Data :%0d", tr.paddr, temp), UVM_NONE)
else
`uvm_error("SCO", $sformatf("Test Failed -> Addr : %0d Data :%0d", tr.paddr, temp))
end
$display("----------------------------------------------------------------");
endfunction
endclass
//////////////////////Agent and Sequencer//////////////////////
class agent extends uvm_agent;
`uvm_component_utils(agent)
function new(input string inst = "agent", uvm_component parent = null);
super.new(inst,parent);
endfunction
driver d;
uvm_sequencer#(transaction) seqr;
monitor m;
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
d = driver::type_id::create("d",this);
m = monitor::type_id::create("m",this);
seqr = uvm_sequencer#(transaction)::type_id::create("seqr", this);
endfunction
virtual function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
d.seq_item_port.connect(seqr.seq_item_export);
endfunction
endclass
//////////////////////RAL Model//////////////////////
/////////// Status Register//////////////
///////// s_reg Registers//////////////
class status_reg extends uvm_reg;
`uvm_object_utils(status_reg)
rand uvm_reg_field status;
rand uvm_reg_field producer;
rand uvm_reg_field consumer;
function new(string name = "status_reg");
super.new(name, 8, UVM_NO_COVERAGE);
endfunction
virtual function void build();
status = uvm_reg_field::type_id::create("status");
producer = uvm_reg_field::type_id::create("producer");
consumer = uvm_reg_field::type_id::create("consumer");
status.configure(this, 1, 0, "RW", 0, 0, 1, 1, 1);
producer.configure(this, 1, 1, "RW", 0, 0, 1, 1, 1);
consumer.configure(this, 1, 2, "RW", 0, 0, 1, 1, 1);
endfunction
endclass
//////////////////Duplicate Register//////////////
///////////// control register///////////////////////
class ctrl_d_reg extends uvm_reg;
`uvm_object_utils(ctrl_d_reg)
rand uvm_reg_field d_enb_field;
rand uvm_reg_field d_enable_field;
rand uvm_reg_field d_r_w_field;
function new(string name = "ctrl_d_reg");
super.new(name, 8, UVM_NO_COVERAGE);
endfunction
virtual function void build();
d_enb_field = uvm_reg_field::type_id::create("d_enb_field");
d_enable_field = uvm_reg_field::type_id::create("d_enable_field");
d_r_w_field = uvm_reg_field::type_id::create("d_r_w_field");
d_enb_field.configure(this, 1, 0, "RW", 0, 0, 1, 1, 1);
d_enable_field.configure(this, 1, 1, "RW", 0, 0, 1, 1, 1);
d_r_w_field.configure(this, 1, 2, "RW", 0, 0, 1, 1, 1);
endfunction
endclass
///////////// d_reg registers///////////////////////
class data_reg extends uvm_reg;
`uvm_object_utils(data_reg)
rand uvm_reg_field data_reg_field;
function new(string name = "data_reg");
super.new(name, 8, UVM_NO_COVERAGE);
endfunction
virtual function void build();
data_reg_field = uvm_reg_field::type_id::create("data_reg_field");
data_reg_field.configure(this, 8, 0, "RW", 0, 0, 1, 1, 1);
endfunction
endclass
/////////////Register Block Implementation/////////////
/////////////Ping pong register block///////////////////
class ping_pong_reg_block extends uvm_reg_block;
`uvm_object_utils(ping_pong_reg_block)
status_reg s_reg0;
status_reg s_reg1;
ctrl_d_reg control_0;
data_reg baud_rate_0;
data_reg trans_count_0;
data_reg sl_address_0;
ctrl_d_reg control_1;
data_reg baud_rate_1;
data_reg trans_count_1;
data_reg sl_address_1;
//uvm_reg_map default_map;
function new(string name = "ping_pong_reg_block");
super.new(name, UVM_NO_COVERAGE);
endfunction
virtual function void build();
default_map = create_map("default_map", 8'h00, 1, UVM_LITTLE_ENDIAN,0);
s_reg0 = status_reg::type_id::create("s_reg0");
s_reg0.build();
s_reg0.configure(this);
default_map.add_reg(s_reg0, 'hF0, "RW");
s_reg1 = status_reg::type_id::create("s_reg1");
s_reg1.build();
s_reg1.configure(this);
default_map.add_reg(s_reg1, 'hF1, "RW");
control_0 = ctrl_d_reg::type_id::create("control_0");
control_0.build();
control_0.configure(this);
default_map.add_reg(control_0, 'hE0, "RW");
baud_rate_0 = data_reg::type_id::create("baud_rate_0");
baud_rate_0.build();
baud_rate_0.configure(this);
default_map.add_reg(baud_rate_0, 'hE1, "RW");
trans_count_0 = data_reg::type_id::create("trans_count_0");
trans_count_0.build();
trans_count_0.configure(this);
default_map.add_reg(trans_count_0, 'hE2, "RW");
sl_address_0 = data_reg::type_id::create("sl_address_0");
sl_address_0.build();
sl_address_0.configure(this);
default_map.add_reg(sl_address_0, 'hE3, "RW");
control_1 = ctrl_d_reg::type_id::create("control_1");
control_1.build();
control_1.configure(this);
default_map.add_reg(control_1, 'hD0, "RW");
baud_rate_1 = data_reg::type_id::create("baud_rate_1");
baud_rate_1.build();
baud_rate_1.configure(this);
default_map.add_reg(baud_rate_1, 'hD1, "RW");
trans_count_1 = data_reg::type_id::create("trans_count_1");
trans_count_1.build();
trans_count_1.configure(this);
default_map.add_reg(trans_count_1, 'hD2, "RW");
sl_address_1 = data_reg::type_id::create("sl_address_1");
sl_address_1.build();
sl_address_1.configure(this);
default_map.add_reg(sl_address_1, 'hD3, "RW");
lock_model();
endfunction
endclass
//////////////////////Adapter//////////////////////
class top_adapter extends uvm_reg_adapter;
`uvm_object_utils (top_adapter)
function new (string name = "top_adapter");
super.new (name);
endfunction
function uvm_sequence_item reg2bus(const ref uvm_reg_bus_op rw);
transaction tr;
tr = transaction::type_id::create("tr");
tr.pwrite = (rw.kind == UVM_WRITE) ? 1'b1 : 1'b0;
tr.paddr = rw.addr;
`uvm_info("reg2bus", $sformatf("pwrite = %0d, paddr = %0d", tr.pwrite, tr.paddr), UVM_NONE)
if(tr.pwrite) tr.pwdata =rw.data;
if(!tr.pwrite) tr.prdata=rw.data;
//tr.pwdata = rw.data;
return tr;
endfunction
function void bus2reg(uvm_sequence_item bus_item, ref uvm_reg_bus_op rw);
transaction tr;
assert($cast(tr, bus_item));
rw.kind = (tr.pwrite == 1'b1) ? UVM_WRITE : UVM_READ;
rw.data = (tr.pwrite == 1'b1) ? tr.pwdata : tr.prdata;
//rw.data = tr.prdata;
rw.addr = tr.paddr;
`uvm_info("bus2reg", $sformatf("pwrite = %0d, paddr = %0d, prdata = %0d", tr.pwrite, tr.paddr, tr.prdata), UVM_NONE)
//rw.data = tr.prdata;
rw.status = UVM_IS_OK;
endfunction
endclass
//////////////////////Environment//////////////////////
class env extends uvm_env;
`uvm_component_utils(env)
agent agent_inst;
ping_pong_reg_block regmodel;
top_adapter adapter_inst;
uvm_reg_predictor #(transaction) predictor_inst;
sco s;
function new(string name = "env", uvm_component parent);
super.new(name, parent);
endfunction : new
function void build_phase(uvm_phase phase);
super.build_phase(phase);
agent_inst = agent::type_id::create("agent_inst", this);
s = sco::type_id::create("s", this);
regmodel = ping_pong_reg_block::type_id::create("regmodel", this);
regmodel.build();
predictor_inst = uvm_reg_predictor#(transaction)::type_id::create("predictor_inst", this);
adapter_inst = top_adapter::type_id::create("adapter_inst",, get_full_name());
endfunction
function void connect_phase(uvm_phase phase);
agent_inst.m.mon_ap.connect(s.recv);
agent_inst.m.mon_ap.connect(predictor_inst.bus_in);
regmodel.default_map.set_sequencer( .sequencer(agent_inst.seqr), .adapter(adapter_inst) );
regmodel.default_map.set_base_addr(0);
predictor_inst.map = regmodel.default_map;
predictor_inst.adapter = adapter_inst;
endfunction
endclass
//////////////////////Sequences//////////////////////
//////////////////Status reg sequence////////////////
/////Write sequence
class data_reg_wr extends uvm_sequence;
`uvm_object_utils(data_reg_wr)
ping_pong_reg_block regmodel;
function new (string name = "data_reg_wr");
super.new(name);
endfunction
task body;
uvm_status_e status;
bit [7:0] wdata;
wdata = 121;
//if (starting_phase != null)
//starting_phase.raise_objection(this);
regmodel.s_reg0.write(status, wdata);
`uvm_info("SEQ_reg", $sformatf("//////////////Check write reg | Data reg :%0d",wdata), UVM_NONE)
//if (starting_phase != null)
//starting_phase.drop_objection(this);
endtask
endclass
//////Read Sequence
class data_reg_rd extends uvm_sequence;
`uvm_object_utils(data_reg_rd)
ping_pong_reg_block regmodel;
function new (string name = "data_reg_rd");
super.new(name);
endfunction
task body;
uvm_status_e status;
bit [7:0] rdata;
//if (starting_phase != null)
//starting_phase.raise_objection(this);
regmodel.s_reg0.read(status, rdata);
`uvm_info("SEQ_reg", $sformatf("//////////////Check read reg | Data reg :%0d",rdata), UVM_NONE)
//if (starting_phase != null)
//starting_phase.drop_objection(this);
endtask
endclass
//////////////////////Test//////////////////////
class test extends uvm_test;
`uvm_component_utils(test)
function new(input string inst = "test", uvm_component c);
super.new(inst, c);
endfunction
env e;
data_reg_wr wr_seq;
data_reg_rd rd_seq;
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
e = env::type_id::create("env", this);
wr_seq = data_reg_wr::type_id::create("wr_seq");
rd_seq = data_reg_rd::type_id::create("rd_seq");
endfunction
virtual task run_phase(uvm_phase phase);
phase.raise_objection(this);
//`uvm_info("TEST", "Starting Write Sequence", UVM_MEDIUM)
wr_seq.regmodel = e.regmodel;
wr_seq.start(e.agent_inst.seqr);
//`uvm_info("TEST", "Starting Read Sequence", UVM_MEDIUM)
rd_seq.regmodel = e.regmodel;
rd_seq.start(e.agent_inst.seqr);
phase.drop_objection(this);
phase.phase_done.set_drain_time(this, 200);
endtask
endclass
//////////////////////TB//////////////////////
module tb;
top_if vif();
apb_mod dut(
.paddr(vif.paddr),
.pwdata(vif.pwdata),
.prdata(vif.prdata),
.pwrite(vif.pwrite),
.psel(vif.psel),
.penable(vif.penable),
.presetn(vif.presetn),
.pclk(vif.pclk)
);
initial begin
vif.pclk <= 0;
end
always #10 vif.pclk = ~vif.pclk;
initial begin
uvm_config_db#(virtual top_if)::set(null, "*", "vif", vif);
run_test("test");
end
initial begin
$dumpfile("dump.vcd");
$dumpvars;
end
endmodule
module apb_mod #(parameter BW = 8, CSR_no = 4)(
input wire pclk,
input wire presetn,
input wire [BW-1:0] paddr,
input wire psel,
input wire penable,
input wire pwrite,
input wire [BW-1:0] pwdata,
output wire [BW-1:0] prdata
);
reg [BW-1:0] prdata_reg;
reg [7:0] s_reg [1:0];
reg [7:0] d_reg_0[3:0];
reg [7:0] d_reg_1[3:0];
always @(posedge pclk or negedge presetn)
begin
if (!presetn)
begin
s_reg[0][0] <= 1;
s_reg[0][1] <= 0;
s_reg[0][2] <= 0;
d_reg_0[0][0] <= 0;
d_reg_1[0][0] <= 0;
prdata_reg <= 0;
end
else if (psel && penable)
begin
if (pwrite) // Write operation
begin
$display("pwdata %0d addr %0d",pwdata,paddr);
case (s_reg[0][1])
1'b0: begin
case (paddr)
8'hf0: begin s_reg[0][1] <= pwdata[0];
$display("reg data %0d",s_reg[0][1]);
end
default: begin
d_reg_0[paddr[3:0]] <= pwdata; // Address limited to 4 bits
s_reg[0][2] <= 1;
s_reg[0][0] <= 0;
$display("reg data %0d",s_reg[0][1]);
end
endcase
end
1'b1: begin
case (paddr)
8'hf0: begin s_reg[0][1] <= pwdata[0];
$display("reg data %0d",s_reg[0][1]);
end
default: begin
d_reg_1[paddr[3:0]] <= pwdata; // Address limited to 4 bits
s_reg[0][2] <= 0;
s_reg[0][0] <= 0;
$display("reg data %0d",s_reg[0][1]);
end
endcase
end
endcase
end
else // Read operation
begin
case (paddr[7:4])
4'hf: prdata_reg <= {5'b00000, s_reg[0][2:0]};
4'he: prdata_reg <= d_reg_0[paddr[3:0]];
default: prdata_reg <= d_reg_1[paddr[3:0]];
endcase
end
end
end
// Fix: Assign read data output correctly
assign prdata = prdata_reg;
endmodule
//////////////////////Interface//////////////////////
interface top_if;
logic [7 : 0] paddr; // 8-bit
logic [7 : 0] pwdata; // 8-bit
logic [7 : 0] prdata; // 8-bit
logic pwrite; // 1-bit
logic psel; // 1-bit
logic penable; // 1-bit
logic presetn; // 1-bit
logic pclk; // 1-bit
endinterface
Your account is not validated. If you wish to use commercial simulators, you need a validated account.
If you have already registered (or have recently changed your email address), but have not clicked on the link in the email we sent you, please do so. If you cannot find the email, please check your spam/junk folder. Or click here to resend the email.
If you have not already registered for a full account, you can do so by clicking below. You will then need to provide us with some identification information. You may wish to save your code first.
Creating, deleting, and renaming files is not supported during Collaboration. To encourage development of these features for Collaboration, tweet to @EDAPlayground
This playground may have been modified. Please save or copy before starting collaboration.
Your exercise has been submitted.