Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 3 additions & 1 deletion Bender.yml
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,11 @@ sources:
- test/hyperbus_test_dut.sv
- test/fixture_hyperbus.sv
- test/hyperbus_tb.sv
- test/dut_if.sv
- test/hyperbus_tb_pkg.sv
- test/hyperbus_pad_delay.sv
- test/dut_if.sv
- test/axi_hyper_tb.sv
- test/hyperbus_atomic_handler_tb.sv
- test/hyperbus_cfg_regs_tb.sv
- test/axi_pre_aw_drain_tb.sv
- test/hyperbus_pad_delay_direct_tb.sv
1 change: 1 addition & 0 deletions scripts/start.tcl
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,6 @@ run_test axi_hyper_tb_synchronous_one_phy sim_run_synchronous_one_phy.wlf
run_test hyperbus_atomic_handler_tb sim_run_atomic_handler.wlf
run_test hyperbus_cfg_regs_tb sim_run_cfg_regs.wlf
run_test axi_pre_aw_drain_tb sim_run_pre_aw_drain.wlf
run_test hyperbus_pad_delay_direct_tb sim_run_pad_delay_direct.wlf

quit -code $regression_failed -f
179 changes: 133 additions & 46 deletions src/backend/hyperbus_phy.sv

Large diffs are not rendered by default.

10 changes: 8 additions & 2 deletions src/backend/hyperbus_trx.sv
Original file line number Diff line number Diff line change
Expand Up @@ -97,20 +97,26 @@ module hyperbus_trx #(
.q_o ( hyper_rwds_o )
);

logic tx_data_oe_q;

// Delay output, clock enables to be synchronous with DDR-converted data
// The delayed clock also ensures t_CSS is respected at the start, end of CS
always_ff @(posedge clk_i or negedge rst_ni) begin : proc_ff_tx_delay
if (!rst_ni) begin
hyper_rwds_oe_o <= 1'b0;
hyper_dq_oe_o <= 1'b0;
tx_data_oe_q <= 1'b0;
tx_clk_ena_q <= 1'b0;
end else begin
hyper_rwds_oe_o <= tx_rwds_oe_i;
hyper_dq_oe_o <= tx_data_oe_i;
tx_data_oe_q <= tx_data_oe_i;
tx_clk_ena_q <= tx_clk_ena_i;
end
end

// Assert immediately to tolerate pad-enable latency, but retain the registered
// release so the final DDR word remains driven for a complete cycle.
assign hyper_dq_oe_o = rst_ni && (tx_data_oe_q || tx_data_oe_i);

/////////////////////
// RX data capture //
/////////////////////
Expand Down
4 changes: 4 additions & 0 deletions src/hyperbus_cfg_frontend.sv
Original file line number Diff line number Diff line change
Expand Up @@ -238,5 +238,9 @@ module hyperbus_cfg_frontend #(
for (genvar i = 0; i < hyperbus_pkg::HyperNumChips; i++) begin : gen_cfg_range_checks
`ASSERT(CfgLatencyAccessRange, staged_phy_cfg.chip[i].t_latency_access >= 4'd3,
clk_i, !rst_ni)
`ASSERT(CfgRwdsSampleFitsLatency,
({1'b0, staged_phy_cfg.chip[i].rwds_sample_delay} + 5'd2) <=
{1'b0, staged_phy_cfg.chip[i].t_latency_access},
clk_i, !rst_ni)
end
endmodule : hyperbus_cfg_frontend
14 changes: 12 additions & 2 deletions src/hyperbus_cfg_regs.sv
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,16 @@ module hyperbus_cfg_regs #(
if (reg_req_i.wstrb[2]) begin
cfg_value_valid &= reg_req_i.wdata[23:16] <= 8'd1;
end
if (reg_req_i.wstrb[0] && reg_req_i.wstrb[1]) begin
cfg_value_valid &= ({1'b0, reg_req_i.wdata[15:8]} + 9'd2) <=
{1'b0, reg_req_i.wdata[7:0]};
end else if (reg_req_i.wstrb[0]) begin
cfg_value_valid &= ({5'b0, phy_cfg_o.chip[i].rwds_sample_delay} + 9'd2) <=
{1'b0, reg_req_i.wdata[7:0]};
end else if (reg_req_i.wstrb[1]) begin
cfg_value_valid &= ({1'b0, reg_req_i.wdata[15:8]} + 9'd2) <=
{5'b0, phy_cfg_o.chip[i].t_latency_access};
end
end
if (cfg_addr == (12'h414 + i * 12'h40)) begin
if (reg_req_i.wstrb[0]) begin
Expand Down Expand Up @@ -179,8 +189,8 @@ module hyperbus_cfg_regs #(
assign cfg_hwif_in.global_cfg.capability.clock_divider.next = ClockDividerImplemented;
assign cfg_hwif_in.global_cfg.capability.staged_apply.next = 1'b1;
assign cfg_hwif_in.global_cfg.capability.error_status.next = 1'b1;
assign cfg_hwif_in.global_cfg.capability.rwds_sample_timing.next = 1'b0;
assign cfg_hwif_in.global_cfg.capability.rwds_oe_timing.next = 1'b0;
assign cfg_hwif_in.global_cfg.capability.rwds_sample_timing.next = 1'b1;
assign cfg_hwif_in.global_cfg.capability.rwds_oe_timing.next = 1'b1;
assign cfg_hwif_in.global_cfg.status.busy.next = status_busy_i;
assign cfg_hwif_in.global_cfg.status.dirty.next = status_dirty_i;
assign cfg_hwif_in.global_cfg.status.decode_error.next =
Expand Down
1 change: 1 addition & 0 deletions src/hyperbus_pkg.sv
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ package hyperbus_pkg;
WaitAddLatAccess,
Read,
Write,
WaitRwdsOe,
WaitXfer,
WaitRWR
} hyper_phy_state_t;
Expand Down
4 changes: 4 additions & 0 deletions test/axi_hyper_tb.sv
Original file line number Diff line number Diff line change
Expand Up @@ -1197,8 +1197,11 @@ module axi_hyper_tb
if (s_reg_error != 1'b0) $error("unexpected error");
reg_master.send_write(32'h300, TbTxDelayLineTaps, '1, s_reg_error);
if (s_reg_error != 1'b0) $error("unexpected error");
reg_master.send_write(32'h304, 8'd2, '1, s_reg_error);
if (s_reg_error != 1'b0) $error("unexpected RWDS OE timing write");
if (NumPhys == 2) begin
reg_master.send_write(32'h340, TbTxDelayLineTaps + 1, '1, s_reg_error);
reg_master.send_write(32'h344, 8'd3, '1, s_reg_error);
end
reg_master.send_read(32'h010, reg_read, s_reg_error);
if (s_reg_error != 1'b0 || !reg_read[2]) $error("staged configuration did not set STATUS.dirty");
Expand Down Expand Up @@ -1374,6 +1377,7 @@ module axi_hyper_tb
.rst_ni ( rst_n ),
.end_sim_i ( end_of_sim ),
.segment_start_count_o ( segment_start_count ),
.pad_delay_cfg_i ( '0 ),
.axi_slv_if ( axi_dut_intf ),
.reg_slv_if ( reg_bus_mst )
);
Expand Down
111 changes: 82 additions & 29 deletions test/dut_if.sv
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,14 @@ module dut_if
parameter int IsClockODelayed = -1,
parameter int unsigned DutVariant = 0,
parameter time PhyCyclTime = 6ns,
parameter time PadDelayTickCyclTime = 5ns,
parameter type axi_rule_t = logic
)(
input logic clk_i,
input logic rst_ni,
input logic end_sim_i,
output logic [31:0] segment_start_count_o,
input hyperbus_tb_pkg::pad_delay_cfg_t pad_delay_cfg_i,

AXI_BUS.Slave axi_slv_if,
REG_BUS.in reg_slv_if
Expand Down Expand Up @@ -85,15 +87,57 @@ module dut_if
logic [NumPhys-1:0] hyper_dq_oe;
logic [NumPhys-1:0] hyper_reset_n_wire;
logic phy_clk;
logic pad_delay_tick_clk;
logic [NumPhys-1:0][hyperbus_pkg::HyperNumChips-1:0] hyper_cs_n_q;
logic segment_start;

logic [NumPhys-1:0][hyperbus_pkg::HyperNumChips-1:0] hyper_cs_n_pad;
logic [NumPhys-1:0] hyper_ck_pad;
logic [NumPhys-1:0] hyper_ck_n_pad;
logic [NumPhys-1:0] hyper_rwds_o_pad;
logic [NumPhys-1:0] hyper_rwds_oe_pad;
logic [NumPhys-1:0][7:0] hyper_dq_o_pad;
logic [NumPhys-1:0] hyper_dq_oe_pad;
logic [NumPhys-1:0] hyper_reset_n_pad;
logic [NumPhys-1:0] hyper_rwds_i_pad;
logic [NumPhys-1:0][7:0] hyper_dq_i_pad;

wire [NumPhys-1:0][NumConnectedChips-1:0] pad_hyper_csn;
wire [NumPhys-1:0] pad_hyper_ck;
wire [NumPhys-1:0] pad_hyper_ckn;
wire [NumPhys-1:0] pad_hyper_rwds;
wire [NumPhys-1:0] pad_hyper_reset;
wire [NumPhys-1:0][7:0] pad_hyper_dq;

hyperbus_pad_delay #(
.NumPhys ( NumPhys ),
.NumConnectedChips ( NumConnectedChips ),
.NumChips ( hyperbus_pkg::HyperNumChips )
) i_pad_delay (
.tick_i ( pad_delay_tick_clk ),
.rst_ni ( rst_ni ),
.cfg_i ( pad_delay_cfg_i ),
.cs_n_i ( hyper_cs_n_wire ),
.ck_i ( hyper_ck_wire ),
.ck_n_i ( hyper_ck_n_wire ),
.rwds_o_i ( hyper_rwds_o ),
.dq_o_i ( hyper_dq_o ),
.reset_n_i ( hyper_reset_n_wire ),
.dq_oe_i ( hyper_dq_oe ),
.rwds_oe_i ( hyper_rwds_oe ),
.cs_n_o ( hyper_cs_n_pad ),
.ck_o ( hyper_ck_pad ),
.ck_n_o ( hyper_ck_n_pad ),
.rwds_o_o ( hyper_rwds_o_pad ),
.dq_o_o ( hyper_dq_o_pad ),
.reset_n_o ( hyper_reset_n_pad ),
.dq_oe_o ( hyper_dq_oe_pad ),
.rwds_oe_o ( hyper_rwds_oe_pad ),
.rwds_i_pad ( hyper_rwds_i_pad ),
.dq_i_pad ( hyper_dq_i_pad ),
.rwds_i ( hyper_rwds_i ),
.dq_i ( hyper_dq_i )
);

axi_chan_logger #(
.aw_chan_t ( axi_aw_chan_t ),
Expand Down Expand Up @@ -137,6 +181,15 @@ module dut_if
end
end

initial begin
pad_delay_tick_clk = 1'b0;
#(real'(PadDelayTickCyclTime) / 8.0);
forever begin
#(real'(PadDelayTickCyclTime) / 4.0);
pad_delay_tick_clk = ~pad_delay_tick_clk;
end
end

assign segment_start = |(hyper_cs_n_q & ~hyper_cs_n_wire);

always_ff @(posedge clk_i or negedge rst_ni) begin
Expand Down Expand Up @@ -199,22 +252,22 @@ module dut_if
for (genvar j=0; j<NumConnectedChips; j++) begin : chips

s27ks0641 #(
/*.mem_file_name ( "s27ks0641.mem" ),*/
.TimingModel ( "S27KS0641DPBHI020" )
) dut (
.DQ7 ( pad_hyper_dq[i][7] ),
.DQ6 ( pad_hyper_dq[i][6] ),
.DQ5 ( pad_hyper_dq[i][5] ),
.DQ4 ( pad_hyper_dq[i][4] ),
.DQ3 ( pad_hyper_dq[i][3] ),
.DQ2 ( pad_hyper_dq[i][2] ),
.DQ1 ( pad_hyper_dq[i][1] ),
.DQ0 ( pad_hyper_dq[i][0] ),
.RWDS ( pad_hyper_rwds[i] ),
.CSNeg ( pad_hyper_csn[i][j] ),
.CK ( pad_hyper_ck[i] ),
.CKNeg ( pad_hyper_ckn[i] ),
.RESETNeg ( pad_hyper_reset[i] )
/*.mem_file_name ( "s27ks0641.mem" ),*/
.TimingModel ( "S27KS0641DPBHI020" )
) dut (
.DQ7 ( pad_hyper_dq[i][7] ),
.DQ6 ( pad_hyper_dq[i][6] ),
.DQ5 ( pad_hyper_dq[i][5] ),
.DQ4 ( pad_hyper_dq[i][4] ),
.DQ3 ( pad_hyper_dq[i][3] ),
.DQ2 ( pad_hyper_dq[i][2] ),
.DQ1 ( pad_hyper_dq[i][1] ),
.DQ0 ( pad_hyper_dq[i][0] ),
.RWDS ( pad_hyper_rwds[i] ),
.CSNeg ( pad_hyper_csn[i][j] ),
.CK ( pad_hyper_ck[i] ),
.CKNeg ( pad_hyper_ckn[i] ),
.RESETNeg ( pad_hyper_reset[i] )
);
end // block: chips
end // block: hyperrams
Expand All @@ -235,20 +288,20 @@ module dut_if

for (genvar i = 0 ; i<NumPhys; i++) begin: pad_gen
for (genvar j = 0; j<NumConnectedChips; j++) begin
pad_functional_pd padinst_hyper_csno (.OEN( 1'b0 ), .I( hyper_cs_n_wire[i][j] ), .O( ), .PAD( pad_hyper_csn[i][j] ), .PEN( 1'b0 ));
pad_functional_pd padinst_hyper_csno (.OEN( 1'b0 ), .I( hyper_cs_n_pad[i][j] ), .O( ), .PAD( pad_hyper_csn[i][j] ), .PEN( 1'b0 ));
end
pad_functional_pd padinst_hyper_ck (.OEN( 1'b0 ), .I( hyper_ck_wire[i] ), .O( ), .PAD( pad_hyper_ck[i] ), .PEN( 1'b0 ) );
pad_functional_pd padinst_hyper_ckno (.OEN( 1'b0 ), .I( hyper_ck_n_wire[i] ), .O( ), .PAD( pad_hyper_ckn[i] ), .PEN( 1'b0 ) );
pad_functional_pd padinst_hyper_rwds (.OEN(~hyper_rwds_oe[i]), .I( hyper_rwds_o[i] ), .O( hyper_rwds_i[i] ), .PAD( pad_hyper_rwds[i] ), .PEN( 1'b0 ) );
pad_functional_pd padinst_hyper_resetn (.OEN( 1'b0 ), .I( hyper_reset_n_wire[i] ), .O( ), .PAD( pad_hyper_reset[i] ), .PEN( 1'b0 ) );
pad_functional_pd padinst_hyper_dqio0 (.OEN(~hyper_dq_oe[i] ), .I( hyper_dq_o[i][0] ), .O( hyper_dq_i[i][0] ), .PAD( pad_hyper_dq[i][0] ), .PEN( 1'b0 ) );
pad_functional_pd padinst_hyper_dqio1 (.OEN(~hyper_dq_oe[i] ), .I( hyper_dq_o[i][1] ), .O( hyper_dq_i[i][1] ), .PAD( pad_hyper_dq[i][1] ), .PEN( 1'b0 ) );
pad_functional_pd padinst_hyper_dqio2 (.OEN(~hyper_dq_oe[i] ), .I( hyper_dq_o[i][2] ), .O( hyper_dq_i[i][2] ), .PAD( pad_hyper_dq[i][2] ), .PEN( 1'b0 ) );
pad_functional_pd padinst_hyper_dqio3 (.OEN(~hyper_dq_oe[i] ), .I( hyper_dq_o[i][3] ), .O( hyper_dq_i[i][3] ), .PAD( pad_hyper_dq[i][3] ), .PEN( 1'b0 ) );
pad_functional_pd padinst_hyper_dqio4 (.OEN(~hyper_dq_oe[i] ), .I( hyper_dq_o[i][4] ), .O( hyper_dq_i[i][4] ), .PAD( pad_hyper_dq[i][4] ), .PEN( 1'b0 ) );
pad_functional_pd padinst_hyper_dqio5 (.OEN(~hyper_dq_oe[i] ), .I( hyper_dq_o[i][5] ), .O( hyper_dq_i[i][5] ), .PAD( pad_hyper_dq[i][5] ), .PEN( 1'b0 ) );
pad_functional_pd padinst_hyper_dqio6 (.OEN(~hyper_dq_oe[i] ), .I( hyper_dq_o[i][6] ), .O( hyper_dq_i[i][6] ), .PAD( pad_hyper_dq[i][6] ), .PEN( 1'b0 ) );
pad_functional_pd padinst_hyper_dqio7 (.OEN(~hyper_dq_oe[i] ), .I( hyper_dq_o[i][7] ), .O( hyper_dq_i[i][7] ), .PAD( pad_hyper_dq[i][7] ), .PEN( 1'b0 ) );
pad_functional_pd padinst_hyper_ck (.OEN( 1'b0 ), .I( hyper_ck_pad[i] ), .O( ), .PAD( pad_hyper_ck[i] ), .PEN( 1'b0 ) );
pad_functional_pd padinst_hyper_ckno (.OEN( 1'b0 ), .I( hyper_ck_n_pad[i] ), .O( ), .PAD( pad_hyper_ckn[i] ), .PEN( 1'b0 ) );
pad_functional_pd padinst_hyper_rwds (.OEN(~hyper_rwds_oe_pad[i]), .I( hyper_rwds_o_pad[i] ), .O( hyper_rwds_i_pad[i] ), .PAD( pad_hyper_rwds[i] ), .PEN( 1'b0 ) );
pad_functional_pd padinst_hyper_resetn (.OEN( 1'b0 ), .I( hyper_reset_n_pad[i] ), .O( ), .PAD( pad_hyper_reset[i] ), .PEN( 1'b0 ) );
pad_functional_pd padinst_hyper_dqio0 (.OEN(~hyper_dq_oe_pad[i]), .I( hyper_dq_o_pad[i][0] ), .O( hyper_dq_i_pad[i][0] ), .PAD( pad_hyper_dq[i][0] ), .PEN( 1'b0 ) );
pad_functional_pd padinst_hyper_dqio1 (.OEN(~hyper_dq_oe_pad[i]), .I( hyper_dq_o_pad[i][1] ), .O( hyper_dq_i_pad[i][1] ), .PAD( pad_hyper_dq[i][1] ), .PEN( 1'b0 ) );
pad_functional_pd padinst_hyper_dqio2 (.OEN(~hyper_dq_oe_pad[i]), .I( hyper_dq_o_pad[i][2] ), .O( hyper_dq_i_pad[i][2] ), .PAD( pad_hyper_dq[i][2] ), .PEN( 1'b0 ) );
pad_functional_pd padinst_hyper_dqio3 (.OEN(~hyper_dq_oe_pad[i]), .I( hyper_dq_o_pad[i][3] ), .O( hyper_dq_i_pad[i][3] ), .PAD( pad_hyper_dq[i][3] ), .PEN( 1'b0 ) );
pad_functional_pd padinst_hyper_dqio4 (.OEN(~hyper_dq_oe_pad[i]), .I( hyper_dq_o_pad[i][4] ), .O( hyper_dq_i_pad[i][4] ), .PAD( pad_hyper_dq[i][4] ), .PEN( 1'b0 ) );
pad_functional_pd padinst_hyper_dqio5 (.OEN(~hyper_dq_oe_pad[i]), .I( hyper_dq_o_pad[i][5] ), .O( hyper_dq_i_pad[i][5] ), .PAD( pad_hyper_dq[i][5] ), .PEN( 1'b0 ) );
pad_functional_pd padinst_hyper_dqio6 (.OEN(~hyper_dq_oe_pad[i]), .I( hyper_dq_o_pad[i][6] ), .O( hyper_dq_i_pad[i][6] ), .PAD( pad_hyper_dq[i][6] ), .PEN( 1'b0 ) );
pad_functional_pd padinst_hyper_dqio7 (.OEN(~hyper_dq_oe_pad[i]), .I( hyper_dq_o_pad[i][7] ), .O( hyper_dq_i_pad[i][7] ), .PAD( pad_hyper_dq[i][7] ), .PEN( 1'b0 ) );
end

endmodule
6 changes: 5 additions & 1 deletion test/hyperbus_cfg_regs_tb.sv
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ module hyperbus_cfg_regs_tb;
reg_read(32'h004, data);
if (data != 32'h0001_0000) $error("REG_IF version reset mismatch: %h", data);
reg_read(32'h008, data);
if (data != 32'h003f_0208) $error("capability fields mismatch: %h", data);
if (data != 32'h00ff_0208) $error("capability fields mismatch: %h", data);
reg_read(32'h400, data);
if (data != 32'h0000_0000) $fatal(1, "chip0 base reset mismatch");
reg_read(32'h418, data);
Expand Down Expand Up @@ -155,6 +155,10 @@ module hyperbus_cfg_regs_tb;
reg_write_error(32'h44c, 32'h0000_0002, 4'b0001);
reg_read(32'h44c, data);
if (data != 32'h0001_0307) $error("invalid latency write changed the register: %h", data);
reg_write_error(32'h44c, 32'h0000_0004, 4'b0001);
reg_write_error(32'h44c, 32'h0000_0600, 4'b0010);
reg_read(32'h44c, data);
if (data != 32'h0001_0307) $error("inconsistent sample timing changed the register: %h", data);
reg_read_error(32'h104);
reg_read_error(32'h1000);

Expand Down
Loading