From 025cf5efe8591c4f0802fd2f1472e57481069152 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Tue, 24 Sep 2019 22:24:31 +1000 Subject: [PATCH] syscon: Add syscon registers These provides some info about the SoC (though it's still somewhat incomplete and needs more work, see comments). There's also a control register for selecting DRAM vs. BRAM at 0 (and for soft-resetting the SoC but that isn't wired up yet). Signed-off-by: Benjamin Herrenschmidt --- Makefile | 3 +- core_tb.vhdl | 3 +- fpga/top-arty.vhdl | 2 + fpga/top-nexys-video.vhdl | 2 + litedram/gen-src/sdram_init/main.c | 3 +- microwatt.core | 1 + soc.vhdl | 49 +++++++++-- syscon.vhdl | 136 +++++++++++++++++++++++++++++ 8 files changed, 190 insertions(+), 9 deletions(-) create mode 100644 syscon.vhdl diff --git a/Makefile b/Makefile index 1978d01..b9ad461 100644 --- a/Makefile +++ b/Makefile @@ -71,7 +71,8 @@ rotator_tb.o: common.o glibc_random.o ppc_fx_insns.o insn_helpers.o rotator.o sim_console.o: sim_uart.o: wishbone_types.o sim_console.o xics.o: wishbone_types.o common.o -soc.o: common.o wishbone_types.o core.o wishbone_arbiter.o sim_uart.o wishbone_bram_wrapper.o dmi_dtm_xilinx.o wishbone_debug_master.o xics.o +soc.o: common.o wishbone_types.o core.o wishbone_arbiter.o sim_uart.o wishbone_bram_wrapper.o dmi_dtm_xilinx.o wishbone_debug_master.o xics.o syscon.o +syscon.o: wishbone_types.o wishbone_arbiter.o: wishbone_types.o wishbone_types.o: writeback.o: common.o crhelpers.o diff --git a/core_tb.vhdl b/core_tb.vhdl index c473de3..9c08919 100644 --- a/core_tb.vhdl +++ b/core_tb.vhdl @@ -25,7 +25,8 @@ begin SIM => true, MEMORY_SIZE => (384*1024), RAM_INIT_FILE => "main_ram.bin", - RESET_LOW => false + RESET_LOW => false, + CLK_FREQ => 100000000 ) port map( rst => rst, diff --git a/fpga/top-arty.vhdl b/fpga/top-arty.vhdl index a458c04..fbea534 100644 --- a/fpga/top-arty.vhdl +++ b/fpga/top-arty.vhdl @@ -92,7 +92,9 @@ begin RAM_INIT_FILE => RAM_INIT_FILE, RESET_LOW => RESET_LOW, SIM => false, + CLK_FREQ => CLK_FREQUENCY, HAS_DRAM => USE_LITEDRAM, + DRAM_SIZE => 256 * 1024 * 1024, DISABLE_FLATTEN_CORE => DISABLE_FLATTEN_CORE ) port map ( diff --git a/fpga/top-nexys-video.vhdl b/fpga/top-nexys-video.vhdl index ea23dd5..c0e3659 100644 --- a/fpga/top-nexys-video.vhdl +++ b/fpga/top-nexys-video.vhdl @@ -75,7 +75,9 @@ begin RAM_INIT_FILE => RAM_INIT_FILE, RESET_LOW => RESET_LOW, SIM => false, + CLK_FREQ => CLK_FREQUENCY, HAS_DRAM => USE_LITEDRAM, + DRAM_SIZE => 512 * 1024 * 1024, DISABLE_FLATTEN_CORE => DISABLE_FLATTEN_CORE ) port map ( diff --git a/litedram/gen-src/sdram_init/main.c b/litedram/gen-src/sdram_init/main.c index cc8b714..eae5c28 100644 --- a/litedram/gen-src/sdram_init/main.c +++ b/litedram/gen-src/sdram_init/main.c @@ -156,7 +156,8 @@ void main(void) printf(" INFO: %016llx\n", (unsigned long long)readq(SYSCON_BASE + 0x08)); printf(" BRAMINFO: %016llx\n", (unsigned long long)readq(SYSCON_BASE + 0x10)); printf(" DRAMINFO: %016llx\n", (unsigned long long)readq(SYSCON_BASE + 0x18)); - printf(" CTRL: %016llx\n", (unsigned long long)readq(SYSCON_BASE + 0x20)); + printf(" CLKINFO: %016llx\n", (unsigned long long)readq(SYSCON_BASE + 0x20)); + printf(" CTRL: %016llx\n", (unsigned long long)readq(SYSCON_BASE + 0x28)); sdrinit(); printf("Booting from BRAM...\n"); } diff --git a/microwatt.core b/microwatt.core index f7002ae..a1ae14b 100644 --- a/microwatt.core +++ b/microwatt.core @@ -46,6 +46,7 @@ filesets: - wishbone_bram_wrapper.vhdl - soc.vhdl - xics.vhdl + - syscon.vhdl file_type : vhdlSource-2008 fpga: diff --git a/soc.vhdl b/soc.vhdl index 53fa2f1..db52db3 100644 --- a/soc.vhdl +++ b/soc.vhdl @@ -12,8 +12,9 @@ use work.wishbone_types.all; -- Memory map: -- --- 0x00000000: Block RAM +-- 0x00000000: Block RAM (MEMORY_SIZE) or DRAM depending on syscon -- 0x40000000: DRAM (when present) +-- 0xc0000000: SYSCON -- 0xc0002000: UART0 -- 0xc0004000: XICS ICP -- 0xf0000000: Block RAM (aliased & repeated) @@ -24,9 +25,11 @@ entity soc is MEMORY_SIZE : positive; RAM_INIT_FILE : string; RESET_LOW : boolean; + CLK_FREQ : positive; SIM : boolean; DISABLE_FLATTEN_CORE : boolean := false; - HAS_DRAM : boolean := false + HAS_DRAM : boolean := false; + DRAM_SIZE : integer := 0 ); port( rst : in std_ulogic; @@ -67,6 +70,12 @@ architecture behaviour of soc is 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; @@ -110,7 +119,7 @@ begin ) port map( clk => system_clk, - rst => rst, + rst => rst or core_reset, alt_reset => alt_reset, wishbone_insn_in => wishbone_icore_in, wishbone_insn_out => wishbone_icore_out, @@ -145,9 +154,10 @@ begin ); -- Wishbone slaves address decoder & mux - slave_intercon: process(wb_master_out, wb_bram_out, wb_uart0_out, wb_dram_out) + 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_UART, + type slave_type is (SLAVE_SYSCON, + SLAVE_UART, SLAVE_BRAM, SLAVE_DRAM, SLAVE_DRAM_INIT, @@ -161,13 +171,16 @@ begin -- 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_BRAM; + 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 @@ -192,6 +205,8 @@ begin wb_dram_in.cyc <= '0'; wb_dram_csr <= '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; @@ -207,6 +222,9 @@ begin wb_dram_in.cyc <= wb_master_out.cyc; wb_master_in <= wb_dram_out; wb_dram_csr <= '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; @@ -220,6 +238,25 @@ begin 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 diff --git a/syscon.vhdl b/syscon.vhdl new file mode 100644 index 0000000..a5b569b --- /dev/null +++ b/syscon.vhdl @@ -0,0 +1,136 @@ +-- syscon module, a bunch of misc global system control MMIO registers +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +library work; +use work.wishbone_types.all; + +entity syscon is + generic ( + SIG_VALUE : std_ulogic_vector(63 downto 0) := x"f00daa5500010001"; + CLK_FREQ : integer; + HAS_UART : boolean; + HAS_DRAM : boolean; + BRAM_SIZE : integer; + DRAM_SIZE : integer + ); + port ( + clk : in std_ulogic; + rst : in std_ulogic; + + -- Wishbone ports: + wishbone_in : in wishbone_master_out; + wishbone_out : out wishbone_slave_out; + + -- System control ports + dram_at_0 : out std_ulogic; + core_reset : out std_ulogic; + soc_reset : out std_ulogic + ); +end entity syscon; + + +architecture behaviour of syscon is + -- Register address bits + constant SYS_REG_BITS : positive := 3; + + -- Register addresses (matches wishbone addr downto 3, ie, 8 bytes per reg) + constant SYS_REG_SIG : std_ulogic_vector(SYS_REG_BITS-1 downto 0) := "000"; + constant SYS_REG_INFO : std_ulogic_vector(SYS_REG_BITS-1 downto 0) := "001"; + constant SYS_REG_BRAMINFO : std_ulogic_vector(SYS_REG_BITS-1 downto 0) := "010"; + constant SYS_REG_DRAMINFO : std_ulogic_vector(SYS_REG_BITS-1 downto 0) := "011"; + constant SYS_REG_CLKINFO : std_ulogic_vector(SYS_REG_BITS-1 downto 0) := "100"; + constant SYS_REG_CTRL : std_ulogic_vector(SYS_REG_BITS-1 downto 0) := "101"; + + -- INFO register bits + constant SYS_REG_INFO_HAS_UART : integer := 0; + constant SYS_REG_INFO_HAS_DRAM : integer := 1; + + -- BRAMINFO contains the BRAM size in the bottom 52 bits + -- DRAMINFO contains the DRAM size if any in the bottom 52 bits + -- (both have reserved top bits for future use) + -- CLKINFO contains the CLK frequency is HZ in the bottom 40 bits + + -- CTRL register bits + constant SYS_REG_CTRL_BITS : positive := 3; + constant SYS_REG_CTRL_DRAM_AT_0 : integer := 0; + constant SYS_REG_CTRL_CORE_RESET : integer := 1; + constant SYS_REG_CTRL_SOC_RESET : integer := 2; + + -- Ctrl register + signal reg_ctrl : std_ulogic_vector(SYS_REG_CTRL_BITS-1 downto 0); + signal reg_ctrl_out : std_ulogic_vector(63 downto 0); + + -- Others + signal reg_info : std_ulogic_vector(63 downto 0); + signal reg_braminfo : std_ulogic_vector(63 downto 0); + signal reg_draminfo : std_ulogic_vector(63 downto 0); + signal reg_clkinfo : std_ulogic_vector(63 downto 0); + signal info_has_dram : std_ulogic; + signal info_has_uart : std_ulogic; + signal info_clk : std_ulogic_vector(39 downto 0); +begin + + -- Generated output signals + dram_at_0 <= reg_ctrl(SYS_REG_CTRL_DRAM_AT_0); + soc_reset <= reg_ctrl(SYS_REG_CTRL_SOC_RESET); + core_reset <= reg_ctrl(SYS_REG_CTRL_CORE_RESET); + + -- All register accesses are single cycle + wishbone_out.ack <= wishbone_in.cyc and wishbone_in.stb; + wishbone_out.stall <= '0'; + + -- Info register is hard wired + info_has_uart <= '1' when HAS_UART else '0'; + info_has_dram <= '1' when HAS_DRAM else '0'; + info_clk <= std_ulogic_vector(to_unsigned(CLK_FREQ, 40)); + reg_info <= (0 => info_has_uart, + 1 => info_has_dram, + others => '0'); + reg_braminfo <= x"000" & std_ulogic_vector(to_unsigned(BRAM_SIZE, 52)); + reg_draminfo <= x"000" & std_ulogic_vector(to_unsigned(DRAM_SIZE, 52)) when HAS_DRAM + else (others => '0'); + reg_clkinfo <= (39 downto 0 => info_clk, + others => '0'); + + -- Control register read composition + reg_ctrl_out <= (63 downto SYS_REG_CTRL_BITS => '0', + SYS_REG_CTRL_BITS-1 downto 0 => reg_ctrl); + + -- Register read mux + with wishbone_in.adr(SYS_REG_BITS+2 downto 3) select wishbone_out.dat <= + SIG_VALUE when SYS_REG_SIG, + reg_info when SYS_REG_INFO, + reg_braminfo when SYS_REG_BRAMINFO, + reg_draminfo when SYS_REG_DRAMINFO, + reg_clkinfo when SYS_REG_CLKINFO, + reg_ctrl_out when SYS_REG_CTRL, + (others => '0') when others; + + -- Register writes + regs_write: process(clk) + begin + if rising_edge(clk) then + if (rst) then + reg_ctrl <= (others => '0'); + else + if wishbone_in.cyc and wishbone_in.stb and wishbone_in.we then + if wishbone_in.adr(SYS_REG_BITS+2 downto 3) = SYS_REG_CTRL then + reg_ctrl(SYS_REG_CTRL_BITS-1 downto 0) <= + wishbone_in.dat(SYS_REG_CTRL_BITS-1 downto 0); + end if; + end if; + + -- Reset auto-clear + if reg_ctrl(SYS_REG_CTRL_SOC_RESET) = '1' then + reg_ctrl(SYS_REG_CTRL_SOC_RESET) <= '0'; + end if; + if reg_ctrl(SYS_REG_CTRL_CORE_RESET) = '1' then + reg_ctrl(SYS_REG_CTRL_CORE_RESET) <= '0'; + end if; + end if; + end if; + end process; + +end architecture behaviour;