feat: add fast-flash support for Verilator simulation and XPI model

- Introduced  target in Makefile to run fast-flash HP Linux userspace acceptance tests with a 7200-second simulation time limit.
- Updated documentation to describe the new fast-flash model and its usage in simulations.
- Implemented Verilator-specific XPI core and fast flash model to handle slot-0 read operations with improved performance.
- Added new tests for the XPI fast flash model to verify protocol compliance and error handling.
- Enhanced existing tests to ensure proper integration of fast-flash features in the HP Linux simulation flow.
This commit is contained in:
maksyuki committed 2026-08-28 11:29:52 +08:00
1 parent e86187a5f3
commit 795b3a4b1d
18 files changed
+728 -6

No files matched your search

+7
View File
@@ -0,0 +1,7 @@
#include <cstdint>
extern "C" void flash_read_byte(std::uint32_t address, std::uint8_t *data) {
if (data != nullptr) {
*data = static_cast<std::uint8_t>(address);
}
}
+181
View File
@@ -0,0 +1,181 @@
`timescale 1ns / 1ps
module xpi_fast_flash_model_tb;
import xpi_pkg::*;
logic clk;
logic rst_n;
logic start;
logic abort;
logic [ 1:0] slot;
logic [31:0] timeout_cycles;
logic [31:0] address;
logic [15:0] data_length;
logic [15:0] lut [0:7];
logic rx_valid;
logic rx_ready;
logic [ 7:0] rx_data;
logic busy;
logic done;
logic error;
xpi_error_e error_code;
logic [ 2:0] error_pc;
logic byte_event;
int unsigned s_expected_address;
int unsigned s_received_count;
logic s_scoreboard_enable;
xpi_fast_flash_model u_dut (
.clk_i (clk),
.rst_n_i (rst_n),
.start_i (start),
.abort_i (abort),
.slot_i (slot),
.timeout_i (timeout_cycles),
.address_i (address),
.data_len_i (data_length),
.lut_i (lut),
.rx_valid_o (rx_valid),
.rx_ready_i (rx_ready),
.rx_data_o (rx_data),
.busy_o (busy),
.done_o (done),
.error_o (error),
.error_code_o (error_code),
.error_pc_o (error_pc),
.phy_byte_event_o(byte_event)
);
always #5 clk = ~clk;
always_ff @(posedge clk) begin
if (s_scoreboard_enable && rx_valid && rx_ready) begin
if (rx_data != 8'(s_expected_address + s_received_count)) begin
$fatal(1, "fast flash data mismatch at byte %0d", s_received_count);
end
if (!byte_event) begin
$fatal(1, "accepted byte did not raise the PHY byte event");
end
s_received_count <= s_received_count + 1;
end
end
task automatic set_default_lut;
begin
lut[0] = xpi_instr(XpiInstrCommand, 2'd0, 8'hEB);
lut[1] = xpi_instr(XpiInstrAddress, 2'd2, 8'd24);
lut[2] = xpi_instr(XpiInstrMode, 2'd2, 8'hF0);
lut[3] = xpi_instr(XpiInstrDummy, 2'd0, 8'd4);
lut[4] = xpi_instr(XpiInstrReceive, 2'd2, 8'd0);
lut[5] = xpi_instr(XpiInstrStop, 2'd0, 8'd0);
lut[6] = xpi_instr(XpiInstrStop, 2'd0, 8'd0);
lut[7] = xpi_instr(XpiInstrStop, 2'd0, 8'd0);
end
endtask
task automatic pulse_start;
begin
@(negedge clk);
start = 1'b1;
@(negedge clk);
start = 1'b0;
end
endtask
task automatic wait_for_done;
begin
while (!done) begin
@(negedge clk);
end
end
endtask
initial begin
logic [7:0] held_data;
clk = 1'b0;
rst_n = 1'b0;
start = 1'b0;
abort = 1'b0;
slot = 2'd0;
timeout_cycles = 32'd100;
address = 32'd0;
data_length = 16'd0;
rx_ready = 1'b0;
s_expected_address = 0;
s_received_count = 0;
s_scoreboard_enable = 1'b0;
set_default_lut();
repeat (3) @(negedge clk);
rst_n = 1'b1;
address = 32'h0000_01FD;
data_length = 16'd6;
s_expected_address = address;
s_received_count = 0;
s_scoreboard_enable = 1'b1;
pulse_start();
while (!rx_valid) begin
@(negedge clk);
end
held_data = rx_data;
repeat (3) begin
@(negedge clk);
if (!rx_valid || (rx_data != held_data)) begin
$fatal(1, "fast flash did not hold data during backpressure");
end
end
rx_ready = 1'b1;
wait_for_done();
if (error || (s_received_count != 6)) begin
$fatal(1, "fast flash read did not complete successfully");
end
s_scoreboard_enable = 1'b0;
rx_ready = 1'b0;
slot = 2'd1;
pulse_start();
wait_for_done();
if (!error || (error_code != XpiErrorSequence)) begin
$fatal(1, "unsupported slot did not report a sequence error");
end
slot = 2'd0;
set_default_lut();
lut[4] = xpi_instr(XpiInstrTransmit, 2'd0, 8'd0);
pulse_start();
wait_for_done();
if (!error || (error_code != XpiErrorSequence)) begin
$fatal(1, "write sequence did not report a sequence error");
end
set_default_lut();
timeout_cycles = 32'd1;
data_length = 16'd4;
pulse_start();
wait_for_done();
if (!error || (error_code != XpiErrorTimeout)) begin
$fatal(1, "expired transfer did not report a timeout");
end
timeout_cycles = 32'd100;
data_length = 16'd4;
pulse_start();
while (!busy) begin
@(negedge clk);
end
abort = 1'b1;
@(negedge clk);
abort = 1'b0;
wait_for_done();
if (!error || (error_code != XpiErrorAborted)) begin
$fatal(1, "aborted transfer did not report an abort error");
end
$display("XPI fast flash model test passed");
$finish;
end
endmodule