+ when SLAVE_TOP_DRAM =>
+ if HAS_DRAM then
+ wb_dram_in.cyc <= wb_master_out.cyc;
+ wb_master_in <= wb_dram_out;
+ else
+ wb_master_in.ack <= wb_master_out.cyc and wb_master_out.stb;
+ wb_master_in.dat <= (others => '1');
+ wb_master_in.stall <= '0';
+ end if;
+ when SLAVE_TOP_IO =>
+ wb_io_in.cyc <= wb_master_out.cyc;
+ wb_master_in <= wb_io_out;
+ end case;
+
+ end process slave_top_intercon;
+
+ -- IO wishbone slave 64->32 bits converter
+ --
+ -- For timing reasons, this adds a one cycle latch on the way both
+ -- in and out. This relaxes timing and routing pressure on the "main"
+ -- memory bus by moving all simple IOs to a slower 32-bit bus.
+ --
+ -- This implementation is rather dumb at the moment, no stash buffer,
+ -- so we stall whenever that latch is busy. This can be improved.
+ --
+ slave_io_latch: process(system_clk)
+ -- State
+ type state_t is (IDLE, WAIT_ACK_BOT, WAIT_ACK_TOP);
+ variable state : state_t;
+
+ -- Misc
+ variable has_top : boolean;
+ variable has_bot : boolean;
+ begin
+ if rising_edge(system_clk) then
+ if (rst) then
+ state := IDLE;
+ wb_io_out.ack <= '0';
+ wb_io_out.stall <= '0';
+ wb_sio_out.cyc <= '0';
+ wb_sio_out.stb <= '0';
+ has_top := false;
+ has_bot := false;
+ else
+ case state is
+ when IDLE =>
+ -- Clear ACK in case it was set
+ wb_io_out.ack <= '0';
+
+ -- Do we have a cycle ?
+ if wb_io_in.cyc = '1' and wb_io_in.stb = '1' then
+ -- Stall master until we are done, we are't (yet) pipelining
+ -- this, it's all slow IOs.
+ wb_io_out.stall <= '1';
+
+ -- Start cycle downstream
+ wb_sio_out.cyc <= '1';
+ wb_sio_out.stb <= '1';
+
+ -- Copy write enable to IO out, copy address as well
+ wb_sio_out.we <= wb_io_in.we;
+ wb_sio_out.adr <= wb_io_in.adr(wb_sio_out.adr'left downto 3) & "000";
+
+ -- Do we have a top word and/or a bottom word ?
+ has_top := wb_io_in.sel(7 downto 4) /= "0000";
+ has_bot := wb_io_in.sel(3 downto 0) /= "0000";
+
+ -- If we have a bottom word, handle it first, otherwise
+ -- send the top word down. XXX Split the actual mux out
+ -- and only generate a control signal.
+ if has_bot then
+ if wb_io_in.we = '1' then
+ wb_sio_out.dat <= wb_io_in.dat(31 downto 0);
+ end if;
+ wb_sio_out.sel <= wb_io_in.sel(3 downto 0);
+
+ -- Wait for ack
+ state := WAIT_ACK_BOT;
+ else
+ if wb_io_in.we = '1' then
+ wb_sio_out.dat <= wb_io_in.dat(63 downto 32);
+ end if;
+ wb_sio_out.sel <= wb_io_in.sel(7 downto 4);
+
+ -- Bump address
+ wb_sio_out.adr(2) <= '1';
+
+ -- Wait for ack
+ state := WAIT_ACK_TOP;
+ end if;
+ end if;
+ when WAIT_ACK_BOT =>
+ -- If we aren't stalled by the device, clear stb
+ if wb_sio_in.stall = '0' then
+ wb_sio_out.stb <= '0';
+ end if;
+
+ -- Handle ack
+ if wb_sio_in.ack = '1' then
+ -- If it's a read, latch the data
+ if wb_sio_out.we = '0' then
+ wb_io_out.dat(31 downto 0) <= wb_sio_in.dat;
+ end if;
+
+ -- Do we have a "top" part as well ?
+ if has_top then
+ -- Latch data & sel
+ if wb_io_in.we = '1' then
+ wb_sio_out.dat <= wb_io_in.dat(63 downto 32);
+ end if;
+ wb_sio_out.sel <= wb_io_in.sel(7 downto 4);
+
+ -- Bump address and set STB
+ wb_sio_out.adr(2) <= '1';
+ wb_sio_out.stb <= '1';
+
+ -- Wait for new ack
+ state := WAIT_ACK_TOP;
+ else
+ -- We are done, ack up, clear cyc downstram
+ wb_sio_out.cyc <= '0';
+
+ -- And ack & unstall upstream
+ wb_io_out.ack <= '1';
+ wb_io_out.stall <= '0';
+
+ -- Wait for next one
+ state := IDLE;
+ end if;
+ end if;
+ when WAIT_ACK_TOP =>
+ -- If we aren't stalled by the device, clear stb
+ if wb_sio_in.stall = '0' then
+ wb_sio_out.stb <= '0';
+ end if;
+
+ -- Handle ack
+ if wb_sio_in.ack = '1' then
+ -- If it's a read, latch the data
+ if wb_sio_out.we = '0' then
+ wb_io_out.dat(63 downto 32) <= wb_sio_in.dat;
+ end if;
+
+ -- We are done, ack up, clear cyc downstram
+ wb_sio_out.cyc <= '0';
+
+ -- And ack & unstall upstream
+ wb_io_out.ack <= '1';
+ wb_io_out.stall <= '0';
+
+ -- Wait for next one
+ state := IDLE;
+ end if;
+ end case;
+ end if;
+ end if;
+ end process;
+
+ -- IO wishbone slave intercon.
+ --
+ slave_io_intercon: process(wb_sio_out, wb_syscon_out, wb_uart0_out, wb_uart1_out,
+ wb_ext_io_out, wb_xics_icp_out, wb_xics_ics_out,
+ wb_spiflash_out)
+ variable slave_io : slave_io_type;
+
+ variable match : std_ulogic_vector(31 downto 12);
+ variable ext_valid : boolean;
+ begin
+
+ -- Simple address decoder.
+ slave_io := SLAVE_IO_NONE;
+ match := "11" & wb_sio_out.adr(29 downto 12);
+ if std_match(match, x"FF---") and HAS_DRAM then
+ slave_io := SLAVE_IO_EXTERNAL;
+ elsif std_match(match, x"F----") then
+ slave_io := SLAVE_IO_SPI_FLASH_MAP;
+ elsif std_match(match, x"C0000") then
+ slave_io := SLAVE_IO_SYSCON;
+ elsif std_match(match, x"C0002") then
+ slave_io := SLAVE_IO_UART;
+ elsif std_match(match, x"C0003") then
+ slave_io := SLAVE_IO_UART1;
+ elsif std_match(match, x"C8---") then
+ slave_io := SLAVE_IO_EXTERNAL;
+ elsif std_match(match, x"C0004") then
+ slave_io := SLAVE_IO_ICP;
+ elsif std_match(match, x"C0005") then
+ slave_io := SLAVE_IO_ICS;
+ elsif std_match(match, x"C0006") then
+ slave_io := SLAVE_IO_SPI_FLASH_REG;
+ end if;
+ slave_io_dbg <= slave_io;
+ wb_uart0_in <= wb_sio_out;
+ wb_uart0_in.cyc <= '0';
+ wb_uart1_in <= wb_sio_out;
+ wb_uart1_in.cyc <= '0';
+ wb_spiflash_in <= wb_sio_out;
+ wb_spiflash_in.cyc <= '0';
+ wb_spiflash_is_reg <= '0';
+ wb_spiflash_is_map <= '0';
+
+ -- Only give xics 8 bits of wb addr (for now...)
+ wb_xics_icp_in <= wb_sio_out;
+ wb_xics_icp_in.adr <= (others => '0');
+ wb_xics_icp_in.adr(7 downto 0) <= wb_sio_out.adr(7 downto 0);
+ wb_xics_icp_in.cyc <= '0';
+ wb_xics_ics_in <= wb_sio_out;
+ wb_xics_ics_in.adr <= (others => '0');
+ wb_xics_ics_in.adr(11 downto 0) <= wb_sio_out.adr(11 downto 0);
+ wb_xics_ics_in.cyc <= '0';
+
+ wb_ext_io_in <= wb_sio_out;
+ wb_ext_io_in.cyc <= '0';
+
+ wb_syscon_in <= wb_sio_out;
+ wb_syscon_in.cyc <= '0';
+
+ wb_ext_is_dram_csr <= '0';
+ wb_ext_is_dram_init <= '0';
+ wb_ext_is_eth <= '0';
+
+ -- Default response, ack & return all 1's
+ wb_sio_in.dat <= (others => '1');
+ wb_sio_in.ack <= wb_sio_out.stb and wb_sio_out.cyc;
+ wb_sio_in.stall <= '0';
+
+ case slave_io is
+ when SLAVE_IO_EXTERNAL =>
+ -- Ext IO "chip selects"
+ --
+ -- DRAM init is special at 0xFF* so we just test the top
+ -- bit. Everything else is at 0xC8* so we test only bits
+ -- 23 downto 16.
+ --
+ ext_valid := false;
+ if wb_sio_out.adr(29) = '1' and HAS_DRAM then -- DRAM init is special
+ wb_ext_is_dram_init <= '1';
+ ext_valid := true;
+ elsif wb_sio_out.adr(23 downto 16) = x"00" and HAS_DRAM then
+ wb_ext_is_dram_csr <= '1';
+ ext_valid := true;
+ elsif wb_sio_out.adr(23 downto 16) = x"02" and HAS_LITEETH then
+ wb_ext_is_eth <= '1';
+ ext_valid := true;
+ elsif wb_sio_out.adr(23 downto 16) = x"03" and HAS_LITEETH then
+ wb_ext_is_eth <= '1';
+ ext_valid := true;
+ end if;
+ if ext_valid then
+ wb_ext_io_in.cyc <= wb_sio_out.cyc;
+ wb_sio_in <= wb_ext_io_out;
+ end if;
+
+ when SLAVE_IO_SYSCON =>
+ wb_syscon_in.cyc <= wb_sio_out.cyc;
+ wb_sio_in <= wb_syscon_out;
+ when SLAVE_IO_UART =>
+ wb_uart0_in.cyc <= wb_sio_out.cyc;
+ wb_sio_in <= wb_uart0_out;
+ when SLAVE_IO_ICP =>
+ wb_xics_icp_in.cyc <= wb_sio_out.cyc;
+ wb_sio_in <= wb_xics_icp_out;
+ when SLAVE_IO_ICS =>
+ wb_xics_ics_in.cyc <= wb_sio_out.cyc;
+ wb_sio_in <= wb_xics_ics_out;
+ when SLAVE_IO_UART1 =>
+ wb_uart1_in.cyc <= wb_sio_out.cyc;
+ wb_sio_in <= wb_uart1_out;
+ when SLAVE_IO_SPI_FLASH_MAP =>
+ -- Clear top bits so they don't make their way to the
+ -- fash chip.
+ wb_spiflash_in.adr(29 downto 28) <= "00";
+ wb_spiflash_in.cyc <= wb_sio_out.cyc;
+ wb_sio_in <= wb_spiflash_out;
+ wb_spiflash_is_map <= '1';
+ when SLAVE_IO_SPI_FLASH_REG =>
+ wb_spiflash_in.cyc <= wb_sio_out.cyc;
+ wb_sio_in <= wb_spiflash_out;
+ wb_spiflash_is_reg <= '1';