Skip to content
Snippets Groups Projects
Commit 069ac755 authored by Wesley W. Terpstra's avatar Wesley W. Terpstra
Browse files

wishbone: sdb auto crossbar mapping support

parent ad44cee9
Branches
Tags
No related merge requests found
......@@ -92,7 +92,7 @@ package wishbone_pkg is
constant c_sdb_device_length : natural := 512; -- bits
subtype t_sdb_record is std_logic_vector(c_sdb_device_length-1 downto 0);
type t_sdb_record_array is array(natural range <>) of t_sdb_record;
type t_sdb_product is record
vendor_id : std_logic_vector(63 downto 0);
device_id : std_logic_vector(31 downto 0);
......@@ -139,9 +139,8 @@ package wishbone_pkg is
syn_date : std_logic_vector(31 downto 0);
syn_username : string(1 to 15);
end record t_sdb_synthesis;
-- general crossbar building functions
function f_sdb_create_array(g_enum_dev_id : boolean := false;
g_dev_id_offs : natural := 0;
......@@ -170,6 +169,12 @@ package wishbone_pkg is
function f_sdb_extract_repo_url(sdb_record : t_sdb_record) return t_sdb_repo_url;
function f_sdb_extract_synthesis(sdb_record : t_sdb_record) return t_sdb_synthesis;
-- Automatic crossbar mapping functions
function f_sdb_auto_device(device : t_sdb_device; enable : boolean := true) return t_sdb_record;
function f_sdb_auto_bridge(bridge : t_sdb_bridge; enable : boolean := true) return t_sdb_record;
function f_sdb_auto_layout(records : t_sdb_record_array) return t_sdb_record_array;
function f_sdb_auto_sdb (records : t_sdb_record_array) return t_wishbone_address;
-- For internal use by the crossbar
function f_sdb_embed_product(product : t_sdb_product) return std_logic_vector; -- (319 downto 8)
function f_sdb_embed_component(sdb_component : t_sdb_component; address : t_wishbone_address) return std_logic_vector; -- (447 downto 8)
......@@ -1130,6 +1135,136 @@ package body wishbone_pkg is
return result;
end;
function f_sdb_auto_device(device : t_sdb_device; enable : boolean)
return t_sdb_record
is
constant c_zero : t_wishbone_address := (others => '0');
variable v_empty : t_sdb_record := (others => '0');
begin
v_empty(7 downto 0) := (others => '1');
if enable then
return f_sdb_embed_device(device, c_zero);
else
return v_empty;
end if;
end f_sdb_auto_device;
function f_sdb_auto_bridge(bridge : t_sdb_bridge; enable : boolean)
return t_sdb_record
is
constant c_zero : t_wishbone_address := (others => '0');
variable v_empty : t_sdb_record := (others => '0');
begin
v_empty(7 downto 0) := (others => '1');
if enable then
return f_sdb_embed_bridge(bridge, c_zero);
else
return v_empty;
end if;
end f_sdb_auto_bridge;
subtype t_usdb_address is unsigned(63 downto 0);
type t_usdb_address_array is array(natural range <>) of t_usdb_address;
-- We map devices by placing the smallest ones first.
-- This is guaranteed to pack the maximum number of devices in the smallest space.
-- If a device has an address != 0, we leave it alone and let the crossbar confirm
-- that the address does not cause a conflict.
function f_sdb_auto_layout_helper(records : t_sdb_record_array)
return t_usdb_address_array
is
alias c_records : t_sdb_record_array(records'length-1 downto 0) is records;
constant c_zero : t_usdb_address := (others => '0');
constant c_used_entries : natural := c_records'length + 1;
constant c_rom_entries : natural := 2**f_ceil_log2(c_used_entries);
constant c_rom_bytes : natural := c_rom_entries * c_sdb_device_length / 8;
variable v_component : t_sdb_component;
variable v_sizes : t_usdb_address_array(c_records'length downto 0);
variable v_address : t_usdb_address_array(c_records'length downto 0);
variable v_map : std_logic_vector(c_records'length downto 0) := (others => '0');
variable v_cursor : unsigned(63 downto 0) := (others => '0');
variable v_increment : unsigned(63 downto 0) := (others => '0');
begin
-- First, extract the length of the devices, ignoring those not to be mapped
for i in c_records'range loop
v_component := f_sdb_extract_component(c_records(i)(447 downto 8));
v_sizes(i) := unsigned(v_component.addr_last);
v_address(i) := unsigned(v_component.addr_first);
-- Silently round up to a power of two; the crossbar will give a warning for us
for j in 62 downto 0 loop
v_sizes(i)(j) := v_sizes(i)(j+1) or v_sizes(i)(j);
end loop;
-- Only map devices/bridges at address zero
if v_address(i) = c_zero then
case c_records(i)(7 downto 0) is
when x"01" => v_map(i) := '1';
when x"02" => v_map(i) := '1';
when others => null;
end case;
end if;
end loop;
-- Assign the SDB record a spot as well
v_address(c_records'length) := (others => '0');
v_sizes(c_records'length) := to_unsigned(c_rom_bytes-1, 64);
v_map(c_records'length) := '1';
-- Start assigning addresses
for j in 0 to 63 loop
v_increment := (j => '1', others => '0');
for i in 0 to c_records'length loop
if v_map(i) = '1' and v_sizes(i)(j) = '0' then
v_map(i) := '0';
v_address(i) := v_cursor;
v_cursor := v_cursor + v_increment;
end if;
end loop;
-- Round up to the next required alignment
if v_cursor(j) = '1' then
v_cursor := v_cursor + v_increment;
end if;
end loop;
return v_address;
end f_sdb_auto_layout_helper;
function f_sdb_auto_layout(records : t_sdb_record_array)
return t_sdb_record_array
is
alias c_records : t_sdb_record_array(records'length-1 downto 0) is records;
variable v_result : t_sdb_record_array(c_records'range) := c_records;
constant c_address : t_usdb_address_array := f_sdb_auto_layout_helper(c_records);
variable v_address : t_wishbone_address;
begin
-- Put the addresses into the mapping
for i in v_result'range loop
v_address := std_logic_vector(c_address(i)(t_wishbone_address'range));
if c_records(i)(7 downto 0) = x"01" then
v_result(i) := f_sdb_embed_device(f_sdb_extract_device(v_result(i)), v_address);
end if;
if c_records(i)(7 downto 0) = x"02" then
v_result(i) := f_sdb_embed_bridge(f_sdb_extract_bridge(v_result(i)), v_address);
end if;
end loop;
return v_result;
end f_sdb_auto_layout;
function f_sdb_auto_sdb(records : t_sdb_record_array)
return t_wishbone_address
is
alias c_records : t_sdb_record_array(records'length-1 downto 0) is records;
constant c_address : t_usdb_address_array(c_records'length downto 0) := f_sdb_auto_layout_helper(c_records);
begin
return std_logic_vector(c_address(c_records'length)(t_wishbone_address'range));
end f_sdb_auto_sdb;
--**************************************************************************************************************************--
......
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