mirror of
https://github.com/retroSoC/retroSoC.git
synced 2026-11-06 14:55:14 +00:00
feat: add comprehensive tests for AXI4 components and lifecycle controllers
- Implemented tests for AXI4 async bridge functionality, including transfer and warm flush scenarios. - Added tests for AXI4 data crossbar to validate concurrent outstanding requests and ACL handling. - Introduced clock frequency monitor tests to ensure detection of clock stop and restart events. - Developed tests for extension DMA master to verify copy operations, tail strobe behavior, and timeout handling. - Created tests for HP lifecycle controller to validate drain, flush, and forced reset functionalities. - Updated existing test scripts to include new RTL components and ensure proper simulation configurations.
This commit is contained in:
67 files changed
+4165
-612
No files matched your search
@@ -0,0 +1,129 @@
|
||||
`timescale 1ns / 1ps
|
||||
|
||||
module axi4_async_bridge_tb;
|
||||
logic src_clk_i = 1'b0;
|
||||
logic dst_clk_i = 1'b0;
|
||||
logic src_rst_n_i = 1'b0;
|
||||
logic dst_rst_n_i = 1'b0;
|
||||
logic clear_i = 1'b0;
|
||||
logic clear_busy_o;
|
||||
logic [7:0] epoch_o;
|
||||
|
||||
axi4_if #(
|
||||
.ADDR_WIDTH(32),
|
||||
.DATA_WIDTH(32),
|
||||
.ID_WIDTH (1),
|
||||
.USER_WIDTH(1)
|
||||
) source (
|
||||
.aclk (src_clk_i),
|
||||
.aresetn(src_rst_n_i)
|
||||
);
|
||||
axi4_if #(
|
||||
.ADDR_WIDTH(32),
|
||||
.DATA_WIDTH(32),
|
||||
.ID_WIDTH (1),
|
||||
.USER_WIDTH(1)
|
||||
) sink (
|
||||
.aclk (dst_clk_i),
|
||||
.aresetn(dst_rst_n_i)
|
||||
);
|
||||
|
||||
always #5 src_clk_i = ~src_clk_i;
|
||||
always #7 dst_clk_i = ~dst_clk_i;
|
||||
|
||||
axi4_async_bridge u_dut (
|
||||
.src_clk_i (src_clk_i),
|
||||
.src_rst_n_i (src_rst_n_i),
|
||||
.dst_clk_i (dst_clk_i),
|
||||
.dst_rst_n_i (dst_rst_n_i),
|
||||
.clear_i (clear_i),
|
||||
.clear_busy_o(clear_busy_o),
|
||||
.epoch_o (epoch_o),
|
||||
.src_axi4 (source),
|
||||
.dst_axi4 (sink)
|
||||
);
|
||||
|
||||
initial begin
|
||||
source.awid = 0;
|
||||
source.awaddr = 0;
|
||||
source.awlen = 0;
|
||||
source.awsize = 2;
|
||||
source.awburst = 1;
|
||||
source.awlock = 0;
|
||||
source.awcache = 0;
|
||||
source.awprot = 0;
|
||||
source.awqos = 0;
|
||||
source.awregion = 0;
|
||||
source.awuser = 0;
|
||||
source.awvalid = 0;
|
||||
source.wdata = 0;
|
||||
source.wstrb = 0;
|
||||
source.wlast = 1;
|
||||
source.wuser = 0;
|
||||
source.wvalid = 0;
|
||||
source.bready = 1;
|
||||
source.arid = 0;
|
||||
source.araddr = 0;
|
||||
source.arlen = 0;
|
||||
source.arsize = 2;
|
||||
source.arburst = 1;
|
||||
source.arlock = 0;
|
||||
source.arcache = 0;
|
||||
source.arprot = 0;
|
||||
source.arqos = 0;
|
||||
source.arregion = 0;
|
||||
source.aruser = 0;
|
||||
source.arvalid = 0;
|
||||
source.rready = 1;
|
||||
sink.awready = 1;
|
||||
sink.wready = 1;
|
||||
sink.bid = 0;
|
||||
sink.bresp = 0;
|
||||
sink.buser = 0;
|
||||
sink.bvalid = 0;
|
||||
sink.arready = 1;
|
||||
sink.rid = 0;
|
||||
sink.rdata = 32'hCAFE_BABE;
|
||||
sink.rresp = 0;
|
||||
sink.rlast = 1;
|
||||
sink.ruser = 0;
|
||||
sink.rvalid = 0;
|
||||
|
||||
repeat (3) @(posedge src_clk_i);
|
||||
src_rst_n_i = 1;
|
||||
dst_rst_n_i = 1;
|
||||
repeat (8) @(posedge src_clk_i);
|
||||
@(negedge src_clk_i);
|
||||
source.araddr = 32'h5000_0040;
|
||||
source.arvalid = 1;
|
||||
do @(posedge src_clk_i); while (!source.arready);
|
||||
@(negedge src_clk_i);
|
||||
source.arvalid = 0;
|
||||
wait (sink.arvalid);
|
||||
if (sink.araddr != 32'h5000_0040) $fatal(1, "async bridge address mismatch");
|
||||
@(posedge dst_clk_i);
|
||||
@(negedge dst_clk_i);
|
||||
sink.rvalid = 1;
|
||||
do @(posedge dst_clk_i); while (!sink.rready);
|
||||
@(negedge dst_clk_i);
|
||||
sink.rvalid = 0;
|
||||
wait (source.rvalid);
|
||||
if (source.rdata != 32'hCAFE_BABE) $fatal(1, "async bridge response mismatch");
|
||||
@(posedge src_clk_i);
|
||||
|
||||
@(negedge src_clk_i);
|
||||
clear_i = 1;
|
||||
wait (clear_busy_o);
|
||||
clear_i = 0;
|
||||
wait (!clear_busy_o);
|
||||
if (epoch_o != 8'd1) $fatal(1, "async bridge epoch did not advance");
|
||||
|
||||
$display("AXI4 async bridge transfer and warm flush test passed");
|
||||
$finish;
|
||||
end
|
||||
|
||||
initial begin
|
||||
#20000;
|
||||
$fatal(1, "AXI4 async bridge test timed out");
|
||||
end
|
||||
endmodule
|
||||
@@ -0,0 +1,230 @@
|
||||
`timescale 1ns / 1ps
|
||||
|
||||
module axi4_data_crossbar_tb;
|
||||
localparam int NumMasters = 8;
|
||||
localparam int NumTargets = 6;
|
||||
|
||||
logic clk_i = 1'b0;
|
||||
logic rst_n_i = 1'b0;
|
||||
logic idle_o;
|
||||
logic [ 7:0] outstanding_read_o;
|
||||
logic [ 7:0] outstanding_write_o;
|
||||
logic fault_valid_o;
|
||||
logic [ 2:0] fault_master_o;
|
||||
logic [ 2:0] fault_target_o;
|
||||
logic [31:0] fault_addr_o;
|
||||
logic fault_write_o;
|
||||
logic [ 3:0] fault_reason_o;
|
||||
|
||||
axi4_if #(
|
||||
.ADDR_WIDTH(32),
|
||||
.DATA_WIDTH(64),
|
||||
.ID_WIDTH (6),
|
||||
.USER_WIDTH(1)
|
||||
) masters[NumMasters] (
|
||||
.aclk (clk_i),
|
||||
.aresetn(rst_n_i)
|
||||
);
|
||||
axi4_if #(
|
||||
.ADDR_WIDTH(32),
|
||||
.DATA_WIDTH(64),
|
||||
.ID_WIDTH (6),
|
||||
.USER_WIDTH(1)
|
||||
) targets[NumTargets] (
|
||||
.aclk (clk_i),
|
||||
.aresetn(rst_n_i)
|
||||
);
|
||||
|
||||
always #5 clk_i = ~clk_i;
|
||||
|
||||
initial begin
|
||||
repeat (500) @(posedge clk_i);
|
||||
$fatal(1, "AXI4 data crossbar test timed out");
|
||||
end
|
||||
|
||||
axi4_data_crossbar u_dut (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i (rst_n_i),
|
||||
.block_new_i (1'b0),
|
||||
.recovery_i (1'b0),
|
||||
.mem_pad_mode_i (2'd1),
|
||||
.ext_h_read_base_i (32'h3000_0000),
|
||||
.ext_h_read_limit_i (32'h4FFF_FFFF),
|
||||
.ext_h_write_base_i (32'h3000_0000),
|
||||
.ext_h_write_limit_i(32'h4FFF_FFFF),
|
||||
.masters (masters),
|
||||
.targets (targets),
|
||||
.idle_o (idle_o),
|
||||
.outstanding_read_o (outstanding_read_o),
|
||||
.outstanding_write_o(outstanding_write_o),
|
||||
.fault_valid_o (fault_valid_o),
|
||||
.fault_master_o (fault_master_o),
|
||||
.fault_target_o (fault_target_o),
|
||||
.fault_addr_o (fault_addr_o),
|
||||
.fault_write_o (fault_write_o),
|
||||
.fault_reason_o (fault_reason_o)
|
||||
);
|
||||
|
||||
task automatic issue_master1_read(input logic [5:0] id, input logic [31:0] addr);
|
||||
begin
|
||||
@(negedge clk_i);
|
||||
masters[1].arid = id;
|
||||
masters[1].araddr = addr;
|
||||
masters[1].arvalid = 1'b1;
|
||||
do @(posedge clk_i); while (!masters[1].arready);
|
||||
@(negedge clk_i);
|
||||
masters[1].arvalid = 1'b0;
|
||||
end
|
||||
endtask
|
||||
|
||||
task automatic return_target0_read(input logic [5:0] id, input logic [63:0] data);
|
||||
begin
|
||||
@(negedge clk_i);
|
||||
targets[0].rid = id;
|
||||
targets[0].rdata = data;
|
||||
targets[0].rresp = 2'b00;
|
||||
targets[0].rlast = 1'b1;
|
||||
targets[0].rvalid = 1'b1;
|
||||
do @(posedge clk_i); while (!targets[0].rready);
|
||||
@(negedge clk_i);
|
||||
targets[0].rvalid = 1'b0;
|
||||
end
|
||||
endtask
|
||||
|
||||
task automatic return_target1_read(input logic [5:0] id, input logic [63:0] data);
|
||||
begin
|
||||
@(negedge clk_i);
|
||||
targets[1].rid = id;
|
||||
targets[1].rdata = data;
|
||||
targets[1].rresp = 2'b00;
|
||||
targets[1].rlast = 1'b1;
|
||||
targets[1].rvalid = 1'b1;
|
||||
do @(posedge clk_i); while (!targets[1].rready);
|
||||
@(negedge clk_i);
|
||||
targets[1].rvalid = 1'b0;
|
||||
end
|
||||
endtask
|
||||
|
||||
`define INIT_MASTER(index) \
|
||||
masters[index].awid = '0; \
|
||||
masters[index].awaddr = '0; \
|
||||
masters[index].awlen = '0; \
|
||||
masters[index].awsize = 3'd3; \
|
||||
masters[index].awburst = 2'b01; \
|
||||
masters[index].awlock = 1'b0; \
|
||||
masters[index].awcache = '0; \
|
||||
masters[index].awprot = '0; \
|
||||
masters[index].awqos = '0; \
|
||||
masters[index].awregion = '0; \
|
||||
masters[index].awuser = '0; \
|
||||
masters[index].awvalid = 1'b0; \
|
||||
masters[index].wdata = '0; \
|
||||
masters[index].wstrb = '0; \
|
||||
masters[index].wlast = 1'b1; \
|
||||
masters[index].wuser = '0; \
|
||||
masters[index].wvalid = 1'b0; \
|
||||
masters[index].bready = 1'b1; \
|
||||
masters[index].arid = '0; \
|
||||
masters[index].araddr = '0; \
|
||||
masters[index].arlen = '0; \
|
||||
masters[index].arsize = 3'd3; \
|
||||
masters[index].arburst = 2'b01; \
|
||||
masters[index].arlock = 1'b0; \
|
||||
masters[index].arcache = '0; \
|
||||
masters[index].arprot = '0; \
|
||||
masters[index].arqos = '0; \
|
||||
masters[index].arregion = '0; \
|
||||
masters[index].aruser = '0; \
|
||||
masters[index].arvalid = 1'b0; \
|
||||
masters[index].rready = 1'b1;
|
||||
|
||||
`define INIT_TARGET(index) \
|
||||
targets[index].awready = 1'b1; \
|
||||
targets[index].wready = 1'b1; \
|
||||
targets[index].bid = '0; \
|
||||
targets[index].bresp = '0; \
|
||||
targets[index].buser = '0; \
|
||||
targets[index].bvalid = 1'b0; \
|
||||
targets[index].arready = 1'b1; \
|
||||
targets[index].rid = '0; \
|
||||
targets[index].rdata = '0; \
|
||||
targets[index].rresp = '0; \
|
||||
targets[index].rlast = 1'b1; \
|
||||
targets[index].ruser = '0; \
|
||||
targets[index].rvalid = 1'b0;
|
||||
|
||||
initial begin
|
||||
`INIT_MASTER(0)
|
||||
`INIT_MASTER(1)
|
||||
`INIT_MASTER(2)
|
||||
`INIT_MASTER(3)
|
||||
`INIT_MASTER(4)
|
||||
`INIT_MASTER(5)
|
||||
`INIT_MASTER(6)
|
||||
`INIT_MASTER(7)
|
||||
`INIT_TARGET(0)
|
||||
`INIT_TARGET(1)
|
||||
`INIT_TARGET(2)
|
||||
`INIT_TARGET(3)
|
||||
`INIT_TARGET(4)
|
||||
`INIT_TARGET(5)
|
||||
|
||||
repeat (3) @(posedge clk_i);
|
||||
rst_n_i = 1'b1;
|
||||
|
||||
issue_master1_read(6'b001_000, 32'h3000_0000);
|
||||
issue_master1_read(6'b001_001, 32'h3800_0000);
|
||||
if (outstanding_read_o != 8'd2 || idle_o) begin
|
||||
$fatal(1, "different-target reads were not tracked concurrently");
|
||||
end
|
||||
|
||||
@(negedge clk_i);
|
||||
masters[1].arid = 6'b001_000;
|
||||
masters[1].araddr = 32'h4000_0000;
|
||||
masters[1].arvalid = 1'b1;
|
||||
#1;
|
||||
if (masters[1].arready) $fatal(1, "same source ID was accepted before completion");
|
||||
masters[1].arvalid = 1'b0;
|
||||
|
||||
fork
|
||||
return_target1_read(6'b001_001, 64'h2222_2222_2222_2222);
|
||||
begin
|
||||
wait (masters[1].rvalid);
|
||||
if ((masters[1].rid != 6'b001_001) || (masters[1].rdata != 64'h2222_2222_2222_2222)) begin
|
||||
$fatal(1, "out-of-order different-ID response was misrouted");
|
||||
end
|
||||
end
|
||||
join
|
||||
return_target0_read(6'b001_000, 64'h1111_1111_1111_1111);
|
||||
@(negedge clk_i);
|
||||
if (!idle_o || (outstanding_read_o != 8'd0)) begin
|
||||
$fatal(1, "read completion did not drain the crossbar");
|
||||
end
|
||||
|
||||
@(negedge clk_i);
|
||||
masters[6].arid = 6'b110_000;
|
||||
masters[6].araddr = 32'h3000_0000;
|
||||
masters[6].arvalid = 1'b1;
|
||||
do @(posedge clk_i); while (!masters[6].arready);
|
||||
#1;
|
||||
if (!fault_valid_o || (fault_master_o != 3'd6) ||
|
||||
(fault_reason_o != 4'd3) || fault_write_o) begin
|
||||
$fatal(1, "reserved-master ACL fault attribution mismatch");
|
||||
end
|
||||
@(negedge clk_i);
|
||||
masters[6].arvalid = 1'b0;
|
||||
targets[5].rid = 6'b110_000;
|
||||
targets[5].rresp = 2'b10;
|
||||
targets[5].rlast = 1'b1;
|
||||
targets[5].rvalid = 1'b1;
|
||||
do @(posedge clk_i); while (!targets[5].rready);
|
||||
@(negedge clk_i);
|
||||
targets[5].rvalid = 1'b0;
|
||||
|
||||
$display("AXI4 data crossbar concurrency and ACL test passed");
|
||||
$finish;
|
||||
end
|
||||
|
||||
`undef INIT_MASTER
|
||||
`undef INIT_TARGET
|
||||
endmodule
|
||||
@@ -0,0 +1,58 @@
|
||||
`timescale 1ns / 1ps
|
||||
|
||||
module clock_frequency_monitor_tb;
|
||||
logic ref_clk_i = 1'b0;
|
||||
logic monitored_clk_i = 1'b0;
|
||||
logic rst_n_i = 1'b0;
|
||||
logic clear_fault_i = 1'b0;
|
||||
logic run_monitored = 1'b1;
|
||||
logic alive_o;
|
||||
logic fault_o;
|
||||
logic [7:0] edge_delta_o;
|
||||
|
||||
always #5 ref_clk_i = ~ref_clk_i;
|
||||
always begin
|
||||
#2;
|
||||
if (run_monitored) monitored_clk_i = ~monitored_clk_i;
|
||||
else monitored_clk_i = 1'b0;
|
||||
end
|
||||
|
||||
clock_frequency_monitor #(
|
||||
.CounterWidth(8),
|
||||
.WindowCycles(8)
|
||||
) u_dut (
|
||||
.ref_clk_i (ref_clk_i),
|
||||
.ref_rst_n_i (rst_n_i),
|
||||
.monitored_clk_i (monitored_clk_i),
|
||||
.monitored_rst_n_i(rst_n_i),
|
||||
.clear_fault_i (clear_fault_i),
|
||||
.alive_o (alive_o),
|
||||
.fault_o (fault_o),
|
||||
.edge_delta_o (edge_delta_o)
|
||||
);
|
||||
|
||||
initial begin
|
||||
repeat (2) @(posedge ref_clk_i);
|
||||
rst_n_i = 1'b1;
|
||||
repeat (20) @(posedge ref_clk_i);
|
||||
if (!alive_o || fault_o || (edge_delta_o == 8'd0)) begin
|
||||
$fatal(1, "running clock was not measured as alive");
|
||||
end
|
||||
|
||||
run_monitored = 1'b0;
|
||||
wait (fault_o);
|
||||
if (alive_o) $fatal(1, "stopped clock remained alive");
|
||||
@(negedge ref_clk_i);
|
||||
clear_fault_i = 1'b1;
|
||||
@(negedge ref_clk_i);
|
||||
clear_fault_i = 1'b0;
|
||||
@(negedge ref_clk_i);
|
||||
if (fault_o) $fatal(1, "clock fault did not clear");
|
||||
run_monitored = 1'b1;
|
||||
repeat (12) @(posedge ref_clk_i);
|
||||
if (!alive_o) $fatal(1, "restarted clock did not recover activity status");
|
||||
|
||||
$display("Clock frequency activity and sticky fault test passed");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
@@ -0,0 +1,125 @@
|
||||
`timescale 1ns / 1ps
|
||||
|
||||
module extension_dma_master_tb;
|
||||
logic clk_i = 1'b0;
|
||||
logic rst_n_i = 1'b0;
|
||||
logic start_i = 1'b0;
|
||||
logic abort_i = 1'b0;
|
||||
logic quiesce_i = 1'b0;
|
||||
logic [31:0] src_addr_i = 32'h3000_0000;
|
||||
logic [31:0] dst_addr_i = 32'h3000_0100;
|
||||
logic [31:0] len_i = 32'd12;
|
||||
logic [31:0] timeout_i = 32'd16;
|
||||
logic busy_o;
|
||||
logic done_o;
|
||||
logic err_o;
|
||||
logic [31:0] fault_addr_o;
|
||||
|
||||
axi4_if #(
|
||||
.ADDR_WIDTH(32),
|
||||
.DATA_WIDTH(64),
|
||||
.ID_WIDTH (3),
|
||||
.USER_WIDTH(1)
|
||||
) axi4 (
|
||||
.aclk (clk_i),
|
||||
.aresetn(rst_n_i)
|
||||
);
|
||||
|
||||
always #5 clk_i = ~clk_i;
|
||||
|
||||
extension_dma_master u_dut (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i (rst_n_i),
|
||||
.start_i (start_i),
|
||||
.abort_i (abort_i),
|
||||
.quiesce_i (quiesce_i),
|
||||
.src_addr_i (src_addr_i),
|
||||
.dst_addr_i (dst_addr_i),
|
||||
.len_i (len_i),
|
||||
.timeout_i (timeout_i),
|
||||
.busy_o (busy_o),
|
||||
.done_o (done_o),
|
||||
.err_o (err_o),
|
||||
.fault_addr_o(fault_addr_o),
|
||||
.axi4 (axi4)
|
||||
);
|
||||
|
||||
task automatic start_dma;
|
||||
begin
|
||||
@(negedge clk_i);
|
||||
start_i = 1'b1;
|
||||
@(negedge clk_i);
|
||||
start_i = 1'b0;
|
||||
end
|
||||
endtask
|
||||
|
||||
task automatic serve_beat(input logic [31:0] expected_src, input logic [31:0] expected_dst,
|
||||
input logic [63:0] data, input logic [7:0] expected_strobe);
|
||||
begin
|
||||
wait (axi4.arvalid);
|
||||
if (axi4.araddr != expected_src) $fatal(1, "DMA read address mismatch");
|
||||
@(posedge clk_i);
|
||||
@(negedge clk_i);
|
||||
axi4.rid = 3'd0;
|
||||
axi4.rdata = data;
|
||||
axi4.rresp = 2'b00;
|
||||
axi4.rlast = 1'b1;
|
||||
axi4.rvalid = 1'b1;
|
||||
do @(posedge clk_i); while (!axi4.rready);
|
||||
@(negedge clk_i);
|
||||
axi4.rvalid = 1'b0;
|
||||
wait (axi4.awvalid);
|
||||
if (axi4.awaddr != expected_dst) $fatal(1, "DMA write address mismatch");
|
||||
@(posedge clk_i);
|
||||
wait (axi4.wvalid);
|
||||
if ((axi4.wdata != data) || (axi4.wstrb != expected_strobe) || !axi4.wlast) begin
|
||||
$fatal(1, "DMA write data or tail strobe mismatch");
|
||||
end
|
||||
@(posedge clk_i);
|
||||
@(negedge clk_i);
|
||||
axi4.bid = 3'd0;
|
||||
axi4.bresp = 2'b00;
|
||||
axi4.bvalid = 1'b1;
|
||||
do @(posedge clk_i); while (!axi4.bready);
|
||||
@(negedge clk_i);
|
||||
axi4.bvalid = 1'b0;
|
||||
end
|
||||
endtask
|
||||
|
||||
initial begin
|
||||
axi4.awready = 1'b1;
|
||||
axi4.wready = 1'b1;
|
||||
axi4.bid = '0;
|
||||
axi4.bresp = '0;
|
||||
axi4.buser = '0;
|
||||
axi4.bvalid = 1'b0;
|
||||
axi4.arready = 1'b1;
|
||||
axi4.rid = '0;
|
||||
axi4.rdata = '0;
|
||||
axi4.rresp = '0;
|
||||
axi4.rlast = 1'b1;
|
||||
axi4.ruser = '0;
|
||||
axi4.rvalid = 1'b0;
|
||||
|
||||
repeat (2) @(posedge clk_i);
|
||||
rst_n_i = 1'b1;
|
||||
start_dma();
|
||||
serve_beat(32'h3000_0000, 32'h3000_0100, 64'h1122_3344_5566_7788, 8'hFF);
|
||||
serve_beat(32'h3000_0008, 32'h3000_0108, 64'hAABB_CCDD_EEFF_0011, 8'h0F);
|
||||
wait (done_o);
|
||||
if (err_o || busy_o) $fatal(1, "successful DMA copy reported an error");
|
||||
|
||||
@(negedge clk_i);
|
||||
timeout_i = 32'd4;
|
||||
len_i = 32'd8;
|
||||
axi4.arready = 1'b0;
|
||||
start_dma();
|
||||
wait (done_o);
|
||||
if (!err_o || (fault_addr_o != src_addr_i)) begin
|
||||
$fatal(1, "DMA no-progress timeout was not attributed to the source address");
|
||||
end
|
||||
|
||||
$display("Extension DMA copy, tail strobe, and timeout test passed");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
@@ -0,0 +1,74 @@
|
||||
`timescale 1ns / 1ps
|
||||
|
||||
module hp_lifecycle_controller_tb;
|
||||
logic clk_i = 1'b0;
|
||||
logic rst_n_i = 1'b0;
|
||||
logic release_req_i = 1'b0;
|
||||
logic hp_idle_i = 1'b0;
|
||||
logic flush_busy_i = 1'b0;
|
||||
logic hp_release_o;
|
||||
logic block_new_o;
|
||||
logic flush_o;
|
||||
logic draining_o;
|
||||
logic forced_fault_o;
|
||||
|
||||
always #5 clk_i = ~clk_i;
|
||||
|
||||
hp_lifecycle_controller u_dut (
|
||||
.clk_i (clk_i),
|
||||
.rst_n_i (rst_n_i),
|
||||
.release_req_i (release_req_i),
|
||||
.hp_idle_i (hp_idle_i),
|
||||
.flush_busy_i (flush_busy_i),
|
||||
.timeout_i (16'd4),
|
||||
.hp_release_o (hp_release_o),
|
||||
.block_new_o (block_new_o),
|
||||
.flush_o (flush_o),
|
||||
.draining_o (draining_o),
|
||||
.forced_fault_o(forced_fault_o)
|
||||
);
|
||||
|
||||
task automatic complete_flush;
|
||||
begin
|
||||
wait (flush_o);
|
||||
@(negedge clk_i);
|
||||
flush_busy_i = 1'b1;
|
||||
wait (!flush_o);
|
||||
repeat (2) @(negedge clk_i);
|
||||
flush_busy_i = 1'b0;
|
||||
wait (!hp_release_o);
|
||||
end
|
||||
endtask
|
||||
|
||||
initial begin
|
||||
repeat (2) @(posedge clk_i);
|
||||
rst_n_i = 1'b1;
|
||||
@(negedge clk_i);
|
||||
release_req_i = 1'b1;
|
||||
wait (hp_release_o);
|
||||
if (block_new_o || draining_o) $fatal(1, "released HP was unexpectedly blocked");
|
||||
|
||||
@(negedge clk_i);
|
||||
release_req_i = 1'b0;
|
||||
repeat (2) @(negedge clk_i);
|
||||
if (!block_new_o || !draining_o || !hp_release_o) begin
|
||||
$fatal(1, "normal shutdown did not enter drain while HP remained released");
|
||||
end
|
||||
hp_idle_i = 1'b1;
|
||||
complete_flush();
|
||||
if (forced_fault_o || block_new_o) $fatal(1, "normal shutdown reported a forced fault");
|
||||
|
||||
@(negedge clk_i);
|
||||
hp_idle_i = 1'b0;
|
||||
release_req_i = 1'b1;
|
||||
wait (hp_release_o);
|
||||
@(negedge clk_i);
|
||||
release_req_i = 1'b0;
|
||||
wait (flush_o);
|
||||
if (!forced_fault_o) $fatal(1, "quiesce timeout did not record a forced fault");
|
||||
complete_flush();
|
||||
|
||||
$display("HP lifecycle drain, flush, and forced reset test passed");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
@@ -164,6 +164,9 @@ module pll_ctrl_tb;
|
||||
sysctrl.perf_flash_wait_i = '0;
|
||||
sysctrl.rtc_wake_i = 1'b0;
|
||||
sysctrl.hp_present_i = 1'b0;
|
||||
sysctrl.hp_actual_released_i = 1'b0;
|
||||
sysctrl.hp_draining_i = 1'b0;
|
||||
sysctrl.hp_forced_fault_i = 1'b0;
|
||||
rst_n_i = 1'b1;
|
||||
#10;
|
||||
rst_n_i = 1'b0;
|
||||
|
||||
@@ -118,6 +118,9 @@ module sysctrl_tb;
|
||||
sysctrl.perf_flash_wait_i = 64'd18;
|
||||
sysctrl.rtc_wake_i = 1'b0;
|
||||
sysctrl.hp_present_i = 1'b0;
|
||||
sysctrl.hp_actual_released_i = 1'b0;
|
||||
sysctrl.hp_draining_i = 1'b0;
|
||||
sysctrl.hp_forced_fault_i = 1'b0;
|
||||
pll_ctrl.req_ready_i = 1'b1;
|
||||
pll_ctrl.rsp_active_sel_i = '0;
|
||||
pll_ctrl.rsp_active_valid_i = 1'b0;
|
||||
|
||||
Reference in new issue
Block a user