-- 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