You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
microwatt/soc.vhdl

420 lines
12 KiB
VHDL

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.all;
use std.textio.all;
use std.env.stop;
library work;
use work.common.all;
use work.wishbone_types.all;
-- Memory map:
--
-- 0x00000000: Block RAM (MEMORY_SIZE) or DRAM depending on syscon
-- 0x40000000: DRAM (when present)
-- 0xc0000000: SYSCON
-- 0xc0002000: UART0
-- 0xc0004000: XICS ICP
-- 0xc0100000: LiteDRAM control (CSRs)
-- 0xf0000000: Block RAM (aliased & repeated)
-- 0xffff0000: DRAM init code (if any)
entity soc is
generic (
MEMORY_SIZE : positive;
RAM_INIT_FILE : string;
RESET_LOW : boolean;
CLK_FREQ : positive;
SIM : boolean;
DISABLE_FLATTEN_CORE : boolean := false;
HAS_DRAM : boolean := false;
DRAM_SIZE : integer := 0
);
port(
rst : in std_ulogic;
system_clk : in std_ulogic;
-- DRAM controller signals
wb_dram_in : out wishbone_master_out;
wb_dram_out : in wishbone_slave_out;
wb_dram_ctrl : out std_ulogic;
wb_dram_init : out std_ulogic;
-- UART0 signals:
uart0_txd : out std_ulogic;
uart0_rxd : in std_ulogic;
-- DRAM controller signals
alt_reset : in std_ulogic
);
end entity soc;
architecture behaviour of soc is
-- Wishbone master signals:
signal wishbone_dcore_in : wishbone_slave_out;
signal wishbone_dcore_out : wishbone_master_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;
-- Syscon signals
signal dram_at_0 : std_ulogic;
signal core_reset : std_ulogic;
signal wb_syscon_in : wishbone_master_out;
signal wb_syscon_out : wishbone_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);
-- XICS0 signals:
signal wb_xics0_in : wishbone_master_out;
signal wb_xics0_out : wishbone_slave_out;
signal int_level_in : std_ulogic_vector(15 downto 0);
signal xics_to_execute1 : XicsToExecute1Type;
-- 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);
signal dmi_din : std_ulogic_vector(63 downto 0);
signal dmi_dout : std_ulogic_vector(63 downto 0);
signal dmi_req : std_ulogic;
signal dmi_wr : std_ulogic;
signal dmi_ack : std_ulogic;
-- Per slave DMI signals
signal dmi_wb_dout : std_ulogic_vector(63 downto 0);
signal dmi_wb_req : std_ulogic;
signal dmi_wb_ack : std_ulogic;
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_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;
begin
resets: process(system_clk)
begin
if rising_edge(system_clk) then
rst_core <= rst or core_reset;
rst_uart <= 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,
ALT_RESET_ADDRESS => (15 downto 0 => '0', others => '1')
)
port map(
clk => system_clk,
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,
wishbone_data_out => wishbone_dcore_out,
dmi_addr => dmi_addr(3 downto 0),
dmi_dout => dmi_core_dout,
dmi_din => dmi_dout,
dmi_wr => dmi_wr,
dmi_ack => dmi_core_ack,
dmi_req => dmi_core_req,
xics_in => xics_to_execute1
);
-- 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_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, wb_dram_out, wb_syscon_out)
-- Selected slave
type slave_type is (SLAVE_SYSCON,
SLAVE_UART,
SLAVE_BRAM,
SLAVE_DRAM,
SLAVE_DRAM_INIT,
SLAVE_DRAM_CTRL,
SLAVE_ICP_0,
SLAVE_NONE);
variable slave : slave_type;
begin
-- Simple address decoder.
slave := SLAVE_NONE;
-- Simple address decoder. Ignore top bits to save silicon for now
slave := SLAVE_NONE;
if std_match(wb_master_out.adr, x"0-------") then
slave := SLAVE_DRAM when HAS_DRAM and dram_at_0 = '1' else
SLAVE_BRAM;
elsif std_match(wb_master_out.adr, x"FFFF----") then
slave := SLAVE_DRAM_INIT;
elsif std_match(wb_master_out.adr, x"F-------") then
slave := SLAVE_BRAM;
elsif std_match(wb_master_out.adr, x"4-------") and HAS_DRAM then
slave := SLAVE_DRAM;
elsif std_match(wb_master_out.adr, x"C0000---") then
slave := SLAVE_SYSCON;
elsif std_match(wb_master_out.adr, x"C0002---") then
slave := SLAVE_UART;
elsif std_match(wb_master_out.adr, x"C01-----") then
slave := SLAVE_DRAM_CTRL;
elsif std_match(wb_master_out.adr, x"C0004---") then
slave := SLAVE_ICP_0;
end if;
-- Wishbone muxing. Defaults:
wb_bram_in <= wb_master_out;
wb_bram_in.cyc <= '0';
wb_uart0_in <= wb_master_out;
wb_uart0_in.cyc <= '0';
-- Only give xics 8 bits of wb addr
wb_xics0_in <= wb_master_out;
wb_xics0_in.adr <= (others => '0');
wb_xics0_in.adr(7 downto 0) <= wb_master_out.adr(7 downto 0);
wb_xics0_in.cyc <= '0';
wb_dram_in <= wb_master_out;
wb_dram_in.cyc <= '0';
wb_dram_ctrl <= '0';
wb_dram_init <= '0';
wb_syscon_in <= wb_master_out;
wb_syscon_in.cyc <= '0';
case slave is
when SLAVE_BRAM =>
wb_bram_in.cyc <= wb_master_out.cyc;
wb_master_in <= wb_bram_out;
when SLAVE_DRAM =>
wb_dram_in.cyc <= wb_master_out.cyc;
wb_master_in <= wb_dram_out;
when SLAVE_DRAM_INIT =>
wb_dram_in.cyc <= wb_master_out.cyc;
wb_master_in <= wb_dram_out;
wb_dram_init <= '1';
when SLAVE_DRAM_CTRL =>
wb_dram_in.cyc <= wb_master_out.cyc;
wb_master_in <= wb_dram_out;
wb_dram_ctrl <= '1';
when SLAVE_SYSCON =>
wb_syscon_in.cyc <= wb_master_out.cyc;
wb_master_in <= wb_syscon_out;
when SLAVE_UART =>
wb_uart0_in.cyc <= wb_master_out.cyc;
wb_master_in <= wb_uart0_out;
when SLAVE_ICP_0 =>
wb_xics0_in.cyc <= wb_master_out.cyc;
wb_master_in <= wb_xics0_out;
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;
-- Syscon slave
syscon0: entity work.syscon
generic map(
HAS_UART => true,
HAS_DRAM => HAS_DRAM,
BRAM_SIZE => MEMORY_SIZE,
DRAM_SIZE => DRAM_SIZE,
CLK_FREQ => CLK_FREQ
)
port map(
clk => system_clk,
rst => rst,
wishbone_in => wb_syscon_in,
wishbone_out => wb_syscon_out,
dram_at_0 => dram_at_0,
core_reset => core_reset,
soc_reset => open -- XXX TODO
);
-- Simulated memory and UART
-- 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
generic map(
FIFO_DEPTH => 32
)
port map(
clk => system_clk,
reset => rst_uart,
txd => uart0_txd,
rxd => uart0_rxd,
irq => int_level_in(0),
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
);
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;
xics0: entity work.xics
generic map(
LEVEL_NUM => 16
)
port map(
clk => system_clk,
rst => rst_xics,
wb_in => wb_xics0_in,
wb_out => wb_xics0_out,
int_level_in => int_level_in,
e_out => xics_to_execute1
);
-- BRAM Memory slave
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
);
-- DMI(debug bus) <-> JTAG bridge
dtm: entity work.dmi_dtm
generic map(
ABITS => 8,
DBITS => 64
)
port map(
sys_clk => system_clk,
sys_reset => rst_dtm,
dmi_addr => dmi_addr,
dmi_din => dmi_din,
dmi_dout => dmi_dout,
dmi_req => dmi_req,
dmi_wr => dmi_wr,
dmi_ack => dmi_ack
);
-- DMI interconnect
dmi_intercon: process(dmi_addr, dmi_req,
dmi_wb_ack, dmi_wb_dout,
dmi_core_ack, dmi_core_dout)
-- DMI address map (each address is a full 64-bit register)
--
-- Offset: Size: Slave:
-- 0 4 Wishbone
-- 10 16 Core
type slave_type is (SLAVE_WB,
SLAVE_CORE,
SLAVE_NONE);
variable slave : slave_type;
begin
-- Simple address decoder
slave := SLAVE_NONE;
if std_match(dmi_addr, "000000--") then
slave := SLAVE_WB;
elsif std_match(dmi_addr, "0001----") then
slave := SLAVE_CORE;
end if;
-- DMI muxing
dmi_wb_req <= '0';
dmi_core_req <= '0';
case slave is
when SLAVE_WB =>
dmi_wb_req <= dmi_req;
dmi_ack <= dmi_wb_ack;
dmi_din <= dmi_wb_dout;
when SLAVE_CORE =>
dmi_core_req <= dmi_req;
dmi_ack <= dmi_core_ack;
dmi_din <= dmi_core_dout;
when others =>
dmi_ack <= dmi_req;
dmi_din <= (others => '1');
end case;
-- SIM magic exit
if SIM and dmi_req = '1' and dmi_addr = "11111111" and dmi_wr = '1' then
stop;
end if;
end process;
-- Wishbone debug master (TODO: Add a DMI address decoder)
wishbone_debug: entity work.wishbone_debug_master
port map(clk => system_clk,
rst => rst_wbdb,
dmi_addr => dmi_addr(1 downto 0),
dmi_dout => dmi_wb_dout,
dmi_din => dmi_dout,
dmi_wr => dmi_wr,
dmi_ack => dmi_wb_ack,
dmi_req => dmi_wb_req,
wb_in => wishbone_debug_in,
wb_out => wishbone_debug_out);
end architecture behaviour;