From 4cf2921b0bd433f870878dd56b3f2bac3a3860c6 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 11 Oct 2021 17:46:44 +1100 Subject: [PATCH] soc: Re-do peripheral address decode to improve timing This generates a series of io_cycle_* signals which are clean latches and which become the 'cyc' signals of the wishbone buses going to various peripherals (syscon, uarts, XICS, GPIO, etc.). Effectively this is done by moving the address decoding into the slave_io_latch process. The slave_io_type, which drives the multiplexer which selects which wishbone to look for a response on, is reduced to just 8 values in the expectation that an 8-way multiplexer will use less logic than one with more than 8 inputs. With this timing is considerably better on the A7-100T. Signed-off-by: Paul Mackerras --- soc.vhdl | 239 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 129 insertions(+), 110 deletions(-) diff --git a/soc.vhdl b/soc.vhdl index b23336c..ee1ea3e 100644 --- a/soc.vhdl +++ b/soc.vhdl @@ -239,12 +239,20 @@ architecture behaviour of soc is SLAVE_IO_ICP, SLAVE_IO_ICS, SLAVE_IO_UART1, - SLAVE_IO_SPI_FLASH_REG, - SLAVE_IO_SPI_FLASH_MAP, + SLAVE_IO_SPI_FLASH, SLAVE_IO_GPIO, - SLAVE_IO_EXTERNAL, - SLAVE_IO_NONE); - signal slave_io_dbg : slave_io_type; + SLAVE_IO_EXTERNAL); + signal current_io_decode : slave_io_type; + + signal io_cycle_none : std_ulogic; + signal io_cycle_syscon : std_ulogic; + signal io_cycle_uart : std_ulogic; + signal io_cycle_uart1 : std_ulogic; + signal io_cycle_icp : std_ulogic; + signal io_cycle_ics : std_ulogic; + signal io_cycle_spi_flash : std_ulogic; + signal io_cycle_gpio : std_ulogic; + signal io_cycle_external : std_ulogic; function wishbone_widen_data(wb : wb_io_master_out) return wishbone_master_out is variable wwb : wishbone_master_out; @@ -465,14 +473,20 @@ begin -- Misc variable has_top : boolean; variable has_bot : boolean; + variable do_cyc : std_ulogic; + variable end_cyc : std_ulogic; + variable slave_io : slave_io_type; + variable match : std_ulogic_vector(31 downto 12); begin if rising_edge(system_clk) then + do_cyc := '0'; + end_cyc := '0'; 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'; + end_cyc := '1'; has_top := false; has_bot := false; else @@ -488,7 +502,7 @@ begin wb_io_out.stall <= '1'; -- Start cycle downstream - wb_sio_out.cyc <= '1'; + do_cyc := '1'; wb_sio_out.stb <= '1'; -- Copy write enable to IO out, copy address as well @@ -551,8 +565,8 @@ begin -- Wait for new ack state := WAIT_ACK_TOP; else - -- We are done, ack up, clear cyc downstram - wb_sio_out.cyc <= '0'; + -- We are done, ack up, clear cyc downstream + end_cyc := '1'; -- And ack & unstall upstream wb_io_out.ack <= '1'; @@ -576,7 +590,7 @@ begin end if; -- We are done, ack up, clear cyc downstram - wb_sio_out.cyc <= '0'; + end_cyc := '1'; -- And ack & unstall upstream wb_io_out.ack <= '1'; @@ -587,144 +601,149 @@ begin end if; end case; end if; + + -- Create individual registered cycle signals for the wishbones + -- going to the various peripherals + if do_cyc = '1' or end_cyc = '1' then + io_cycle_none <= '0'; + io_cycle_syscon <= '0'; + io_cycle_uart <= '0'; + io_cycle_uart1 <= '0'; + io_cycle_icp <= '0'; + io_cycle_ics <= '0'; + io_cycle_spi_flash <= '0'; + io_cycle_gpio <= '0'; + io_cycle_external <= '0'; + wb_sio_out.cyc <= '0'; + wb_ext_is_dram_init <= '0'; + wb_spiflash_is_map <= '0'; + wb_spiflash_is_reg <= '0'; + wb_ext_is_dram_csr <= '0'; + wb_ext_is_eth <= '0'; + wb_ext_is_sdcard <= '0'; + end if; + if do_cyc = '1' then + -- Decode I/O address + -- This is real address bits 29 downto 12 + match := "11" & wb_io_in.adr(26 downto 9); + slave_io := SLAVE_IO_SYSCON; + if std_match(match, x"FF---") and HAS_DRAM then + slave_io := SLAVE_IO_EXTERNAL; + io_cycle_external <= '1'; + wb_ext_is_dram_init <= '1'; + elsif std_match(match, x"F----") then + slave_io := SLAVE_IO_SPI_FLASH; + io_cycle_spi_flash <= '1'; + wb_spiflash_is_map <= '1'; + elsif std_match(match, x"C8---") then + -- Ext IO "chip selects" + if std_match(match, x"--00-") and HAS_DRAM then + slave_io := SLAVE_IO_EXTERNAL; + io_cycle_external <= '1'; + wb_ext_is_dram_csr <= '1'; + elsif (std_match(match, x"--02-") or std_match(match, x"--03-")) and + HAS_LITEETH then + slave_io := SLAVE_IO_EXTERNAL; + io_cycle_external <= '1'; + wb_ext_is_eth <= '1'; + elsif std_match(match, x"--04-") and HAS_SD_CARD then + slave_io := SLAVE_IO_EXTERNAL; + io_cycle_external <= '1'; + wb_ext_is_sdcard <= '1'; + else + io_cycle_none <= '1'; + end if; + elsif std_match(match, x"C0000") then + slave_io := SLAVE_IO_SYSCON; + io_cycle_syscon <= '1'; + elsif std_match(match, x"C0002") then + slave_io := SLAVE_IO_UART; + io_cycle_uart <= '1'; + elsif std_match(match, x"C0003") then + slave_io := SLAVE_IO_UART1; + io_cycle_uart1 <= '1'; + elsif std_match(match, x"C0004") then + slave_io := SLAVE_IO_ICP; + io_cycle_icp <= '1'; + elsif std_match(match, x"C0005") then + slave_io := SLAVE_IO_ICS; + io_cycle_ics <= '1'; + elsif std_match(match, x"C0006") then + slave_io := SLAVE_IO_SPI_FLASH; + io_cycle_spi_flash <= '1'; + wb_spiflash_is_reg <= '1'; + elsif std_match(match, x"C0007") then + slave_io := SLAVE_IO_GPIO; + io_cycle_gpio <= '1'; + else + io_cycle_none <= '1'; + end if; + current_io_decode <= slave_io; + wb_sio_out.cyc <= '1'; + end if; end if; end process; - -- IO wishbone slave intercon. + -- IO wishbone slave interconnect. -- - 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; + slave_io_intercon: process(all) begin - - -- Simple address decoder. - slave_io := SLAVE_IO_NONE; - match := "11" & wb_sio_out.adr(27 downto 10); - 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; - elsif std_match(match, x"C0007") then - slave_io := SLAVE_IO_GPIO; - end if; - slave_io_dbg <= slave_io; wb_uart0_in <= wb_sio_out; - wb_uart0_in.cyc <= '0'; + wb_uart0_in.cyc <= io_cycle_uart; wb_uart1_in <= wb_sio_out; - wb_uart1_in.cyc <= '0'; + wb_uart1_in.cyc <= io_cycle_uart1; + wb_spiflash_in <= wb_sio_out; - wb_spiflash_in.cyc <= '0'; - wb_spiflash_is_reg <= '0'; - wb_spiflash_is_map <= '0'; + wb_spiflash_in.cyc <= io_cycle_spi_flash; + -- Clear top bits so they don't make their way to the + -- flash chip. + wb_spiflash_in.adr(27 downto 26) <= "00"; + wb_gpio_in <= wb_sio_out; - wb_gpio_in.cyc <= '0'; + wb_gpio_in.cyc <= io_cycle_gpio; -- 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(5 downto 0) <= wb_sio_out.adr(5 downto 0); - wb_xics_icp_in.cyc <= '0'; + wb_xics_icp_in.cyc <= io_cycle_icp; wb_xics_ics_in <= wb_sio_out; wb_xics_ics_in.adr <= (others => '0'); wb_xics_ics_in.adr(9 downto 0) <= wb_sio_out.adr(9 downto 0); - wb_xics_ics_in.cyc <= '0'; + wb_xics_ics_in.cyc <= io_cycle_ics; wb_ext_io_in <= wb_sio_out; - wb_ext_io_in.cyc <= '0'; + wb_ext_io_in.cyc <= io_cycle_external; 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'; - wb_ext_is_sdcard <= '0'; + wb_syscon_in.cyc <= io_cycle_syscon; - -- 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 + case current_io_decode 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 (21 downto 14 in the wishbone addr). - -- - ext_valid := false; - if wb_sio_out.adr(27) = '1' and HAS_DRAM then -- DRAM init is special - wb_ext_is_dram_init <= '1'; - ext_valid := true; - elsif wb_sio_out.adr(21 downto 14) = x"00" and HAS_DRAM then - wb_ext_is_dram_csr <= '1'; - ext_valid := true; - elsif wb_sio_out.adr(21 downto 14) = x"02" and HAS_LITEETH then - wb_ext_is_eth <= '1'; - ext_valid := true; - elsif wb_sio_out.adr(21 downto 14) = x"03" and HAS_LITEETH then - wb_ext_is_eth <= '1'; - ext_valid := true; - elsif wb_sio_out.adr(21 downto 14) = x"04" and HAS_SD_CARD then - wb_ext_is_sdcard <= '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; - + wb_sio_in <= wb_ext_io_out; 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(27 downto 26) <= "00"; - wb_spiflash_in.cyc <= wb_sio_out.cyc; + when SLAVE_IO_SPI_FLASH => 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'; when SLAVE_IO_GPIO => - wb_gpio_in.cyc <= wb_sio_out.cyc; wb_sio_in <= wb_gpio_out; - when others => end case; + -- Default response, ack & return all 1's + if io_cycle_none = '1' then + wb_sio_in.dat <= (others => '1'); + wb_sio_in.ack <= wb_sio_out.stb and wb_sio_out.cyc; + wb_sio_in.stall <= '0'; + end if; + end process; -- Syscon slave