Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added coverage.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
136 changes: 83 additions & 53 deletions rtl/traffic.sv
Original file line number Diff line number Diff line change
@@ -1,56 +1,86 @@
module traffic ( input pclk,
input presetn,
input [31:0] paddr,
input [31:0] pwdata,
input psel,
input pwrite,
input penable,

// Outputs
output [31:0] prdata);

reg [3:0] ctl_reg; // profile, blink_red, blink_yellow, mod_en RW
reg [1:0] stat_reg; // state[1:0]
reg [31:0] timer_0; // timer_g2y[31:20], timer_r2g[19:8], timer_y2r[7:0] RW
reg [31:0] timer_1; // timer_g2y[31:20], timer_r2g[19:8], timer_y2r[7:0] RW

reg [31:0] data_in;
reg [31:0] rdata_tmp;

// Set all registers to default values
always @ (posedge pclk) begin
if (!presetn) begin
data_in <= 0;
ctl_reg <= 0;
stat_reg <= 0;
timer_0 <= 32'hcafe_1234;
timer_1 <= 32'hface_5678;
end
end

// Capture write data
always @ (posedge pclk) begin
if (presetn & psel & penable)
if (pwrite)
module traffic (
input pclk,
input presetn,
input [31:0] paddr,
input [31:0] pwdata,
input psel,
input pwrite,
input penable,
output reg pready,
output reg pslverr,
output reg [31:0] prdata
);

// Internal registers
reg [3:0] ctl_reg;
reg [31:0] timer_0;
reg [31:0] timer_1;

typedef enum logic [1:0] { IDLE, SETUP, ACCESS, TRANSFER } state_t;
state_t state;

// Reset and initialization
always @(posedge pclk or negedge presetn) begin
if (!(paddr inside {0, 4, 8})) begin pslverr <=1;end
if (!presetn) begin
// Reset all internal states and registers
state <= IDLE;
ctl_reg <= 4'b0;
timer_0 <= 32'hcafe1234;
timer_1 <= 32'hface5678;
prdata <= 32'h0;
pready <= 1'b0;
pslverr <= 1'b0;
$display("RESET: Registers reset to default values");
end else begin
case (state)
IDLE: begin
pready <= 1'b0; // Ensure pready is deasserted
if (psel && !penable) begin
state <= SETUP;
$display("IDLE: Detected psel, moving to SETUP");
end
end

SETUP: begin
if (psel && penable) begin
state <= ACCESS;
$display("SETUP: Detected penable, moving to ACCESS");
end
end
ACCESS: begin
if (psel && penable && (paddr<32)) begin
if (pwrite) begin
// Write operation
case (paddr)
32'h0: ctl_reg <= pwdata[3:0];
32'h4: timer_0 <= pwdata;
32'h8: timer_1 <= pwdata;
default: pslverr <= 1'b1;
endcase
$display("DUT WRITE: Addr=%h, Data=%h", paddr, pwdata);
end else begin
// Read operation
case (paddr)
'h0 : ctl_reg <= pwdata;
'h4 : timer_0 <= pwdata;
'h8 : timer_1 <= pwdata;
'hc : stat_reg <= pwdata;
32'h0: prdata <= {28'b0, ctl_reg};
32'h4: prdata <= timer_0;
32'h8: prdata <= timer_1;
default: prdata <= 32'hDEADBEEF;
endcase
$display("DUT READ: Addr=%h, Data=%h", paddr, prdata);
end
pready <= 1'b1; // Indicate transaction completion
state <= TRANSFER; // Move to the next state
end else begin
pready <= 1'b0; // Ensure pready is low if not in a valid transaction
end
end
TRANSFER: begin
pready <= 1'b0; // Deassert pready after the transaction
state <= IDLE; // Return to IDLE for the next transaction
$display("TRANSFER: Transaction done, returning to IDLE");
end
endcase
end

// Provide read data
always @ (penable) begin
if (psel & !pwrite)
case (paddr)
'h0 : rdata_tmp <= ctl_reg;
'h4 : rdata_tmp <= timer_0;
'h8 : rdata_tmp <= timer_1;
'hc : rdata_tmp <= stat_reg;
endcase
end

assign prdata = (psel & penable & !pwrite) ? rdata_tmp : 'hz;

end
end
endmodule
59 changes: 34 additions & 25 deletions tb/apb_driver.sv
Original file line number Diff line number Diff line change
Expand Up @@ -35,29 +35,38 @@ class apb_driver extends uvm_driver #(apb_tr);
end
endtask

virtual task read ( input bit [31:0] addr,
output logic [31:0] data);
vif.paddr <= addr;
vif.pwrite <= 0;
vif.psel <= 1;
@(posedge vif.pclk);
vif.penable <= 1;
@(posedge vif.pclk);
data = vif.prdata;
vif.psel <= 0;
vif.penable <= 0;
endtask

virtual task write ( input bit [31:0] addr,
input bit [31:0] data);
vif.paddr <= addr;
vif.pwdata <= data;
vif.pwrite <= 1;
vif.psel <= 1;
@(posedge vif.pclk);
vif.penable <= 1;
@(posedge vif.pclk);
vif.psel <= 0;
vif.penable <= 0;
endtask
virtual task write(input bit [31:0] addr, input bit [31:0] data);
vif.paddr <= addr;
vif.pwdata <= data;
vif.pwrite <= 1;
vif.psel <= 1;
@(posedge vif.pclk);
vif.penable <= 1;

// Wait for pready to be asserted
wait (vif.pready == 1);
@(posedge vif.pclk);
$display("DRIVER WRITE: Addr=%h, Data=%h, pready=%b", addr, data, vif.pready);

vif.psel <= 0;
vif.penable <= 0;
endtask

virtual task read(input bit [31:0] addr, output logic [31:0] data);
vif.paddr <= addr;
vif.pwrite <= 0;
vif.psel <= 1;
@(posedge vif.pclk);
vif.penable <= 1;

// Wait for pready to be asserted
wait (vif.pready == 1);
@(posedge vif.pclk);
data = vif.prdata;
$display("DRIVER READ: Addr=%h, Data=%h, pready=%b", addr, data, vif.pready);

vif.psel <= 0;
vif.penable <= 0;
endtask

endclass
27 changes: 19 additions & 8 deletions tb/apb_if.sv
Original file line number Diff line number Diff line change
@@ -1,9 +1,20 @@
interface apb_if (input pclk, input presetn);
logic [31:0] paddr;
logic [31:0] pwdata;
logic [31:0] prdata;
logic pwrite;
logic psel;
logic penable;
logic presetn;
interface apb_if (input pclk, input presetn); // presetn as input
logic [31:0] paddr;
logic [31:0] pwdata;
logic [31:0] prdata;
logic pwrite;
logic psel;
logic penable;
logic pready; // If pready is used
logic pslverr;
// Assertion: pslverr should be asserted for invalid addresses
property invalid_address_check;
@(posedge pclk) (paddr inside {0, 4, 8}) or pslverr == 1'b1;
endproperty

assert property (invalid_address_check)
else $error("Invalid address detected !");



endinterface
58 changes: 35 additions & 23 deletions tb/apb_monitor.sv
Original file line number Diff line number Diff line change
Expand Up @@ -7,28 +7,40 @@ class apb_monitor extends uvm_monitor;
uvm_analysis_port #(apb_tr) mon_ap;
virtual apb_if vif;

virtual function void build_phase (uvm_phase phase);
super.build_phase (phase);
mon_ap = new ("mon_ap", this);
uvm_config_db #(virtual apb_if)::get (null, "uvm_test_top.*", "apb_if", vif);
endfunction

virtual task run_phase (uvm_phase phase);
fork
@(posedge vif.presetn);
forever begin
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
mon_ap = new("mon_ap", this);
if (!uvm_config_db#(virtual apb_if)::get(null, "uvm_test_top.*", "apb_if", vif))
`uvm_error("MONITOR", "Failed to get apb_if");
endfunction



virtual task run_phase(uvm_phase phase);
fork
@(posedge vif.presetn); // Wait for reset deassertion
forever begin
@(posedge vif.pclk);
if (vif.psel & vif.penable & vif.presetn) begin
apb_tr tr = apb_tr::type_id::create ("tr");
tr.addr = vif.paddr;
if (vif.pwrite)
tr.data = vif.pwdata;
else
tr.data = vif.prdata;
tr.write = vif.pwrite;
mon_ap.write (tr);
end
end
join_none
endtask
if (vif.psel && vif.penable && vif.presetn) begin
apb_tr tr = apb_tr::type_id::create("tr");
tr.addr = vif.paddr;

if (vif.pwrite) begin
tr.data = vif.pwdata;
tr.write = 1'b1;
$display("MONITOR: Captured WRITE - Addr=%h, Data=%h", tr.addr, tr.data);
end else begin
tr.data = vif.prdata;
tr.write = 1'b0;
$display("MONITOR: Captured READ - Addr=%h, Data=%h", tr.addr, tr.data);
end

// Forward the transaction
mon_ap.write(tr);
end
end
join_none
endtask


endclass
26 changes: 26 additions & 0 deletions tb/invalid_address_test.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
class invalid_address_test extends uvm_test;
`uvm_component_utils(invalid_address_test)

traffic_env m_env;
uvm_sequence invalid_seq;

function new(string name = "invalid_address_test", uvm_component parent = null);
super.new(name, parent);
endfunction

virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
m_env = traffic_env::type_id::create("m_env", this);
endfunction

virtual task main_phase(uvm_phase phase);
phase.raise_objection(this);

// Create and run the invalid_address_sequence

invalid_seq = invalid_address_sequence::type_id::create("invalid_seq");
invalid_seq.start(m_env.m_agent.m_seqr); // Start the sequence on the APB sequencer

phase.drop_objection(this);
endtask
endclass
20 changes: 12 additions & 8 deletions tb/reg_lib/ral_block_traffic_cfg.sv
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
// These registers are grouped together to form a register block called "cfg"
class ral_block_traffic_cfg extends uvm_reg_block;

`uvm_object_utils(ral_block_traffic_cfg)
Expand All @@ -10,32 +9,37 @@ class ral_block_traffic_cfg extends uvm_reg_block;
uvm_reg_map reg_map;


function new(string name = "traffic_cfg");
super.new(name, build_coverage(UVM_NO_COVERAGE));
function new(string name = "ral_block_traffic_cfg");
super.new(name, UVM_CVR_ALL);
`uvm_info("RAL_BLOCK", $sformatf("Creating instance: %s", name), UVM_LOW);
endfunction


virtual function void build();
this.reg_map = create_map("", 0, 4, UVM_LITTLE_ENDIAN, 0);
this.reg_map = create_map("", 0, 8, UVM_LITTLE_ENDIAN, 0);

this.ctrl = ral_cfg_ctl::type_id::create("ctrl",,get_full_name());
this.ctrl.configure(this, null, "");
this.ctrl.build();
this.ctrl.configure(this, null, "");
this.reg_map.add_reg(this.ctrl, `UVM_REG_ADDR_WIDTH'h0, "RW", 0);


this.timer[0] = ral_cfg_timer::type_id::create("timer[0]",,get_full_name());
this.timer[0].configure(this, null, "");
this.timer[0].build();
this.timer[0].configure(this, null, "");

this.reg_map.add_reg(this.timer[0], `UVM_REG_ADDR_WIDTH'h4, "RW", 0);

this.timer[1] = ral_cfg_timer::type_id::create("timer[1]",,get_full_name());
this.timer[1].configure(this, null, "");
this.timer[1].build();
this.timer[1].configure(this, null, "");

this.reg_map.add_reg(this.timer[1], `UVM_REG_ADDR_WIDTH'h8, "RW", 0);

this.stat = ral_cfg_stat::type_id::create("stat",,get_full_name());
this.stat.configure(this, null, "");
this.stat.build();
this.stat.configure(this, null, "");

this.reg_map.add_reg(this.stat, `UVM_REG_ADDR_WIDTH'hc, "RO", 0);

lock_model();
Expand Down
Loading