X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=soc.vhdl;h=0a700260ad7f049b9468a0a6dab8bd093df514d7;hb=081684273e11fee3d3ec14bd97e8d858e1d29402;hp=6ed6bf745c4d22fdb04bbdd039305c7250bc1c5e;hpb=8e0389b9736c60572e13ef5eeb50d3a775c3ffc6;p=microwatt.git diff --git a/soc.vhdl b/soc.vhdl index 6ed6bf7..0a70026 100644 --- a/soc.vhdl +++ b/soc.vhdl @@ -10,52 +10,164 @@ use work.common.all; use work.wishbone_types.all; --- 0x00000000: Main memory (1 MB) --- 0xc0002000: UART0 (for host communication) +-- Memory map. *** Keep include/microwatt_soc.h updated on changes *** +-- +-- Main bus: +-- 0x00000000: Block RAM (MEMORY_SIZE) or DRAM depending on syscon +-- 0x40000000: DRAM (when present) +-- 0x80000000: Block RAM (aliased & repeated) + +-- IO Bus: +-- 0xc0000000: SYSCON +-- 0xc0002000: UART0 +-- 0xc0003000: UART1 (if any) +-- 0xc0004000: XICS ICP +-- 0xc0005000: XICS ICS +-- 0xc0006000: SPI Flash controller +-- 0xc8nnnnnn: External IO bus +-- 0xf0000000: Flash "ROM" mapping +-- 0xff000000: DRAM init code (if any) or flash ROM (**) + +-- External IO bus: +-- 0xc8000000: LiteDRAM control (CSRs) +-- 0xc8020000: LiteEth CSRs (*) +-- 0xc8030000: LiteEth MMIO (*) + +-- (*) LiteEth must be a single aligned 32KB block as the CSRs and MMIOs +-- are actually decoded as a single wishbone which LiteEth will +-- internally split based on bit 16. + +-- (**) DRAM init code is currently special and goes to the external +-- IO bus, this will be fixed when it's moved out of litedram and +-- into the main SoC once we have a common "firmware". + +-- Interrupt numbers: +-- +-- 0 : UART0 +-- 1 : Ethernet + entity soc is generic ( - MEMORY_SIZE : positive; - RAM_INIT_FILE : string; - RESET_LOW : boolean; - SIM : boolean; - DISABLE_FLATTEN_CORE : boolean := false + MEMORY_SIZE : natural; + RAM_INIT_FILE : string; + CLK_FREQ : positive; + SIM : boolean; + DISABLE_FLATTEN_CORE : boolean := false; + HAS_DRAM : boolean := false; + DRAM_SIZE : integer := 0; + DRAM_INIT_SIZE : integer := 0; + HAS_SPI_FLASH : boolean := false; + SPI_FLASH_DLINES : positive := 1; + SPI_FLASH_OFFSET : integer := 0; + SPI_FLASH_DEF_CKDV : natural := 2; + SPI_FLASH_DEF_QUAD : boolean := false; + LOG_LENGTH : natural := 512; + HAS_LITEETH : boolean := false; + UART0_IS_16550 : boolean := true; + HAS_UART1 : boolean := false ); port( rst : in std_ulogic; system_clk : in std_ulogic; + -- "Large" (64-bit) DRAM wishbone + wb_dram_in : out wishbone_master_out; + wb_dram_out : in wishbone_slave_out := wishbone_slave_out_init; + + -- "Small" (32-bit) external IO wishbone + wb_ext_io_in : out wb_io_master_out; + wb_ext_io_out : in wb_io_slave_out := wb_io_slave_out_init; + wb_ext_is_dram_csr : out std_ulogic; + wb_ext_is_dram_init : out std_ulogic; + wb_ext_is_eth : out std_ulogic; + + -- External interrupts + ext_irq_eth : in std_ulogic := '0'; + -- UART0 signals: uart0_txd : out std_ulogic; - uart0_rxd : in std_ulogic; + uart0_rxd : in std_ulogic := '0'; - -- Misc (to use for things like LEDs) - core_terminated : out std_ulogic + -- UART1 signals: + uart1_txd : out std_ulogic; + uart1_rxd : in std_ulogic := '0'; + + -- SPI Flash signals + spi_flash_sck : out std_ulogic; + spi_flash_cs_n : out std_ulogic; + spi_flash_sdat_o : out std_ulogic_vector(SPI_FLASH_DLINES-1 downto 0); + spi_flash_sdat_oe : out std_ulogic_vector(SPI_FLASH_DLINES-1 downto 0); + spi_flash_sdat_i : in std_ulogic_vector(SPI_FLASH_DLINES-1 downto 0) := (others => '1'); + + -- DRAM controller signals + alt_reset : in std_ulogic := '0' ); end entity soc; architecture behaviour of soc is -- Wishbone master signals: - signal wishbone_dcore_in : wishbone_slave_out; + signal wishbone_dcore_in : wishbone_slave_out; signal wishbone_dcore_out : wishbone_master_out; - signal wishbone_icore_in : wishbone_slave_out; + signal wishbone_icore_in : wishbone_slave_out; signal wishbone_icore_out : wishbone_master_out; signal wishbone_debug_in : wishbone_slave_out; signal wishbone_debug_out : wishbone_master_out; + -- Arbiter array (ghdl doesnt' support assigning the array + -- elements in the entity instantiation) + constant NUM_WB_MASTERS : positive := 3; + signal wb_masters_out : wishbone_master_out_vector(0 to NUM_WB_MASTERS-1); + signal wb_masters_in : wishbone_slave_out_vector(0 to NUM_WB_MASTERS-1); + -- Wishbone master (output of arbiter): - signal wb_master_in : wishbone_slave_out; - signal wb_master_out : wishbone_master_out; + signal wb_master_in : wishbone_slave_out; + signal wb_master_out : wishbone_master_out; + + -- Main "IO" bus, from main slave decoder to the latch + signal wb_io_in : wishbone_master_out; + signal wb_io_out : wishbone_slave_out; + + -- Secondary (smaller) IO bus after the IO bus latch + signal wb_sio_out : wb_io_master_out; + signal wb_sio_in : wb_io_slave_out; + + -- Syscon signals + signal dram_at_0 : std_ulogic; + signal do_core_reset : std_ulogic; + signal wb_syscon_in : wb_io_master_out; + signal wb_syscon_out : wb_io_slave_out; -- UART0 signals: - signal wb_uart0_in : wishbone_master_out; - signal wb_uart0_out : wishbone_slave_out; - signal uart_dat8 : std_ulogic_vector(7 downto 0); + signal wb_uart0_in : wb_io_master_out; + signal wb_uart0_out : wb_io_slave_out; + signal uart0_dat8 : std_ulogic_vector(7 downto 0); + signal uart0_irq : std_ulogic; + + -- UART1 signals: + signal wb_uart1_in : wb_io_master_out; + signal wb_uart1_out : wb_io_slave_out; + signal uart1_dat8 : std_ulogic_vector(7 downto 0); + signal uart1_irq : std_ulogic; + + -- SPI Flash controller signals: + signal wb_spiflash_in : wb_io_master_out; + signal wb_spiflash_out : wb_io_slave_out; + signal wb_spiflash_is_reg : std_ulogic; + signal wb_spiflash_is_map : std_ulogic; + + -- XICS signals: + signal wb_xics_icp_in : wb_io_master_out; + signal wb_xics_icp_out : wb_io_slave_out; + signal wb_xics_ics_in : wb_io_master_out; + signal wb_xics_ics_out : wb_io_slave_out; + signal int_level_in : std_ulogic_vector(15 downto 0); + signal ics_to_icp : ics_to_icp_t; + signal core_ext_irq : std_ulogic; -- Main memory signals: signal wb_bram_in : wishbone_master_out; signal wb_bram_out : wishbone_slave_out; - constant mem_adr_bits : positive := positive(ceil(log2(real(MEMORY_SIZE)))); -- DMI debug bus signals signal dmi_addr : std_ulogic_vector(7 downto 0); @@ -72,17 +184,83 @@ architecture behaviour of soc is signal dmi_core_dout : std_ulogic_vector(63 downto 0); signal dmi_core_req : std_ulogic; signal dmi_core_ack : std_ulogic; + + -- Delayed/latched resets and alt_reset + signal rst_core : std_ulogic := '1'; + signal rst_uart : std_ulogic := '1'; + signal rst_xics : std_ulogic := '1'; + signal rst_spi : std_ulogic := '1'; + signal rst_bram : std_ulogic := '1'; + signal rst_dtm : std_ulogic := '1'; + signal rst_wbar : std_ulogic := '1'; + signal rst_wbdb : std_ulogic := '1'; + signal alt_reset_d : std_ulogic; + + -- IO branch split: + type slave_io_type is (SLAVE_IO_SYSCON, + SLAVE_IO_UART, + SLAVE_IO_ICP, + SLAVE_IO_ICS, + SLAVE_IO_UART1, + SLAVE_IO_SPI_FLASH_REG, + SLAVE_IO_SPI_FLASH_MAP, + SLAVE_IO_EXTERNAL, + SLAVE_IO_NONE); + signal slave_io_dbg : slave_io_type; + + -- This is the component exported by the 16550 compatible + -- UART from FuseSoC. + -- + component uart_top port ( + wb_clk_i : in std_ulogic; + wb_rst_i : in std_ulogic; + wb_adr_i : in std_ulogic_vector(2 downto 0); + wb_dat_i : in std_ulogic_vector(7 downto 0); + wb_dat_o : out std_ulogic_vector(7 downto 0); + wb_we_i : in std_ulogic; + wb_stb_i : in std_ulogic; + wb_cyc_i : in std_ulogic; + wb_ack_o : out std_ulogic; + int_o : out std_ulogic; + stx_pad_o : out std_ulogic; + srx_pad_i : in std_ulogic; + rts_pad_o : out std_ulogic; + cts_pad_i : in std_ulogic; + dtr_pad_o : out std_ulogic; + dsr_pad_i : in std_ulogic; + ri_pad_i : in std_ulogic; + dcd_pad_i : in std_ulogic + ); + end component; begin + resets: process(system_clk) + begin + if rising_edge(system_clk) then + rst_core <= rst or do_core_reset; + rst_uart <= rst; + rst_spi <= rst; + rst_xics <= rst; + rst_bram <= rst; + rst_dtm <= rst; + rst_wbar <= rst; + rst_wbdb <= rst; + alt_reset_d <= alt_reset; + end if; + end process; + -- Processor core processor: entity work.core generic map( SIM => SIM, - DISABLE_FLATTEN => DISABLE_FLATTEN_CORE + DISABLE_FLATTEN => DISABLE_FLATTEN_CORE, + ALT_RESET_ADDRESS => (23 downto 0 => '0', others => '1'), + LOG_LENGTH => LOG_LENGTH ) port map( clk => system_clk, - rst => rst, + rst => rst_core, + alt_reset => alt_reset_d, wishbone_insn_in => wishbone_icore_in, wishbone_insn_out => wishbone_icore_out, wishbone_data_in => wishbone_dcore_in, @@ -92,96 +270,572 @@ begin dmi_din => dmi_dout, dmi_wr => dmi_wr, dmi_ack => dmi_core_ack, - dmi_req => dmi_core_req + dmi_req => dmi_core_req, + ext_irq => core_ext_irq ); -- Wishbone bus master arbiter & mux + wb_masters_out <= (0 => wishbone_dcore_out, + 1 => wishbone_icore_out, + 2 => wishbone_debug_out); + wishbone_dcore_in <= wb_masters_in(0); + wishbone_icore_in <= wb_masters_in(1); + wishbone_debug_in <= wb_masters_in(2); wishbone_arbiter_0: entity work.wishbone_arbiter + generic map( + NUM_MASTERS => NUM_WB_MASTERS + ) port map( - clk => system_clk, rst => rst, - wb1_in => wishbone_dcore_out, wb1_out => wishbone_dcore_in, - wb2_in => wishbone_icore_out, wb2_out => wishbone_icore_in, - wb3_in => wishbone_debug_out, wb3_out => wishbone_debug_in, - wb_out => wb_master_out, wb_in => wb_master_in + clk => system_clk, + rst => rst_wbar, + wb_masters_in => wb_masters_out, + wb_masters_out => wb_masters_in, + wb_slave_out => wb_master_out, + wb_slave_in => wb_master_in ); - -- Wishbone slaves address decoder & mux - slave_intercon: process(wb_master_out, wb_bram_out, wb_uart0_out) - -- Selected slave - type slave_type is (SLAVE_UART_0, - SLAVE_MEMORY, - SLAVE_NONE); - variable slave : slave_type; + -- Top level Wishbone slaves address decoder & mux + -- + -- From CPU to BRAM, DRAM, IO, selected on top 3 bits and dram_at_0 + -- 0000 - BRAM + -- 0001 - DRAM + -- 01xx - DRAM + -- 10xx - BRAM + -- 11xx - IO + -- + slave_top_intercon: process(wb_master_out, wb_bram_out, wb_dram_out, wb_io_out, dram_at_0) + type slave_top_type is (SLAVE_TOP_BRAM, + SLAVE_TOP_DRAM, + SLAVE_TOP_IO); + variable slave_top : slave_top_type; + variable top_decode : std_ulogic_vector(3 downto 0); begin - -- Simple address decoder. - slave := SLAVE_NONE; - if wb_master_out.adr(31 downto 24) = x"00" then - slave := SLAVE_MEMORY; - elsif wb_master_out.adr(31 downto 24) = x"c0" then - if wb_master_out.adr(23 downto 12) = x"002" then - slave := SLAVE_UART_0; - end if; + -- Top-level address decoder + top_decode := wb_master_out.adr(31 downto 29) & dram_at_0; + slave_top := SLAVE_TOP_BRAM; + if std_match(top_decode, "0000") then + slave_top := SLAVE_TOP_BRAM; + elsif std_match(top_decode, "0001") then + slave_top := SLAVE_TOP_DRAM; + elsif std_match(top_decode, "01--") then + slave_top := SLAVE_TOP_DRAM; + elsif std_match(top_decode, "10--") then + slave_top := SLAVE_TOP_BRAM; + elsif std_match(top_decode, "11--") then + slave_top := SLAVE_TOP_IO; end if; - -- Wishbone muxing. Defaults: + -- Top level wishbone muxing. wb_bram_in <= wb_master_out; wb_bram_in.cyc <= '0'; - wb_uart0_in <= wb_master_out; - wb_uart0_in.cyc <= '0'; - case slave is - when SLAVE_MEMORY => + wb_dram_in <= wb_master_out; + wb_dram_in.cyc <= '0'; + wb_io_in <= wb_master_out; + wb_io_in.cyc <= '0'; + case slave_top is + when SLAVE_TOP_BRAM => wb_bram_in.cyc <= wb_master_out.cyc; wb_master_in <= wb_bram_out; - when SLAVE_UART_0 => - wb_uart0_in.cyc <= wb_master_out.cyc; - wb_master_in <= wb_uart0_out; + 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'; when others => - wb_master_in.dat <= (others => '1'); - wb_master_in.ack <= wb_master_out.stb and wb_master_out.cyc; - wb_master_in.stall <= '0'; end case; - end process slave_intercon; - -- Simulated memory and UART + end process; - -- UART0 wishbone slave - -- XXX FIXME: Need a proper wb64->wb8 adapter that - -- converts SELs into low address bits and muxes - -- data accordingly (either that or rejects large - -- cycles). - uart0: entity work.pp_soc_uart + -- Syscon slave + syscon0: entity work.syscon generic map( - FIFO_DEPTH => 32 - ) + HAS_UART => true, + HAS_DRAM => HAS_DRAM, + BRAM_SIZE => MEMORY_SIZE, + DRAM_SIZE => DRAM_SIZE, + DRAM_INIT_SIZE => DRAM_INIT_SIZE, + CLK_FREQ => CLK_FREQ, + HAS_SPI_FLASH => HAS_SPI_FLASH, + SPI_FLASH_OFFSET => SPI_FLASH_OFFSET, + HAS_LITEETH => HAS_LITEETH, + UART0_IS_16550 => UART0_IS_16550, + HAS_UART1 => HAS_UART1 + ) port map( clk => system_clk, - reset => rst, - txd => uart0_txd, - rxd => uart0_rxd, - wb_adr_in => wb_uart0_in.adr(11 downto 0), - wb_dat_in => wb_uart0_in.dat(7 downto 0), - wb_dat_out => uart_dat8, - wb_cyc_in => wb_uart0_in.cyc, - wb_stb_in => wb_uart0_in.stb, - wb_we_in => wb_uart0_in.we, - wb_ack_out => wb_uart0_out.ack + rst => rst, + wishbone_in => wb_syscon_in, + wishbone_out => wb_syscon_out, + dram_at_0 => dram_at_0, + core_reset => do_core_reset, + soc_reset => open -- XXX TODO ); - wb_uart0_out.dat <= x"00000000000000" & uart_dat8; - wb_uart0_out.stall <= '0' when wb_uart0_in.cyc = '0' else not wb_uart0_out.ack; - -- BRAM Memory slave - bram0: entity work.wishbone_bram_wrapper + -- + -- UART0 + -- + -- Either potato (legacy) or 16550 + -- + uart0_pp: if not UART0_IS_16550 generate + uart0: entity work.pp_soc_uart + generic map( + FIFO_DEPTH => 32 + ) + port map( + clk => system_clk, + reset => rst_uart, + txd => uart0_txd, + rxd => uart0_rxd, + irq => uart0_irq, + wb_adr_in => wb_uart0_in.adr(11 downto 0), + wb_dat_in => wb_uart0_in.dat(7 downto 0), + wb_dat_out => uart0_dat8, + wb_cyc_in => wb_uart0_in.cyc, + wb_stb_in => wb_uart0_in.stb, + wb_we_in => wb_uart0_in.we, + wb_ack_out => wb_uart0_out.ack + ); + end generate; + + uart0_16550 : if UART0_IS_16550 generate + signal irq_l : std_ulogic; + begin + uart0: uart_top + port map ( + wb_clk_i => system_clk, + wb_rst_i => rst_uart, + wb_adr_i => wb_uart0_in.adr(4 downto 2), + wb_dat_i => wb_uart0_in.dat(7 downto 0), + wb_dat_o => uart0_dat8, + wb_we_i => wb_uart0_in.we, + wb_stb_i => wb_uart0_in.stb, + wb_cyc_i => wb_uart0_in.cyc, + wb_ack_o => wb_uart0_out.ack, + int_o => irq_l, + stx_pad_o => uart0_txd, + srx_pad_i => uart0_rxd, + rts_pad_o => open, + cts_pad_i => '1', + dtr_pad_o => open, + dsr_pad_i => '1', + ri_pad_i => '0', + dcd_pad_i => '1' + ); + + -- Add a register on the irq out, helps timing + uart0_irq_latch: process(system_clk) + begin + if rising_edge(system_clk) then + uart0_irq <= irq_l; + end if; + end process; + end generate; + + wb_uart0_out.dat <= x"000000" & uart0_dat8; + wb_uart0_out.stall <= not wb_uart0_out.ack; + + -- + -- UART1 + -- + -- Always 16550 if it exists + -- + uart1: if HAS_UART1 generate + signal irq_l : std_ulogic; + begin + uart1: uart_top + port map ( + wb_clk_i => system_clk, + wb_rst_i => rst_uart, + wb_adr_i => wb_uart1_in.adr(4 downto 2), + wb_dat_i => wb_uart1_in.dat(7 downto 0), + wb_dat_o => uart1_dat8, + wb_we_i => wb_uart1_in.we, + wb_stb_i => wb_uart1_in.stb, + wb_cyc_i => wb_uart1_in.cyc, + wb_ack_o => wb_uart1_out.ack, + int_o => irq_l, + stx_pad_o => uart1_txd, + srx_pad_i => uart1_rxd, + rts_pad_o => open, + cts_pad_i => '1', + dtr_pad_o => open, + dsr_pad_i => '1', + ri_pad_i => '0', + dcd_pad_i => '1' + ); + -- Add a register on the irq out, helps timing + uart0_irq_latch: process(system_clk) + begin + if rising_edge(system_clk) then + uart1_irq <= irq_l; + end if; + end process; + wb_uart1_out.dat <= x"000000" & uart1_dat8; + wb_uart1_out.stall <= not wb_uart1_out.ack; + end generate; + + no_uart1 : if not HAS_UART1 generate + wb_uart1_out.dat <= x"00000000"; + wb_uart1_out.ack <= wb_uart1_in.cyc and wb_uart1_in.stb; + wb_uart1_out.stall <= '0'; + end generate; + + spiflash_gen: if HAS_SPI_FLASH generate + spiflash: entity work.spi_flash_ctrl + generic map ( + DATA_LINES => SPI_FLASH_DLINES, + DEF_CLK_DIV => SPI_FLASH_DEF_CKDV, + DEF_QUAD_READ => SPI_FLASH_DEF_QUAD + ) + port map( + rst => rst_spi, + clk => system_clk, + wb_in => wb_spiflash_in, + wb_out => wb_spiflash_out, + wb_sel_reg => wb_spiflash_is_reg, + wb_sel_map => wb_spiflash_is_map, + sck => spi_flash_sck, + cs_n => spi_flash_cs_n, + sdat_o => spi_flash_sdat_o, + sdat_oe => spi_flash_sdat_oe, + sdat_i => spi_flash_sdat_i + ); + end generate; + + no_spi0_gen: if not HAS_SPI_FLASH generate + wb_spiflash_out.dat <= (others => '1'); + wb_spiflash_out.ack <= wb_spiflash_in.cyc and wb_spiflash_in.stb; + wb_spiflash_out.stall <= wb_spiflash_in.cyc and not wb_spiflash_out.ack; + end generate; + + xics_icp: entity work.xics_icp + port map( + clk => system_clk, + rst => rst_xics, + wb_in => wb_xics_icp_in, + wb_out => wb_xics_icp_out, + ics_in => ics_to_icp, + core_irq_out => core_ext_irq + ); + + xics_ics: entity work.xics_ics generic map( - MEMORY_SIZE => MEMORY_SIZE, - RAM_INIT_FILE => RAM_INIT_FILE + SRC_NUM => 16, + PRIO_BITS => 3 ) port map( clk => system_clk, - rst => rst, - wishbone_in => wb_bram_in, - wishbone_out => wb_bram_out + rst => rst_xics, + wb_in => wb_xics_ics_in, + wb_out => wb_xics_ics_out, + int_level_in => int_level_in, + icp_out => ics_to_icp ); + -- Assign external interrupts + interrupts: process(all) + begin + int_level_in <= (others => '0'); + int_level_in(0) <= uart0_irq; + int_level_in(1) <= ext_irq_eth; + int_level_in(2) <= uart1_irq; + end process; + + -- BRAM Memory slave + bram: if MEMORY_SIZE /= 0 generate + bram0: entity work.wishbone_bram_wrapper + generic map( + MEMORY_SIZE => MEMORY_SIZE, + RAM_INIT_FILE => RAM_INIT_FILE + ) + port map( + clk => system_clk, + rst => rst_bram, + wishbone_in => wb_bram_in, + wishbone_out => wb_bram_out + ); + end generate; + + no_bram: if MEMORY_SIZE = 0 generate + wb_bram_out.ack <= wb_bram_in.cyc and wb_bram_in.stb; + wb_bram_out.dat <= x"FFFFFFFFFFFFFFFF"; + wb_bram_out.stall <= not wb_bram_out.ack; + end generate; + -- DMI(debug bus) <-> JTAG bridge dtm: entity work.dmi_dtm generic map( @@ -190,7 +844,7 @@ begin ) port map( sys_clk => system_clk, - sys_reset => rst, + sys_reset => rst_dtm, dmi_addr => dmi_addr, dmi_din => dmi_din, dmi_dout => dmi_dout, @@ -248,7 +902,8 @@ begin -- Wishbone debug master (TODO: Add a DMI address decoder) wishbone_debug: entity work.wishbone_debug_master - port map(clk => system_clk, rst => rst, + port map(clk => system_clk, + rst => rst_wbdb, dmi_addr => dmi_addr(1 downto 0), dmi_dout => dmi_wb_dout, dmi_din => dmi_dout,