mirror of
https://github.com/antonblanchard/microwatt.git
synced 2026-01-11 23:43:15 +00:00
Instead of a single global timebase register in the SoC, we now have a timebase counter in each core; however, now they are only reset by the soc reset, not the core reset. Thus they stay in sync even when some cores are disabled (via the syscon cpu_ctrl register). This implements mtspr to the TBLW and TBUW SPRs, which write the lower and upper 32 bits of this core's timebase, respectively. In order to fulfil the ISA's requirements that (a) some method for getting the timebases into sync and (b) some method for preventing userspace from reading the timebase be provided by the platform, this adds a syscon register TB_CTRL with two read/write bits implemented; bit 0 freezes all the timebases in the system when set, and bit 1 makes reading the timebase privileged (in all cores). Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
287 lines
12 KiB
VHDL
287 lines
12 KiB
VHDL
-- 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.git.all;
|
|
use work.wishbone_types.all;
|
|
|
|
entity syscon is
|
|
generic (
|
|
NCPUS : positive := 1;
|
|
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;
|
|
DRAM_INIT_SIZE : integer;
|
|
HAS_SPI_FLASH : boolean;
|
|
SPI_FLASH_OFFSET : integer;
|
|
HAS_LITEETH : boolean;
|
|
HAS_SD_CARD : boolean;
|
|
UART0_IS_16550 : boolean;
|
|
HAS_UART1 : boolean
|
|
);
|
|
port (
|
|
clk : in std_ulogic;
|
|
rst : in std_ulogic;
|
|
|
|
-- Wishbone ports:
|
|
wishbone_in : in wb_io_master_out;
|
|
wishbone_out : out wb_io_slave_out;
|
|
|
|
-- System control ports
|
|
dram_at_0 : out std_ulogic;
|
|
core_reset : out std_ulogic_vector(NCPUS-1 downto 0);
|
|
soc_reset : out std_ulogic;
|
|
alt_reset : out std_ulogic;
|
|
tb_rdp : out std_ulogic;
|
|
tb_frz : out std_ulogic
|
|
);
|
|
end entity syscon;
|
|
|
|
|
|
architecture behaviour of syscon is
|
|
-- Register address bits
|
|
constant SYS_REG_BITS : positive := 6;
|
|
|
|
-- 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) := "000000";
|
|
constant SYS_REG_INFO : std_ulogic_vector(SYS_REG_BITS-1 downto 0) := "000001";
|
|
constant SYS_REG_BRAMINFO : std_ulogic_vector(SYS_REG_BITS-1 downto 0) := "000010";
|
|
constant SYS_REG_DRAMINFO : std_ulogic_vector(SYS_REG_BITS-1 downto 0) := "000011";
|
|
constant SYS_REG_CLKINFO : std_ulogic_vector(SYS_REG_BITS-1 downto 0) := "000100";
|
|
constant SYS_REG_CTRL : std_ulogic_vector(SYS_REG_BITS-1 downto 0) := "000101";
|
|
constant SYS_REG_DRAMINITINFO : std_ulogic_vector(SYS_REG_BITS-1 downto 0) := "000110";
|
|
constant SYS_REG_SPIFLASHINFO : std_ulogic_vector(SYS_REG_BITS-1 downto 0) := "000111";
|
|
constant SYS_REG_UART0_INFO : std_ulogic_vector(SYS_REG_BITS-1 downto 0) := "001000";
|
|
constant SYS_REG_UART1_INFO : std_ulogic_vector(SYS_REG_BITS-1 downto 0) := "001001";
|
|
constant SYS_REG_GIT_INFO : std_ulogic_vector(SYS_REG_BITS-1 downto 0) := "001010";
|
|
constant SYS_REG_CPU_CTRL : std_ulogic_vector(SYS_REG_BITS-1 downto 0) := "001011";
|
|
constant SYS_REG_TB_CTRL : std_ulogic_vector(SYS_REG_BITS-1 downto 0) := "001100";
|
|
|
|
-- Muxed reg read signal
|
|
signal reg_out : std_ulogic_vector(63 downto 0);
|
|
|
|
-- INFO register bits
|
|
constant SYS_REG_INFO_HAS_UART : integer := 0; -- Has a UART (always set)
|
|
constant SYS_REG_INFO_HAS_DRAM : integer := 1; -- Has DRAM
|
|
constant SYS_REG_INFO_HAS_BRAM : integer := 2; -- Has "main" BRAM
|
|
constant SYS_REG_INFO_HAS_SPIF : integer := 3; -- Has SPI flash
|
|
constant SYS_REG_INFO_HAS_LETH : integer := 4; -- Has LiteEth ethernet
|
|
constant SYS_REG_INFO_HAS_LSYS : integer := 5; -- Has 6-bit address syscon
|
|
constant SYS_REG_INFO_HAS_URT1 : integer := 6; -- Has second UART
|
|
constant SYS_REG_INFO_HAS_ARTB : integer := 7; -- Has architected TB frequency
|
|
constant SYS_REG_INFO_HAS_SDCARD : integer := 8; -- Has LiteSDCard SD-card interface
|
|
|
|
-- 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 := 4;
|
|
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;
|
|
constant SYS_REG_CTRL_ALT_RESET : integer := 3;
|
|
|
|
-- SPI Info register bits
|
|
--
|
|
-- Top 32-bit is flash offset which is the amount of flash
|
|
-- reserved for the FPGA bitfile if any
|
|
constant SYS_REG_SPI_INFO_IS_FLASH : integer := 0;
|
|
|
|
-- UART0/1 info registers bits
|
|
--
|
|
-- 0 ..31 : UART clock freq (in HZ)
|
|
-- 32 : UART is 16550 (otherwise pp)
|
|
--
|
|
|
|
-- GIT info register bits
|
|
--
|
|
-- 0 ..55 : git hash (14 chars = 56 bits)
|
|
-- 63 : dirty flag
|
|
--
|
|
|
|
-- 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);
|
|
signal ctrl_init_alt_reset : std_ulogic;
|
|
|
|
-- 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_dramiinfo : std_ulogic_vector(63 downto 0);
|
|
signal reg_clkinfo : std_ulogic_vector(63 downto 0);
|
|
signal reg_spiinfo : std_ulogic_vector(63 downto 0);
|
|
signal reg_uart0info : std_ulogic_vector(63 downto 0);
|
|
signal reg_uart1info : std_ulogic_vector(63 downto 0);
|
|
signal reg_gitinfo : std_ulogic_vector(63 downto 0);
|
|
signal reg_cpuctrl : std_ulogic_vector(63 downto 0);
|
|
signal reg_tbctrl : std_ulogic_vector(63 downto 0);
|
|
signal info_has_dram : std_ulogic;
|
|
signal info_has_bram : std_ulogic;
|
|
signal info_has_uart : std_ulogic;
|
|
signal info_has_spif : std_ulogic;
|
|
signal info_has_leth : std_ulogic;
|
|
signal info_has_lsdc : std_ulogic;
|
|
signal info_has_urt1 : std_ulogic;
|
|
signal info_clk : std_ulogic_vector(39 downto 0);
|
|
signal info_fl_off : std_ulogic_vector(31 downto 0);
|
|
signal uinfo_16550 : std_ulogic;
|
|
signal uinfo_freq : std_ulogic_vector(31 downto 0);
|
|
signal tb_rdprot : std_ulogic;
|
|
signal tb_freeze : std_ulogic;
|
|
|
|
-- Wishbone response latch
|
|
signal wb_rsp : wb_io_slave_out;
|
|
begin
|
|
-- Generated output signals
|
|
dram_at_0 <= '1' when BRAM_SIZE = 0 else reg_ctrl(SYS_REG_CTRL_DRAM_AT_0);
|
|
soc_reset <= reg_ctrl(SYS_REG_CTRL_SOC_RESET);
|
|
core_reset <= not reg_cpuctrl(NCPUS-1 downto 0) when reg_ctrl(SYS_REG_CTRL_CORE_RESET) = '0'
|
|
else (others => '1');
|
|
alt_reset <= reg_ctrl(SYS_REG_CTRL_ALT_RESET);
|
|
|
|
|
|
-- Info register is hard wired
|
|
info_has_uart <= '1' when HAS_UART else '0';
|
|
info_has_dram <= '1' when HAS_DRAM else '0';
|
|
info_has_bram <= '1' when BRAM_SIZE /= 0 else '0';
|
|
info_has_spif <= '1' when HAS_SPI_FLASH else '0';
|
|
info_has_leth <= '1' when HAS_LITEETH else '0';
|
|
info_has_lsdc <= '1' when HAS_SD_CARD else '0';
|
|
info_has_urt1 <= '1' when HAS_UART1 else '0';
|
|
info_clk <= std_ulogic_vector(to_unsigned(CLK_FREQ, 40));
|
|
reg_info <= (SYS_REG_INFO_HAS_UART => info_has_uart,
|
|
SYS_REG_INFO_HAS_DRAM => info_has_dram,
|
|
SYS_REG_INFO_HAS_BRAM => info_has_bram,
|
|
SYS_REG_INFO_HAS_SPIF => info_has_spif,
|
|
SYS_REG_INFO_HAS_LETH => info_has_leth,
|
|
SYS_REG_INFO_HAS_SDCARD => info_has_lsdc,
|
|
SYS_REG_INFO_HAS_LSYS => '1',
|
|
SYS_REG_INFO_HAS_URT1 => info_has_urt1,
|
|
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_dramiinfo <= x"000" & std_ulogic_vector(to_unsigned(DRAM_INIT_SIZE, 52)) when HAS_DRAM
|
|
else (others => '0');
|
|
reg_clkinfo <= (39 downto 0 => info_clk,
|
|
others => '0');
|
|
info_fl_off <= std_ulogic_vector(to_unsigned(SPI_FLASH_OFFSET, 32));
|
|
reg_spiinfo <= (31 downto 0 => info_fl_off,
|
|
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);
|
|
|
|
-- UART info registers read composition
|
|
uinfo_16550 <= '1' when UART0_IS_16550 else '0';
|
|
uinfo_freq <= std_ulogic_vector(to_unsigned(CLK_FREQ, 32));
|
|
reg_uart0info <= (32 => uinfo_16550,
|
|
31 downto 0 => uinfo_freq,
|
|
others => '0');
|
|
reg_uart1info <= (32 => '1',
|
|
31 downto 0 => uinfo_freq,
|
|
others => '0');
|
|
|
|
-- GIT info register composition
|
|
reg_gitinfo <= (63 => GIT_DIRTY,
|
|
55 downto 0 => GIT_HASH,
|
|
others => '0');
|
|
|
|
reg_cpuctrl(63 downto 8) <= std_ulogic_vector(to_unsigned(NCPUS, 56));
|
|
|
|
reg_tbctrl <= 62x"0" & tb_rdprot & tb_freeze;
|
|
|
|
-- Wishbone response
|
|
wb_rsp.ack <= wishbone_in.cyc and wishbone_in.stb;
|
|
with wishbone_in.adr(SYS_REG_BITS downto 1) select reg_out <=
|
|
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_dramiinfo when SYS_REG_DRAMINITINFO,
|
|
reg_clkinfo when SYS_REG_CLKINFO,
|
|
reg_ctrl_out when SYS_REG_CTRL,
|
|
reg_spiinfo when SYS_REG_SPIFLASHINFO,
|
|
reg_uart0info when SYS_REG_UART0_INFO,
|
|
reg_uart1info when SYS_REG_UART1_INFO,
|
|
reg_gitinfo when SYS_REG_GIT_INFO,
|
|
reg_cpuctrl when SYS_REG_CPU_CTRL,
|
|
reg_tbctrl when SYS_REG_TB_CTRL,
|
|
(others => '0') when others;
|
|
wb_rsp.dat <= reg_out(63 downto 32) when wishbone_in.adr(0) = '1' else
|
|
reg_out(31 downto 0);
|
|
wb_rsp.stall <= '0';
|
|
|
|
-- Wishbone response latch
|
|
regs_read: process(clk)
|
|
begin
|
|
if rising_edge(clk) then
|
|
-- Send response from latch
|
|
wishbone_out <= wb_rsp;
|
|
end if;
|
|
end process;
|
|
|
|
-- Timebase control
|
|
tb_rdp <= tb_rdprot;
|
|
tb_frz <= tb_freeze;
|
|
|
|
-- Initial state
|
|
ctrl_init_alt_reset <= '1' when HAS_DRAM else '0';
|
|
|
|
-- Register writes
|
|
regs_write : process(clk)
|
|
begin
|
|
if rising_edge(clk) then
|
|
if (rst) then
|
|
reg_ctrl <= (SYS_REG_CTRL_ALT_RESET => ctrl_init_alt_reset,
|
|
others => '0');
|
|
reg_cpuctrl(7 downto 0) <= x"01"; -- enable cpu 0 only
|
|
tb_rdprot <= '0';
|
|
tb_freeze <= '0';
|
|
else
|
|
if wishbone_in.cyc and wishbone_in.stb and wishbone_in.we then
|
|
-- Change this if CTRL ever has more than 32 bits
|
|
if wishbone_in.adr(SYS_REG_BITS downto 1) = SYS_REG_CTRL and
|
|
wishbone_in.adr(0) = '0' then
|
|
reg_ctrl(SYS_REG_CTRL_BITS-1 downto 0) <=
|
|
wishbone_in.dat(SYS_REG_CTRL_BITS-1 downto 0);
|
|
end if;
|
|
if wishbone_in.adr(SYS_REG_BITS downto 1) = SYS_REG_CPU_CTRL and
|
|
wishbone_in.adr(0) = '0' and wishbone_in.sel(0) = '1' then
|
|
reg_cpuctrl(7 downto 0) <= wishbone_in.dat(7 downto 0);
|
|
end if;
|
|
if wishbone_in.adr(SYS_REG_BITS downto 1) = SYS_REG_TB_CTRL and
|
|
wishbone_in.adr(0) = '0' and wishbone_in.sel(0) = '1' then
|
|
tb_rdprot <= wishbone_in.dat(1);
|
|
tb_freeze <= wishbone_in.dat(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;
|
|
|
|
-- If BRAM doesn't exist, force DRAM at 0
|
|
if BRAM_SIZE = 0 then
|
|
reg_ctrl(SYS_REG_CTRL_DRAM_AT_0) <= '1';
|
|
end if;
|
|
end if;
|
|
end if;
|
|
end process;
|
|
|
|
end architecture behaviour;
|