Guidelines to implement sdb in a hdl design
Single crossbar example:
The wishbone crossbar component implements the sdb ROM, describing the
wishbone bus structure and connected devices.
The hdl source of the wishbone crossbar are in:
git:https://www.ohwr.org/hdl-core-lib/general-cores.git
under: modules/wishbone/wb_crossbar/
Each wishbone bus device (slave, bridge, ...) is described with an sdb
record.
A record takes 64 bytes in ROM. Note that the crossbar will add a record
to the sdb ROM to describe itself.
For more information see the sdb
specification.
NOTE: The sdb_extension branch of git:https://www.ohwr.org/hdl-core-lib/general-cores.git contains a crossbar version that supports extra meta-information sdb records.
Steps to implement sdb:*
The following code has to be added to the hdl top module.
This example is taken from the
FmcAdc100M14b4cha
project.
Git
repository,
branch master.
1) Add the wishbone package*
library work;
use work.wishbone_pkg.all;
2) Add wishbone master(s) and slave(s) numbers constants*
-- Number of master port(s) on the wishbone crossbar
constant c_NUM_WB_MASTERS : integer := 10;
-- Number of slave port(s) on the wishbone crossbar
constant c_NUM_WB_SLAVES : integer := 1;
3) Add wishbone master(s) and slave(s) devices numbering*
-- Wishbone master(s)
constant c_MASTER_GENNUM : integer := 0;
-- Wishbone slave(s)
constant c_SLAVE_DMA : integer := 0; -- DMA controller in the Gennum core
constant c_SLAVE_ONEWIRE : integer := 1; -- Carrier onewire interface
constant c_SLAVE_SPEC_CSR : integer := 2; -- SPEC control and status registers
constant c_SLAVE_UTC : integer := 3; -- UTC core for time-tagging
constant c_SLAVE_INT : integer := 4; -- Interrupt controller
constant c_SLAVE_FMC_SYS_I2C : integer := 5; -- Mezzanine system I2C interface (EEPROM)
constant c_SLAVE_FMC_SPI : integer := 6; -- Mezzanine SPI interface
constant c_SLAVE_FMC_I2C : integer := 7; -- Mezzanine I2C controller
constant c_SLAVE_FMC_ADC : integer := 8; -- Mezzanine ADC core
constant c_SLAVE_FMC_ONEWIRE : integer := 9; -- Mezzanine onewire interface
4) Add devices descriptor(s)*
Add only the one not already in the wishbone package (wishbone_pkg.vhd) or in the crossbar (sdb_rom.vhd).
NOTE: Only one device descriptor is shown here.
NOTE: Addresses are in byte.
-- Devices sdb description
constant c_DMA_SDB_DEVICE : t_sdb_device := (
abi_class => x"0000",
abi_ver_major => x"01",
abi_ver_minor => x"01",
wbd_endian => c_sdb_endian_big,
wbd_width => x"7",
sdb_component => (
addr_first => x"0000000000000000",
addr_last => x"00000000000000ff",
product => (
vendor_id => x"000000000000CE42",
device_id => x"00000013",
version => x"00000001",
date => x"20121116",
name => "WB-DMA.Control ")));
5) Add meta-information descriptor(s)*
Those descriptors are optional.
They should be placed in a separate package. This is to allow an automated generation of the package by and external program (e.g. just before synthesis).
-- Top module repository url
constant c_SDB_REPO_URL : t_sdb_repo_url := (
-- url (string, 63 char)
repo_url => "git:https://www.ohwr.org/fmc-projects/fmc-adc-100m14b4cha.git ");
-- Synthesis informations
constant c_SDB_SYNTHESIS : t_sdb_synthesis := (
-- Top module name (string, 16 char)
syn_module_name => "spec_top_fmc_adc",
-- Commit ID (hex string, 128-bit = 32 char)
-- git log -1 --format="%H" | cut -c1-32
syn_commit_id => "baa41197a02acc5cbdfbc5c893849b40",
-- Synthesis tool name (string, 8 char)
syn_tool_name => "ISE ",
-- Synthesis tool version (bcd encoded, 32-bit)
syn_tool_version => x"00000133",
-- Synthesis date (bcd encoded, 32-bit)
syn_date => x"20130312",
-- Synthesised by (string, 15 char)
syn_username => "mcattin ");
-- Integration record
constant c_SDB_INTEGRATION : t_sdb_integration := (
product => (
vendor_id => x"000000000000CE42", -- CERN
device_id => x"47c786a2", -- echo "spec_fmc-adc-100m14b4cha" | md5sum | cut -c1-8
version => x"00010000", -- bcd encoded, [31:16] = major, [15:0] = minor
date => x"20130312", -- yyyymmdd
name => "spec_fmcadc100m14b "));
6) Add the sdb ROM base address*
-- sdb header address
constant c_SDB_ADDRESS : t_wishbone_address := x"00000000";
7) Add the sdb layout*
The f_sdb_embed_device function takes the device number (defined in 3) and the device base address (in byte).
-- Wishbone crossbar layout
constant c_INTERCONNECT_LAYOUT : t_sdb_record_array(12 downto 0) :=
(
0 => f_sdb_embed_device(c_DMA_SDB_DEVICE, x"00001000"),
1 => f_sdb_embed_device(c_ONEWIRE_SDB_DEVICE, x"00001200"),
2 => f_sdb_embed_device(c_SPEC_CSR_SDB_DEVICE, x"00001300"),
3 => f_sdb_embed_device(c_UTC_SDB_DEVICE, x"00001400"),
4 => f_sdb_embed_device(c_INT_SDB_DEVICE, x"00001500"),
5 => f_sdb_embed_device(c_I2C_SDB_DEVICE, x"00001600"),
6 => f_sdb_embed_device(c_SPI_SDB_DEVICE, x"00001700"),
7 => f_sdb_embed_device(c_I2C_SDB_DEVICE, x"00001800"),
8 => f_sdb_embed_device(c_ADC_SDB_DEVICE, x"00001900"),
9 => f_sdb_embed_device(c_ONEWIRE_SDB_DEVICE, x"00001A00"),
10 => f_sdb_embed_repo_url(c_SDB_REPO_URL),
11 => f_sdb_embed_synthesis(c_SDB_SYNTHESIS),
12 => f_sdb_embed_integration(c_SDB_INTEGRATION)
);
8) Add wishbone buses signals declaration*
-- Wishbone buse(s) from crossbar master port(s)
signal cnx_master_out : t_wishbone_master_out_array(c_NUM_WB_MASTERS-1 downto 0);
signal cnx_master_in : t_wishbone_master_in_array(c_NUM_WB_MASTERS-1 downto 0);
-- Wishbone buse(s) to crossbar slave port(s)
signal cnx_slave_out : t_wishbone_slave_out_array(c_NUM_WB_SLAVES-1 downto 0);
signal cnx_slave_in : t_wishbone_slave_in_array(c_NUM_WB_SLAVES-1 downto 0);
9) Add wishbone crossbar instantiation*
NOTE: All wishbone addresses coming and going to the crossbar are byte addresses.
NOTE: The generic g_num_masters means "number of wishbone master(s)
connected to slave ports of the crossbar".
And the generic g_num_slaves means "number of wishbone slave(s)
connected to master ports of the crossbar".
Therefore, the master_i/_o ports are connected to the wishbone
slave(s), while the slave_i/_o ports are connected to the wishbone
master(s).
cmp_sdb_crossbar : xwb_sdb_crossbar
generic map (
g_num_masters => c_NUM_WB_SLAVES,
g_num_slaves => c_NUM_WB_MASTERS,
g_registered => true,
g_wraparound => true,
g_layout => c_INTERCONNECT_LAYOUT,
g_sdb_addr => c_SDB_ADDRESS)
port map (
clk_sys_i => sys_clk_125,
rst_n_i => sys_rst_n,
slave_i => cnx_slave_in,
slave_o => cnx_slave_out,
master_i => cnx_master_in,
master_o => cnx_master_out);
10) Connect the wishbone master(s)*
NOTE: If the crossbar is used along with the GN4124 core, the addresses
must be converted
because the GN4124 uses 32-bit word addresses. In this case the
following code must be added.
In addition, unused signals in t_wishbone_master_in type should be
set to zero.
cmp_gn4124_core : gn4124_core
port map(
[..]
-- CSR wishbone interface (master pipelined)
csr_clk_i => sys_clk_125,
csr_adr_o => gn_wb_adr,
csr_dat_o => cnx_slave_in(c_MASTER_GENNUM).dat,
csr_sel_o => cnx_slave_in(c_MASTER_GENNUM).sel,
csr_stb_o => cnx_slave_in(c_MASTER_GENNUM).stb,
csr_we_o => cnx_slave_in(c_MASTER_GENNUM).we,
csr_cyc_o => cnx_slave_in(c_MASTER_GENNUM).cyc,
csr_dat_i => cnx_slave_out(c_MASTER_GENNUM).dat,
csr_ack_i => cnx_slave_out(c_MASTER_GENNUM).ack,
csr_stall_i => cnx_slave_out(c_MASTER_GENNUM).stall,
[..]
);
-- Convert 32-bit word address into byte address for crossbar
cnx_slave_in(c_MASTER_GENNUM).adr <= addr_from_gn4124_core(29 downto 0) & "00";
-- Convert 32-bit byte address into word address for DMA controller
addr_to_gn1424_core_dma_controller <= "00" & cnx_master_out(c_SLAVE_DMA).adr(31 downto 2);
-- Unused wishbone signals from DMA controller to crossbar
cnx_master_in(c_SLAVE_DMA).err <= '0';
cnx_master_in(c_SLAVE_DMA).rty <= '0';
cnx_master_in(c_SLAVE_DMA).int <= '0';
11) Connect the wishbone slave(s)*
WARNING: The wishbone slaves address granularity must be set to byte.
NOTE: Only one example is shown here.
cmp_carrier_onewire : xwb_onewire_master
generic map(
g_interface_mode => CLASSIC,
g_address_granularity => BYTE,
g_num_ports => 1,
g_ow_btp_normal => "5.0",
g_ow_btp_overdrive => "1.0"
)
port map(
clk_sys_i => sys_clk_125,
rst_n_i => sys_rst_n,
slave_i => cnx_master_out(c_SLAVE_ONEWIRE),
slave_o => cnx_master_in(c_SLAVE_ONEWIRE),
desc_o => open,
owr_pwren_o => carrier_owr_pwren,
owr_en_o => carrier_owr_en,
owr_i => carrier_owr_i
);
Nested crossbars example:
- See fine delay with white rabbit core: git:https://www.ohwr.org/fmc-projects/fmc-delay-1ns-8cha.git
Matthieu Cattin - 26 March 2013