Files
lt16lab/soc/lib/wishbone.vhd
Thomas Fehmel 657a54ba18 Initial Commit
2016-10-18 14:21:45 +02:00

708 lines
21 KiB
VHDL

-- See the file "LICENSE" for the full license governing this code. --
-- This is a Package defining the Internal Interfaces and Constants of the Bus Bridge
-- Signal naming conventions: input signals end with _i, output signals end with _o
-- Signals inside of Records do not have these endings
--
-- Constants names are written uppercase
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.all;
use work.lt16x32_global.all;
package wishbone is
constant DEBUG: boolean := true;
type endian_type is (big, little);
-- Configuration of the Wishbone Bus (every non-derived constant must be a power of 2)
constant WB_PORT_SIZE: integer := 32; -- Data Port Bitwidth
constant WB_PORT_GRAN: integer := 8; -- Data Port Granularity (Bitsize of smallest addressable unit)
constant WB_MAX_OPSIZE: integer := WB_PORT_SIZE; -- Maximum Operand Size
constant WB_ENDIANESS: endian_type := big; -- Endianess, 0 => Little Endian, 1 => Big Endian
constant WB_ADR_WIDTH: integer := 32; -- Length of Bus Addresses
constant WB_ADR_BOUND: integer := 2; -- lower boundary of Address, derived from PORT_SIZE and PORT_GRAN ( log2(SEL_WIDTH) ), number of Adress Bits which can not be used
constant WB_SEL_WIDTH: integer := WB_PORT_SIZE/WB_PORT_GRAN; -- Bitwidth of the select signal (sel_I/O), number of min size units that fit on data bus (WB_PORT_SIZE/WB_PORT_GRAN)
constant NWBMST: integer :=4; --Number of Wishbone master connectors on the Interconnect
constant NWBSLV: integer :=16; --Number of Wishbone slave connectors on the Interconnect
subtype wb_addr_type is std_logic_vector(WB_ADR_WIDTH-1 downto WB_ADR_BOUND);
constant zadr : wb_addr_type := (others => '0');
constant zdat : std_logic_vector(WB_PORT_SIZE-1 downto 0):= (others=>'0');
constant zslv22: std_logic_vector(21 downto 0) := (others=>'0');
constant zadr32 : std_logic_vector(31 downto 0):= (others=>'0');
constant dc32: std_logic_vector(31 downto 0):= (others=>'-');
--
-- ----------------------------------------------------------------------------------------
-- -- master:data tag signals (input and output)
-- type wb_tag_mst_i_data_type is record
-- dc: std_logic;
-- end record;
--
-- type wb_tag_mst_o_data_type is record
-- dc: std_logic;
-- end record;
--
-- -- address tag signals (input and output)
-- type wb_tag_mst_i_adr_type is record
-- dc: std_logic;
-- end record;
--
-- type wb_tag_mst_o_adr_type is record
-- dc: std_logic;
-- end record;
--
-- -- cycle tag signals (input and output)
-- type wb_tag_mst_i_cyc_type is record
-- dc: std_logic;
-- end record;
--
-- type wb_tag_mst_o_cyc_type is record
-- dc: std_logic;
-- end record;
-- -- slv:data tag signals (input and output)
-- type wb_tag_slv_i_data_type is record
-- dc: std_logic;
-- end record;
--
-- type wb_tag_slv_o_data_type is record
-- dc: std_logic;
-- end record;
--
-- -- address tag signals (input and output)
-- type wb_tag_slv_i_adr_type is record
-- dc: std_logic;
-- end record;
--
-- type wb_tag_slv_o_adr_type is record
-- dc: std_logic;
-- end record;
--
-- -- cycle tag signals (input and output)
-- type wb_tag_slv_i_cyc_type is record
-- dc: std_logic;
-- end record;
--
-- type wb_tag_slv_o_cyc_type is record
-- dc: std_logic;
-- end record;
-- ----------------------------------------------------------------------------------------
-- -- tag types
-- ----------------------------------------------------------------------------------------
-- -- master input tag signals
-- type wb_tag_mst_i_type is record
-- tgd: wb_tag_mst_i_data_type;
-- tga: wb_tag_mst_i_adr_type;
-- tgc: wb_tag_mst_i_cyc_type;
-- end record;
--
-- -- master output tag signals
-- type wb_tag_mst_o_type is record
-- tgd: wb_tag_mst_o_data_type;
-- tga: wb_tag_mst_o_adr_type;
-- tgc: wb_tag_mst_o_cyc_type;
-- end record;
--
-- -- slave input tag signals
-- type wb_tag_slv_i_type is record
-- tgd: wb_tag_slv_i_data_type;
-- tga: wb_tag_slv_i_adr_type;
-- tgc: wb_tag_slv_i_cyc_type;
-- end record;
--
-- -- slave output tag signals
-- type wb_tag_slv_o_type is record
-- tgd: wb_tag_slv_o_data_type;
-- tga: wb_tag_slv_o_adr_type;
-- tgc: wb_tag_slv_o_cyc_type;
-- end record;
--
-- ----------------------------------------------------------------------------------------
-- -- Wishbone Clock and Reset
-- type wb_sys_type is record
-- rst: std_logic;
-- clk: std_logic;
-- end record;
subtype wb_config_type is std_logic_vector(63 downto 0);
--Cycle type identifier:
--000: Classic cycle, 001: Constant address burst, 010: Incrementing burst
--111: End-of-Burst
subtype wb_tag_cti_io is std_logic_vector(2 downto 0);
--Burst type extension:
--00: Linear burst, 01: 4-beat wrap burst
--10: 8-beat wrap burst, 11: 16-beat wrap burst
subtype wb_tag_bte_io is std_logic_vector(1 downto 0);
-- Wishbone Master Input Signals
type wb_mst_in_type is record
dat: std_logic_vector(WB_PORT_SIZE-1 downto 0);
ack: std_logic;
--tagn: wb_tag_mst_i_type;
--stall: std_logic;
--err: std_logic;
--rty: std_logic;
end record;
-- Wishbone Master Output Signals
type wb_mst_out_type is record
adr : wb_addr_type;
dat : std_logic_vector(WB_PORT_SIZE-1 downto 0);
we : std_logic;
sel : std_logic_vector(WB_SEL_WIDTH-1 downto 0);
stb : std_logic;
cyc : std_logic;
cti : wb_tag_cti_io;
bte : wb_tag_bte_io;
--tagn: wb_tag_mst_o_type;
--lock: std_logic;
--wbcfg: wb_config_type; -- memory access reg.
end record;
-- Wishbone Slave Input Signals
-- type wb_slv_in_type is record
-- adr : wb_addr_type;
-- dat : std_logic_vector(WB_PORT_SIZE-1 downto 0);
-- we : std_logic;
-- sel : std_logic_vector(WB_SEL_WIDTH-1 downto 0);
-- stb : std_logic;
-- cyc : std_logic;
-- cti : wb_tag_cti_io;
-- bte : wb_tag_bte_io;
-- --tagn: wb_tag_slv_o_type;
-- --lock: std_logic;
-- end record;
subtype wb_slv_in_type is wb_mst_out_type;
-- Wishbone Slave Output Signals
type wb_slv_out_type is record
dat: std_logic_vector(WB_PORT_SIZE-1 downto 0);
ack: std_logic;
--tagn: wb_tag_slv_i_type;
--stall: std_logic;
--err: std_logic;
--rty: std_logic;
wbcfg : wb_config_type; -- memory access reg.
end record;
--
--array types
--
type wb_mst_out_vector_type is array (natural range <>) of wb_mst_out_type;
type wb_mst_in_vector_type is array (natural range <>) of wb_mst_in_type;
type wb_slv_out_vector_type is array (natural range <>) of wb_slv_out_type;
type wb_slv_in_vector_type is array (natural range <>) of wb_slv_in_type;
subtype wb_mst_out_vector is wb_mst_out_vector_type(NWBMST-1 downto 0);
subtype wb_slv_out_vector is wb_slv_out_vector_type(NWBSLV-1 downto 0);
subtype wb_mst_in_vector is wb_mst_in_vector_type(NWBMST-1 downto 0);
subtype wb_slv_in_vector is wb_slv_in_vector_type(NWBSLV-1 downto 0);
--30 bits
subtype generic_addr_type is integer range 0 to 16#7fffffff#;
subtype generic_mask_type is integer range 0 to 16#7fffffff#; --lowest 2 get disregarded
constant wbm_in_none : wb_mst_in_type :=
( zdat, --data
'0' --ack
--(others=>'0'), --tagn
--'0' --stall
--'0', --err
--'0' --rty
);
constant wbm_out_none : wb_mst_out_type :=
( zadr, -- adr
zdat, -- dat
'0', -- we
(others => '0'), -- sel
'0', -- stb
'0', -- cyc
"000", -- cti
"00" -- bte
--(others => '0'), -- tagn
--'0' --lock
);
constant wbs_in_none: wb_slv_in_type :=
( zadr, -- adr
zdat, -- dat
'0', -- we
(others => '0'), -- sel
'0', -- stb
'0', -- cyc
"000", -- cti
"00" -- bte
--(others => '0'), -- tagn
--'0' --lock
);
constant wbs_out_none: wb_slv_out_type :=
( zdat, -- dat
'0', -- ack
--(others=>'0'), --tagn
--'0', --stall
--'0', --err
--'0', --rty
(others=>'1') --cfg
);
-- function to calculate a valid sel signal (see Wishbone Specification B4 Page 58 ff.)
function select_bytes(
address: std_logic_vector;
len: std_logic_vector; -- number of Granularity sized Units transferred
sel: std_logic_vector
) return std_logic_vector;
function wb_membar(
memaddr : generic_addr_type;
addrmask : generic_mask_type)
return std_logic_vector;
function slvadrmap(
cfg : std_logic_vector(63 downto 0);
mstadr : wb_addr_type
)
return boolean;
function gen_select(
adr : std_logic_vector(1 downto 0); -- core_adr
sz : std_logic_vector(1 downto 0)
)
return std_logic_vector;
function decsz(
sel : std_logic_vector(WB_SEL_WIDTH-1 downto 0)
)
return std_logic_vector;
function sel2adr(
sel: std_logic_vector(WB_SEL_WIDTH-1 downto 0)
)
return std_logic_vector;
function enc_wb_dat(
wradr : std_logic_vector(1 downto 0);
wrsz : std_logic_vector(1 downto 0);
din : std_logic_vector(memory_width - 1 downto 0)
)
return std_logic_vector;
function dec_wb_dat(
sel : std_logic_vector(WB_SEL_WIDTH-1 downto 0);
din : std_logic_vector(WB_PORT_SIZE-1 downto 0)
)
return std_logic_vector;
----------------------------------------------------------------------------------------
-- end package definition
----------------------------------------------------------------------------------------
end;
package body wishbone is
function select_bytes(
address: std_logic_vector; -- least significant bits which determine the select signal
len: std_logic_vector; -- number of Granularity sized Units transferred
sel: std_logic_vector -- signal which is to set
) return std_logic_vector is
-- declarate and initialize variables
-- initialize result with 1 (dec)
variable res: unsigned(sel'range) := (others => '0');
-- convert length to unsigned
variable len_u: unsigned(WB_ADR_BOUND-1 downto 0) := unsigned(len);
-- zero vector for comparison with 0
variable len_zero: unsigned(WB_ADR_BOUND-1 downto 0) := (others => '0');
-- full select signal
variable sel_full: std_logic_vector(sel'range) := (others => '1');
begin
-- initialization
res(0) := '1';
-- handle special case: len=0 = max length
if (len_u = len_zero) then
return std_logic_vector(sel_full);
end if;
-- check if Bitwidths are valid
--if (DEBUG = true) then
assert (sel'length = 2**address'length)
report "Wishbone, function select_byte: array lengths of address and sel argument do not match, please check your Bitwidths configuration"
severity failure;
--end if;
-- create result vector for case len = 1 (dec)
for i in address'range loop
if (address(i) = '1') then
res := res sll i+1;
end if;
end loop;
-- exponentially expand result vector ones when length > 1 (dec)
for j in address'range loop
len_u := len_u sll 1;
if not(len_u = len_zero) then
for i in 0 to (WB_SEL_WIDTH/2)-1 loop
res(2*i+1 downto 2*i) := ( others => ( res(2*i) OR res(2*i+1) ) );
end loop;
end if;
end loop;
return std_logic_vector(res);
end; -- end function
---------------------------------------------------------------
-- Function: wb_membar(memaddr, addrmask)
--
-- This function reformat the slave address and mask to support address mapping in slvadrmap function
-- The function will put both the mem address and mask into a field.
-- input: memaddr(30 bits) = base address, addrmask(22 bits)
-- output: cfg (64 bits)
--
-- base_addr[63:34], 30b
-- mask_addr[31: 2], 30b = {FF, 22b}
---------------------------------------------------------------
function wb_membar(
memaddr : generic_addr_type;
addrmask : generic_mask_type)
return std_logic_vector is
variable cfg : std_logic_vector(63 downto 0);
begin
--base_addr[63:34], 30b
--mask_addr[31: 2], 30b = {FF, 22b}
--slv_exist = cfg(0);
cfg(63 downto 32) := std_logic_vector(to_unsigned(memaddr , WB_ADR_WIDTH)); -- 31 b
--cfg(33 downto 32) := (others=>'0'); --2 bits (free)
--cfg(31 downto 24) := x"FF"; -- fixed, nonmaskable
cfg(31 downto 0) := std_logic_vector(to_unsigned(addrmask, WB_ADR_WIDTH)); --31b
--cfg( 1 downto 0) := "00"; --(free)
return(cfg);
end;
---------------------------------------------------------------
-- Function: slvadrmap(cfg, mstadr)
--
-- This function compares the request address from master to slave address (slvo.cfg)
-- slvo.cfg contains its address and mask to identify its address range
-- For non-exist slave, there will be no wb_membar function call in order to format the cfg e.g. setting cfg(31 downto 24) = x"FF"
-- therefore the cfg always return all zeros including the default masking portion
-- besides checking nonexist slave from cfg(31 downto 24) = x"00", slave_mask_vector is another alternative way
-- but the function need to input slave_mask_vector
---------------------------------------------------------------
function slvadrmap(
cfg : std_logic_vector(63 downto 0);
mstadr : wb_addr_type
)
return boolean is
variable mmap: std_logic_vector(29 downto 0) := (others=>'0');
variable addrmapflag: boolean := false;
begin
--base_addr = cfg[63:34], 30b
--mask_addr = cfg[31: 2], 30b
--mmap = (base_addr ^ mstreq_baseaddr) and mask_addr)
-----------------------------------------------------
mmap := (cfg(63 downto 34) xor mstadr) and cfg(31 downto 2);
if (mmap = (mmap'range => '0')) then
addrmapflag := true;
else
addrmapflag := false;
end if;
return(addrmapflag);
end;
---------------------------------------------------------------
-- Function: gen_select(Address(1 downto 0),ACCESS_SIZE)
-- for the 2 LSBs of an address, returns the WB select signal
-- for a given ACCESS_SIZE{BYTE,HALFWORD,WORD}
---------------------------------------------------------------
function gen_select(
adr : std_logic_vector(1 downto 0);
sz : std_logic_vector(1 downto 0)
)
return std_logic_vector is
variable sel_out :std_logic_vector(WB_SEL_WIDTH-1 downto 0) := (others=>'0');
begin
if WB_ENDIANESS = big then
--if WB_ENDIANESS = little then
case (sz) is
when "00" =>
--SIZE: BYTE
if (adr = "11") then sel_out := "0001";
elsif (adr = "10") then sel_out := "0010";
elsif (adr = "01") then sel_out := "0100";
elsif (adr = "00") then sel_out := "1000";
else sel_out := (others=>'0');
end if;
when "01" =>
--SIZE: HALFWORD
if (adr = "10") then sel_out := "0011";
elsif (adr = "11") then sel_out := "0011";
elsif (adr = "01") then sel_out := "1100";
elsif (adr = "00") then sel_out := "1100";
else sel_out := (others=>'0');
end if;
when "10" =>
--SIZE: WORD
sel_out := (others => '1');
when others =>
sel_out := (others=>'0');
end case;
else
case (sz) is
when "00" =>
--SIZE: BYTE
if (adr = "00") then sel_out := "0001";
elsif (adr = "01") then sel_out := "0010";
elsif (adr = "10") then sel_out := "0100";
elsif (adr = "11") then sel_out := "1000";
else sel_out := (others=>'0');
end if;
when "01" =>
--SIZE: HALFWORD
if (adr = "00") then sel_out := "0011";
elsif (adr = "01") then sel_out := "0011";
elsif (adr = "10") then sel_out := "1100";
elsif (adr = "11") then sel_out := "1100";
else sel_out := (others=>'0');
end if;
when "10" =>
--SIZE: WORD
sel_out := (others => '1');
when others =>
sel_out := (others=>'0');
end case;
end if;
return(sel_out);
end;
---------------------------------------------------------------
-- Function: sel2adr(port_gran, wbsel) - decselwb2mem
-- to retrieve last 2 bits address for core
-- big endian
---------------------------------------------------------------
function sel2adr(
sel : std_logic_vector(WB_SEL_WIDTH-1 downto 0)
)
return std_logic_vector is
variable adr :std_logic_vector(1 downto 0) := (others=>'0');
begin
if WB_ENDIANESS = big then
case WB_PORT_GRAN is
when 8 =>
case sel is
when "1000" => adr := "00";
when "0100" => adr := "01";
when "0010" => adr := "10";
when "0001" => adr := "11";
when "1100" => adr := "00";
when "0011" => adr := "10";
when "1111" => adr := "00";
when others => adr := "11";
end case;
when 16 =>
--untested! do not use without (extensive) testing
if sel(1 downto 0) = "10" then adr := "00";
elsif sel(1 downto 0) = "11" then adr := "01";
elsif sel(1 downto 0) = "01" then adr := "10";
else adr := "00";
end if;
when others =>
--untested! do not use without (extensive) testing
adr := "00";
end case;
else
case WB_PORT_GRAN is
when 8 =>
case sel is
when "0001" => adr := "00";
when "0010" => adr := "01";
when "0100" => adr := "10";
when "1000" => adr := "11";
when "0011" => adr := "00";
when "1100" => adr := "10";
when "1111" => adr := "00";
when others => adr := "00";
end case;
when 16 =>
--untested! do not use without (extensive) testing
if sel(1 downto 0) = "01" then adr := "00";
elsif sel(1 downto 0) = "11" then adr := "01";
elsif sel(1 downto 0) = "10" then adr := "10";
else adr := "00";
end if;
when others =>
--untested! do not use without (extensive) testing
adr := "00";
end case;
end if;
return(adr);
end;
---------------------------------------------------------------
-- Function: enc_wb_dat (byte addr,ACCESS_SIZE,DATA)
-- Encodes a 32-bit input vector to a WB data word,
-- depending on the provided byte address and ACCESS_SIZE
---------------------------------------------------------------
function enc_wb_dat(
wradr : std_logic_vector(1 downto 0);
wrsz : std_logic_vector(1 downto 0);
din : std_logic_vector(memory_width - 1 downto 0)
)
return std_logic_vector is
variable dword :std_logic_vector(WB_PORT_SIZE-1 downto 0) := (others=>'0');
begin
if WB_ENDIANESS = big then
--if WB_ENDIANESS = little then
case wrsz is
when "00" =>
if wradr = "11" then dword( 7 downto 0) := din(7 downto 0);
elsif wradr = "10" then dword(15 downto 8) := din(7 downto 0);
elsif wradr = "01" then dword(23 downto 16) := din(7 downto 0);
elsif wradr = "00" then dword(31 downto 24) := din(7 downto 0);
else dword := (others=>'0');
end if;
when "01" =>
if wradr = "10" or wradr = "11" then dword(15 downto 0) := din(15 downto 0);
elsif wradr = "00" or wradr = "01" then dword(31 downto 16):= din(15 downto 0);
else dword:= (others=>'0');
end if;
when "10" =>
dword := din;
when others =>
dword := (others=>'0');
end case;
else
case wrsz is
when "00" =>
if wradr = "00" then dword( 7 downto 0) := din(7 downto 0);
elsif wradr = "01" then dword(15 downto 8) := din(7 downto 0);
elsif wradr = "10" then dword(23 downto 16) := din(7 downto 0);
elsif wradr = "11" then dword(31 downto 24) := din(7 downto 0);
else dword := (others=>'0');
end if;
when "01" =>
if wradr = "00" or wradr = "01" then dword(15 downto 0) := din(15 downto 0);
elsif wradr = "10" or wradr = "11" then dword(31 downto 16):= din(15 downto 0);
else dword:= (others=>'0');
end if;
when "10" =>
dword := din;
when others =>
dword := (others=>'0');
end case;
end if;
return(dword);
end;
---------------------------------------------------------------
-- Function: dec_wb_dat(select,dword)
-- Decodes a WB data word using the given select signal
--
---------------------------------------------------------------
function dec_wb_dat(
sel : std_logic_vector(WB_SEL_WIDTH-1 downto 0);
din : std_logic_vector(WB_PORT_SIZE-1 downto 0)
)
return std_logic_vector is
variable dword :std_logic_vector(WB_PORT_SIZE-1 downto 0) := (others=>'0');
begin
case WB_PORT_GRAN is
when 8 =>
case sel is
when "0001" =>
dword(7 downto 0) := din( 7 downto 0);
when "0010" =>
dword(7 downto 0) := din(15 downto 8);
when "0100" =>
dword(7 downto 0) := din(23 downto 16);
when "1000" =>
dword(7 downto 0) := din(31 downto 24);
when "1100" =>
dword(15 downto 0) := din(31 downto 16);
when "0011" =>
dword(15 downto 0) := din(15 downto 0);
when "1111" =>
dword := din;
when others =>
dword := (others => '0');
end case;
when 16 =>
--untested! do not use without (extensive) testing
if sel = "0011" then dword(15 downto 0):= din(15 downto 0) ;
elsif sel = "1100" then dword(15 downto 0):= din(31 downto 16);
else dword := (others=>'0');
end if;
when 32 =>
--untested! do not use without (extensive) testing
dword := din;
when others =>
dword := (others=>'0');
end case;
return(dword);
end;
---------------------------------------------------------------
-- Function: decsz(port_gran) equivalent to "decselwb2mem"
--
--
---------------------------------------------------------------
function decsz(
sel : std_logic_vector(WB_SEL_WIDTH-1 downto 0)
)
return std_logic_vector is
variable sz :std_logic_vector(1 downto 0) := (others=>'0');
begin
case WB_PORT_GRAN is
when 8 =>
case sel is
when "0001" =>
sz := "00";
when "0010" =>
sz := "00";
when "0100" =>
sz := "00";
when "1000" =>
sz := "00";
when "1100" =>
sz := "01";
when "0011" =>
sz := "01";
when "1111" =>
sz := "10";
when others =>
sz := "11";
end case;
when 16 => sz := "01";
--untested! do not use without (extensive) testing
when 32 => sz := "10";
--untested! do not use without (extensive) testing
when others => sz := "00";
end case;
return(sz);
end;
end; -- end package body