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.
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:https://www.ohwr.org/fmc-projects/fmc-adc-100m14b4cha.git::mcattin_sdb
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 the sdb ROM base address*
-- sdb header address
constant c_SDB_ADDRESS : t_wishbone_address := x"00000000";
6) 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(c_NUM_WB_MASTERS-1 downto 0) :=
(
c_SLAVE_DMA => f_sdb_embed_device(c_DMA_SDB_DEVICE, x"00001000"),
c_SLAVE_ONEWIRE => f_sdb_embed_device(c_ONEWIRE_SDB_DEVICE, x"00001200"),
c_SLAVE_SPEC_CSR => f_sdb_embed_device(c_SPEC_CSR_SDB_DEVICE, x"00001300"),
c_SLAVE_UTC => f_sdb_embed_device(c_UTC_SDB_DEVICE, x"00001400"),
c_SLAVE_INT => f_sdb_embed_device(c_INT_SDB_DEVICE, x"00001500"),
c_SLAVE_FMC_SYS_I2C => f_sdb_embed_device(c_I2C_SDB_DEVICE, x"00001600"),
c_SLAVE_FMC_SPI => f_sdb_embed_device(c_SPI_SDB_DEVICE, x"00001700"),
c_SLAVE_FMC_I2C => f_sdb_embed_device(c_I2C_SDB_DEVICE, x"00001800"),
c_SLAVE_FMC_ADC => f_sdb_embed_device(c_ADC_SDB_DEVICE, x"00001900"),
c_SLAVE_FMC_ONEWIRE => f_sdb_embed_device(c_ONEWIRE_SDB_DEVICE, x"00001A00")
);
7) 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);
8) 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);
9) 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';
10) 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 - 10 December 2012