Commit 5f010f90 authored by Dimitris Lampridis's avatar Dimitris Lampridis

[hdl] handle host 32-bit address overflow in L2P DMA master

parent f2863fc1
......@@ -86,7 +86,14 @@ architecture behavioral of l2p_dma_master is
---------------------
-- Constants
---------------------
constant c_L2P_MAX_PAYLOAD : integer := 32;
-- L2P_MAX_PAYLOAD must be a power of 2 for easier 32-bit address overflow check.
constant c_L2P_MAX_PAYLOAD_NBITS : integer := 7;
constant c_L2P_MAX_PAYLOAD_BYTES : integer := 2 ** c_L2P_MAX_PAYLOAD_NBITS;
constant c_L2P_MAX_PAYLOAD_WORDS : integer := c_L2P_MAX_PAYLOAD_BYTES / 4;
constant c_L2P_A32_OVERFLOW_MASK : std_logic_vector(31 downto 0) :=
not std_logic_vector(to_unsigned(c_L2P_MAX_PAYLOAD_BYTES - 1, 32));
constant c_TIMEOUT : integer := 2000;
-- how many pending WB requests to allow without ACK
......@@ -330,13 +337,13 @@ begin
l2p_byte_swap <= dma_ctrl_byte_swap_i;
l2p_last_packet <= '0';
elsif (l2p_dma_current_state = L2P_SETUP) then
if (l2p_len_cnt > c_L2P_MAX_PAYLOAD) then
l2p_data_cnt <= TO_UNSIGNED(c_L2P_MAX_PAYLOAD, 13);
l2p_len_header <= TO_UNSIGNED(c_L2P_MAX_PAYLOAD, 13);
if (l2p_len_cnt > c_L2P_MAX_PAYLOAD_WORDS) then
l2p_data_cnt <= TO_UNSIGNED(c_L2P_MAX_PAYLOAD_WORDS, 13);
l2p_len_header <= TO_UNSIGNED(c_L2P_MAX_PAYLOAD_WORDS, 13);
l2p_last_packet <= '0';
elsif (l2p_len_cnt = c_L2P_MAX_PAYLOAD) then
l2p_data_cnt <= TO_UNSIGNED(c_L2P_MAX_PAYLOAD, 13);
l2p_len_header <= TO_UNSIGNED(c_L2P_MAX_PAYLOAD, 13);
elsif (l2p_len_cnt = c_L2P_MAX_PAYLOAD_WORDS) then
l2p_data_cnt <= TO_UNSIGNED(c_L2P_MAX_PAYLOAD_WORDS, 13);
l2p_len_header <= TO_UNSIGNED(c_L2P_MAX_PAYLOAD_WORDS, 13);
l2p_last_packet <= '1';
else
l2p_data_cnt <= l2p_len_cnt(12 downto 0);
......@@ -349,10 +356,15 @@ begin
end if;
elsif (l2p_dma_current_state = L2P_LAST_DATA) then
if (l2p_last_packet = '0') then
-- Increase Address
-- TODO Not overflow safe !
l2p_address_l <= std_logic_vector(unsigned(l2p_address_l) + (c_L2P_MAX_PAYLOAD * 4));
l2p_len_cnt <= l2p_len_cnt - c_L2P_MAX_PAYLOAD;
-- Increase Address, check for overflow
if (l2p_address_l and (c_L2P_A32_OVERFLOW_MASK)) = c_L2P_A32_OVERFLOW_MASK then
l2p_address_h <= std_logic_vector(unsigned(l2p_address_h) + 1);
l2p_address_l(31 downto c_L2P_MAX_PAYLOAD_NBITS) <= (others => '0');
else
l2p_address_l <= std_logic_vector(
unsigned(l2p_address_l) + (c_L2P_MAX_PAYLOAD_BYTES));
end if;
l2p_len_cnt <= l2p_len_cnt - c_L2P_MAX_PAYLOAD_WORDS;
else
l2p_len_cnt <= (others => '0');
end if;
......
......@@ -153,7 +153,7 @@ module main;
initial begin
automatic int ntest = 1;
const int tests = 7;
const int tests = 8;
uint32_t addr, val, expected;
......@@ -321,6 +321,48 @@ module main;
#1us;
end
$write("Test %0d/%0d: 256B read over DMA with 32bit host address overflow: ",
ntest++, tests);
acc.write('h14, 'h100); // count
acc.write('h20, 'h00); // attrib
acc.write('h0c, 'hffffff80); // hstartL
acc.write('h10, 'h00000000); // hstartH
acc.write('h00, 'h01); // start
// Transfer will be split internally by L2P DMA master in two requests, the first
// one with a 32-bit adress starting at ffff_ff80 and the next one with a 64-bit
// address starting at 1_0000_0000
@(posedge DUT.cmp_wrapped_gn4124.ldm_arb_dframe);
@(posedge DUT.cmp_wrapped_gn4124.sys_clk);
val_check("Host address overflow header", 1, DUT.cmp_wrapped_gn4124.ldm_arb_data, 'h02ff0020);
@(posedge DUT.cmp_wrapped_gn4124.sys_clk);
val_check("Host address overflow address", 1, DUT.cmp_wrapped_gn4124.ldm_arb_data, 'hffffff80);
@(posedge DUT.cmp_wrapped_gn4124.ldm_arb_dframe);
@(posedge DUT.cmp_wrapped_gn4124.sys_clk);
val_check("Host address overflow header", 2, DUT.cmp_wrapped_gn4124.ldm_arb_data, 'h03ff0020);
@(posedge DUT.cmp_wrapped_gn4124.sys_clk);
val_check("Host address overflow address high", 2, DUT.cmp_wrapped_gn4124.ldm_arb_data, 1);
@(posedge DUT.cmp_wrapped_gn4124.sys_clk);
val_check("Host address overflow address low", 2, DUT.cmp_wrapped_gn4124.ldm_arb_data, 0);
@(posedge dma_irq);
// Check irq status
reg_check('h04, 'h04);
if (dma_irq != 1'b1)
$fatal(1, "dma irq should be 1");
// clear irq
acc.write('h04, 'h04);
reg_check('h04, 'h00);
if (dma_irq != 1'b0)
$fatal(1, "dma irq should be 0");
repeat(4) @(posedge clk_125m);
$write("PASS\n");
$display();
$display("Simulation PASSED");
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment