Files

360 lines
14 KiB
VHDL

library IEEE;
use IEEE.STD_LOGIC_1164.all;
use ieee.numeric_std.all;
use work.wishbone_pkg.all;
library UNISIM;
use UNISIM.vcomponents.all;
entity multiboot is
port (
wb_clk_i : in std_logic;
wb_rst_i : in std_logic;
wb_adr_i : in t_wishbone_address;
wb_dat_i : in t_wishbone_data;
wb_dat_o : out t_wishbone_data;
wb_sel_i : in t_wishbone_byte_select;
wb_stb_i : in std_logic;
wb_cyc_i : in std_logic;
wb_we_i : in std_logic;
wb_ack_o : out std_logic;
wb_stall_o : out std_logic;
wb_int_o : out std_logic;
wb_err_o : out std_logic;
wb_rty_o : out std_logic
);
end multiboot;
architecture Behavioral of multiboot is
COMPONENT ICAPE2_wrapper
PORT (
CLK : IN std_ulogic;
CSIB : IN std_ulogic;
I : IN std_logic_vector (31 DOWNTO 0);
RDWRB : IN std_ulogic;
O : OUT std_logic_vector (31 DOWNTO 0)
);
END COMPONENT;
attribute NOOPT : boolean;
attribute NOOPT of ICAPE2_wrapper : component is TRUE;
type FSM_STATE is (st_abort, st_abort_1, st_abort_2,
st_idle, st_ack, st_dummy, st_bus_width_sync, st_bus_width_detect, st_dummy_2, st_sync, st_noop_1,
-- states used in the read-branch of the state machine
st_wr_addr, st_wr_data, st_wr_noop_2, st_wr_noop_3,
-- states used in the read-branch of the state machine
st_rd_addr, st_rd_noop_2, st_rd_noop_3, st_rd_deselect, st_rd_read, st_rd_read_1, st_rd_terminate,
st_cmd, st_cmd_ce, st_cmd_desync, st_noop_4, st_noop_5, st_cmd_deselect
);
signal NEXT_STATE : FSM_STATE;
signal CE : std_logic;
signal I : std_logic_vector(31 downto 0);
signal ICAP_WRITE : std_logic;
signal O : std_logic_vector(31 downto 0);
signal wb_write : std_logic; -- internal write
signal wb_read : std_logic; -- internal read
type std_logic_v32array is array ( natural range <> ) of std_logic_vector(31 downto 0);
-- see Xilinx UG470 table 5-18 for opcodes:
constant OPCODE_NOP : std_logic_vector(1 downto 0) := "00";
constant OPCODE_RD : std_logic_vector(1 downto 0) := "01";
constant OPCODE_WR : std_logic_vector(1 downto 0) := "10";
-- see Xilinx UG470 table 5-17:
constant HDR_TYPE : std_logic_vector(2 downto 0) := "001";
constant WRD_CNT_WIDTH :integer := 11;
begin
ICAPE2_wrapper_inst : ICAPE2_wrapper
-- generic map (
-- ICAP_WIDTH => "X32",
-- SIM_CFG_FILE_NAME => "NONE"
-- )
port map (
CLK => wb_clk_i, -- 1-bit Clock Input
CSIB => CE, -- 1-bit Active-Low ICAP Enable
I => I, -- 32-bit iConfiguration data input bus
RDWRB => ICAP_WRITE, -- 1-bit input: Read/Write Select input
O => O -- 32-bit iConfiguration data output bus
);
-- generate other wishbone signals
wb_err_o <= '0';
wb_rty_o <= '0';
wb_stall_o <= '0';
wb_int_o <= '0';
-- generate wishbone write and read access signal
wb_write <= wb_cyc_i and wb_stb_i and wb_we_i;
wb_read <= wb_cyc_i and wb_stb_i and not wb_we_i;
p: process(wb_clk_i, wb_rst_i)
variable cnt: unsigned (31 downto 0);
variable preload: unsigned (31 downto 0);
begin
if (wb_rst_i='1') then
ICAP_WRITE <= '1';
CE <= '1';
I <= x"20000000";
wb_ack_o <= '0';
cnt := (others => '0');
NEXT_STATE <= st_abort; -- Start with an Abort Sequence after reset.
-- It has been empirically determined that without this Abort
-- the very first ICAPE2 read cycle fails
elsif (rising_edge(wb_clk_i)) then
case NEXT_STATE is
when st_idle =>
CE <= '1';
I <= x"20000000";
wb_ack_o <= '0';
cnt := (others => '0');
if wb_write = '1' and wb_adr_i(5) = '1' then
ICAP_WRITE <= '1';
NEXT_STATE <= st_ack;
elsif wb_write = '1' or wb_read = '1' then
ICAP_WRITE <= '0';
NEXT_STATE <= st_dummy;
else
ICAP_WRITE <= '1';
NEXT_STATE <= st_idle;
end if;
when st_abort =>
ICAP_WRITE <= '0';
CE <= '1';
I <= x"20000000";
wb_ack_o <= '1';
preload := unsigned(wb_dat_i);
cnt := (others => '0');
NEXT_STATE <= st_abort_1;
when st_abort_1 =>
ICAP_WRITE <= '0';
CE <= '0';
I <= x"20000000";
wb_ack_o <= '1';
preload := unsigned(wb_dat_i);
cnt := (others => '0');
NEXT_STATE <= st_abort_2;
when st_abort_2 =>
ICAP_WRITE <= '1'; -- The actual Abort: change ICAP_WRITE while CE is asserted (see also UG470 figure 2-6 and text)
CE <= '0';
I <= x"20000000";
wb_ack_o <= '1';
preload := unsigned(wb_dat_i);
cnt := (others => '0');
NEXT_STATE <= st_idle;
-- Just acknowledge the wishbone bus when the address is out of the ICAPE2 range
when st_ack =>
ICAP_WRITE <= '1';
CE <= '1';
I <= x"20000000";
wb_ack_o <= '1';
preload := unsigned(wb_dat_i);
cnt := (others => '0');
NEXT_STATE <= st_idle;
-- Bus Width and Sync word sequence to access ICAPE2 registers (see also (part of) UG470 Table 6-1)
when st_dummy =>
ICAP_WRITE <= '0';
CE <= '0';
I <= x"FFFFFFFF"; -- step 1: dummy word
wb_ack_o <= '0';
cnt := (others => '0');
NEXT_STATE <= st_bus_width_sync;
when st_bus_width_sync =>
ICAP_WRITE <= '0';
CE <= '0';
I <= x"000000BB"; -- step 2: bus width sync word
wb_ack_o <= '0';
cnt := (others => '0');
NEXT_STATE <= st_bus_width_detect;
when st_bus_width_detect =>
ICAP_WRITE <= '0';
CE <= '0';
I <= x"11220044"; -- step 3: bus width detect
wb_ack_o <= '0';
cnt := (others => '0');
NEXT_STATE <= st_dummy_2;
when st_dummy_2 =>
ICAP_WRITE <= '0';
CE <= '0';
I <= x"FFFFFFFF"; -- step 4: dummy word
wb_ack_o <= '0';
cnt := (others => '0');
NEXT_STATE <= st_sync;
when st_sync =>
ICAP_WRITE <= '0';
CE <= '0';
I <= x"AA995566"; -- step 5: sync word
wb_ack_o <= '0';
cnt := (others => '0');
NEXT_STATE <= st_noop_1;
when st_noop_1 =>
ICAP_WRITE <= '0';
CE <= '0';
I <= x"20000000"; -- step 6: Type 1 NO OP
wb_ack_o <= '0';
cnt := (others => '0');
if wb_write = '1' then
NEXT_STATE <= st_wr_addr; -- note that write can go straight on without deselecting CE
else
NEXT_STATE <= st_rd_addr;
end if;
-- Writing ICAPE2 registers (see also (part of) UG470 Table 7-1)
when st_wr_addr =>
ICAP_WRITE <= '0';
CE <= '0'; -- step 7
I (31 downto 29) <= HDR_TYPE; -- Header type (UG470 table 5-17)
I (28 downto 27) <= OPCODE_WR;
I (26 downto 18) <= (others => '0'); -- reserved (UG470 table 5-17)
I (17 downto 13) <= wb_adr_i(4 downto 0); -- register address (UG470 table 5-17)
I (12 downto 11) <= (others => '0'); -- reserved (UG470 table 5-17)
I (10 downto 0) <= std_logic_vector(to_unsigned(1, WRD_CNT_WIDTH)); -- word count = 1 (UG470 table 5-17)
wb_ack_o <= '0';
cnt := (others => '0');
NEXT_STATE <= st_wr_data;
when st_wr_data =>
ICAP_WRITE <= '0';
CE <= '0';
I <= wb_dat_i; -- step 8: data
wb_ack_o <= '1';
cnt := (others => '0');
NEXT_STATE <= st_wr_noop_2;
when st_wr_noop_2 =>
ICAP_WRITE <= '0';
CE <= '0';
I <= x"20000000"; -- step 9: Type 1 NO OP
wb_ack_o <= '0';
cnt := (others => '0');
NEXT_STATE <= st_cmd_ce;
-- Reading ICAPE2 registers (see also UG470 Table 6-1)
-- http://forums.xilinx.com/t5/7-Series-FPGAs/ICAPE2-Configuration-Register-Read-Procedure/td-p/356861
-- http://www.xilinx.com/support/answers/44942.htm
when st_rd_addr =>
ICAP_WRITE <= '0';
CE <= '0'; -- step 7
I (31 downto 29) <= HDR_TYPE; -- Header type (UG470 table 5-17)
I (28 downto 27) <= OPCODE_RD;
I (26 downto 18) <= (others => '0'); -- reserved (UG470 table 5-17)
I (17 downto 13) <= wb_adr_i(4 downto 0); -- register address (UG470 table 5-17)
I (12 downto 11) <= (others => '0'); -- reserved (UG470 table 5-17)
I (10 downto 0) <= std_logic_vector(to_unsigned(1, WRD_CNT_WIDTH)); -- word count = 1 (UG470 table 5-17)
wb_ack_o <= '0';
cnt := (others => '0');
NEXT_STATE <= st_rd_noop_2;
when st_rd_noop_2 =>
ICAP_WRITE <= '0';
CE <= '0';
I <= x"20000000"; -- step 8: Type 1 NO OP
cnt := (others => '0');
wb_ack_o <= '0';
NEXT_STATE <= st_rd_noop_3;
when st_rd_noop_3 =>
ICAP_WRITE <= '0';
CE <= '0';
I <= x"20000000"; -- step 9: Type 1 NO OP
wb_ack_o <= '0';
cnt := (others => '0');
NEXT_STATE <= st_rd_deselect;
when st_rd_deselect => -- UG470 below Table 6-1: "The user must change the SelectMAP interface from write
-- to read control between steps 8 and 9, and back to write control after step 9.
-- (UG191 figure 7-2 takes back CE http://www.xilinx.com/support/documentation/user_guides/ug191.pdf)
ICAP_WRITE <= '0';
CE <= '1';
I <= x"20000000"; -- de assert CE without changing ICAP_WRITE (avoid Abort)
cnt := (others => '0');
wb_ack_o <= '0';
NEXT_STATE <= st_rd_read;
when st_rd_read =>
ICAP_WRITE <= '1'; -- change to "Read" while CE de-asserted
CE <= '1';
I <= x"20000000";
cnt := (others => '0');
wb_ack_o <= '0';
NEXT_STATE <= st_rd_read_1;
when st_rd_read_1 =>
ICAP_WRITE <= '1'; -- assert CE again and wait for valid data to read
CE <= '0';
I <= x"20000000"; -- step 10: Type 1 NO OP
cnt := cnt + 1;
if cnt /= 4 then -- 3 is not enough... 4 is! Empirically tested on real hardware
NEXT_STATE <= st_rd_read_1;
wb_ack_o <= '0';
else
NEXT_STATE <= st_rd_terminate;
wb_ack_o <= '1'; -- acknowledge the presented data, the actual data transfer takes place in this cycle
end if;
when st_rd_terminate =>
ICAP_WRITE <= '1';
CE <= '1'; -- de assert CE without changing ICAP_WRITE (avoid Abort)
I <= x"20000000";
wb_ack_o <= '0';
cnt := (others => '0');
NEXT_STATE <= st_cmd;
when st_cmd => -- change to "Write" while CE de-asserted
ICAP_WRITE <= '0';
CE <= '1';
I <= x"20000000";
wb_ack_o <= '0';
cnt := (others => '0');
NEXT_STATE <= st_cmd_ce;
when st_cmd_ce =>
ICAP_WRITE <= '0';
CE <= '0';
I <= x"30008001"; -- step 11: Type 1 write 1 word to CMD
wb_ack_o <= '0';
cnt := (others => '0');
NEXT_STATE <= st_cmd_desync;
when st_cmd_desync =>
ICAP_WRITE <= '0';
CE <= '0';
I <= x"0000000D"; -- step 12: DESYNC
wb_ack_o <= '0';
cnt := (others => '0');
NEXT_STATE <= st_noop_4;
when st_noop_4 =>
ICAP_WRITE <= '0';
CE <= '0';
I <= x"20000000"; -- step 13: Type 1 NO OP
wb_ack_o <= '0';
cnt := (others => '0');
NEXT_STATE <= st_noop_5;
when st_noop_5 =>
ICAP_WRITE <= '0';
CE <= '0';
I <= x"20000000"; -- step 14: Type 1 NO OP
wb_ack_o <= '0';
cnt := (others => '0');
NEXT_STATE <= st_cmd_deselect;
when st_cmd_deselect =>
ICAP_WRITE <= '0';
CE <= '1'; -- de assert CE without changing ICAP_WRITE (avoid Abort)
I <= x"20000000";
wb_ack_o <= '0';
cnt := (others => '0');
NEXT_STATE <= st_idle;
when others =>
ICAP_WRITE <= '1';
CE <= '1';
I <= x"20000000";
wb_ack_o <= '0';
NEXT_STATE <= st_idle;
end case;
end if;
end process;
wb_dat_o <= O;
end Behavioral;