From 9961d70dfbcae24dc75b1f5a963ac7372b534af4 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Tue, 24 Sep 2019 14:57:34 +1000 Subject: [PATCH] Improve PLL/MMCM clocks configuration We can now pass both the input clock and target clock frequency via generics. Add support for both 50Mhz and 100Mhz target freqs for both cases. Signed-off-by: Benjamin Herrenschmidt --- fpga/clk_gen_mcmm.vhd | 74 ++++++++++++++++++------ fpga/clk_gen_plle2.vhd | 128 ++++++++++++++++++++++++----------------- fpga/toplevel.vhdl | 8 ++- microwatt.core | 42 ++++++++++++-- 4 files changed, 176 insertions(+), 76 deletions(-) diff --git a/fpga/clk_gen_mcmm.vhd b/fpga/clk_gen_mcmm.vhd index 206b02a..08db930 100644 --- a/fpga/clk_gen_mcmm.vhd +++ b/fpga/clk_gen_mcmm.vhd @@ -6,7 +6,9 @@ use UNISIM.vcomponents.all; entity clock_generator is generic ( - clk_period_hz : positive := 12000000); + CLK_INPUT_HZ : positive := 12000000; + CLK_OUTPUT_HZ : positive := 50000000 + ); port ( ext_clk : in std_logic; pll_rst_in : in std_logic; @@ -22,28 +24,66 @@ architecture rtl of clock_generator is clkfbout_mult : real range 2.0 to 64.0; clkout_divide : real range 1.0 to 128.0; divclk_divide : integer range 1 to 106; + force_rst : std_ulogic; end record; function gen_pll_settings ( - constant freq_hz : positive) + constant input_hz : positive; + constant output_hz : positive) return pll_settings_t is + + constant bad_settings : pll_settings_t := + (clkin_period => 0.0, + clkfbout_mult => 2.0, + clkout_divide => 1.0, + divclk_divide => 1, + force_rst => '1'); begin - if freq_hz = 100000000 then - return (clkin_period => 10.0, - clkfbout_mult => 16.0, - clkout_divide => 32.0, - divclk_divide => 1); - elsif freq_hz = 12000000 then - return (clkin_period => 83.33, - clkfbout_mult => 50.0, - clkout_divide => 12.0, - divclk_divide => 1); - else - report "Unsupported input frequency" severity failure; - end if; + case input_hz is + when 100000000 => + case output_hz is + when 100000000 => + return (clkin_period => 10.0, + clkfbout_mult => 16.0, + clkout_divide => 16.0, + divclk_divide => 1, + force_rst => '0'); + when 50000000 => + return (clkin_period => 10.0, + clkfbout_mult => 16.0, + clkout_divide => 32.0, + divclk_divide => 1, + force_rst => '0'); + when others => + report "Unsupported output frequency" severity failure; + return bad_settings; + end case; + when 12000000 => + case output_hz is + when 100000000 => + return (clkin_period => 83.33, + clkfbout_mult => 50.0, + clkout_divide => 6.0, + divclk_divide => 1, + force_rst => '0'); + when 50000000 => + return (clkin_period => 83.33, + clkfbout_mult => 50.0, + clkout_divide => 12.0, + divclk_divide => 1, + force_rst => '0'); + when others => + report "Unsupported output frequency" severity failure; + return bad_settings; + end case; + when others => + report "Unsupported input frequency" severity failure; + return bad_settings; + end case; end function gen_pll_settings; - constant pll_settings : pll_settings_t := gen_pll_settings(clk_period_hz); + constant pll_settings : pll_settings_t := gen_pll_settings(clk_input_hz, + clk_output_hz); begin pll : MMCME2_BASE generic map ( @@ -71,6 +111,6 @@ begin CLKFBIN => clkfb, CLKIN1 => ext_clk, PWRDWN => '0', - RST => pll_rst_in + RST => pll_rst_in or pll_settings.force_rst ); end architecture rtl; diff --git a/fpga/clk_gen_plle2.vhd b/fpga/clk_gen_plle2.vhd index f82cb53..750840b 100644 --- a/fpga/clk_gen_plle2.vhd +++ b/fpga/clk_gen_plle2.vhd @@ -5,67 +5,89 @@ Library UNISIM; use UNISIM.vcomponents.all; entity clock_generator is - generic ( - clk_period_hz : positive := 100000000); - port ( - ext_clk : in std_logic; - pll_rst_in : in std_logic; - pll_clk_out : out std_logic; - pll_locked_out : out std_logic); + generic ( + CLK_INPUT_HZ : positive := 100000000; + CLK_OUTPUT_HZ : positive := 100000000 + ); + port ( + ext_clk : in std_logic; + pll_rst_in : in std_logic; + pll_clk_out : out std_logic; + pll_locked_out : out std_logic); end entity clock_generator; architecture rtl of clock_generator is + signal clkfb : std_ulogic; - signal clkfb : std_ulogic; + type pll_settings_t is record + clkin_period : real range 0.000 to 52.631; + clkfbout_mult : integer range 2 to 64; + clkout_divide : integer range 1 to 128; + divclk_divide : integer range 1 to 56; + force_rst : std_ulogic; + end record; - type pll_settings_t is record - clkin_period : real range 0.000 to 52.631; - clkfbout_mult : integer range 2 to 64; - clkout_divide : integer range 1 to 128; - divclk_divide : integer range 1 to 56; - end record; + function gen_pll_settings ( + constant input_hz : positive; + constant output_hz : positive) + return pll_settings_t is - function gen_pll_settings ( - constant freq_hz : positive) - return pll_settings_t is - begin - if freq_hz = 100000000 then - return (clkin_period => 10.0, - clkfbout_mult => 16, - clkout_divide => 32, - divclk_divide => 1); - else - report "Unsupported input frequency" severity failure; --- return (clkin_period => 0.0, --- clkfbout_mult => 0, --- clkout_divide => 0, --- divclk_divide => 0); - end if; - end function gen_pll_settings; + constant bad_settings : pll_settings_t := + (clkin_period => 0.0, + clkfbout_mult => 2, + clkout_divide => 1, + divclk_divide => 1, + force_rst => '1'); + begin + case input_hz is + when 100000000 => + case output_hz is + when 100000000 => + return (clkin_period => 10.0, + clkfbout_mult => 16, + clkout_divide => 16, + divclk_divide => 1, + force_rst => '0'); + when 50000000 => + return (clkin_period => 10.0, + clkfbout_mult => 16, + clkout_divide => 32, + divclk_divide => 1, + force_rst => '0'); + when others => + report "Unsupported output frequency" severity failure; + return bad_settings; + end case; + when others => + report "Unsupported input frequency" severity failure; + return bad_settings; + end case; + end function gen_pll_settings; - constant pll_settings : pll_settings_t := gen_pll_settings(clk_period_hz); + constant pll_settings : pll_settings_t := gen_pll_settings(clk_input_hz, + clk_output_hz); begin - pll : PLLE2_BASE - generic map ( - BANDWIDTH => "OPTIMIZED", - CLKFBOUT_MULT => pll_settings.clkfbout_mult, - CLKIN1_PERIOD => pll_settings.clkin_period, - CLKOUT0_DIVIDE => pll_settings.clkout_divide, - DIVCLK_DIVIDE => pll_settings.divclk_divide, - STARTUP_WAIT => "FALSE") - port map ( - CLKOUT0 => pll_clk_out, - CLKOUT1 => open, - CLKOUT2 => open, - CLKOUT3 => open, - CLKOUT4 => open, - CLKOUT5 => open, - CLKFBOUT => clkfb, - LOCKED => pll_locked_out, - CLKIN1 => ext_clk, - PWRDWN => '0', - RST => pll_rst_in, - CLKFBIN => clkfb); + pll : PLLE2_BASE + generic map ( + BANDWIDTH => "OPTIMIZED", + CLKFBOUT_MULT => pll_settings.clkfbout_mult, + CLKIN1_PERIOD => pll_settings.clkin_period, + CLKOUT0_DIVIDE => pll_settings.clkout_divide, + DIVCLK_DIVIDE => pll_settings.divclk_divide, + STARTUP_WAIT => "FALSE") + port map ( + CLKOUT0 => pll_clk_out, + CLKOUT1 => open, + CLKOUT2 => open, + CLKOUT3 => open, + CLKOUT4 => open, + CLKOUT5 => open, + CLKFBOUT => clkfb, + LOCKED => pll_locked_out, + CLKIN1 => ext_clk, + PWRDWN => '0', + RST => pll_rst_in or pll_settings.force_rst, + CLKFBIN => clkfb); end architecture rtl; diff --git a/fpga/toplevel.vhdl b/fpga/toplevel.vhdl index c6ed4ae..d73c802 100644 --- a/fpga/toplevel.vhdl +++ b/fpga/toplevel.vhdl @@ -5,7 +5,9 @@ entity toplevel is generic ( MEMORY_SIZE : positive := 524288; RAM_INIT_FILE : string := "firmware.hex"; - RESET_LOW : boolean := true + RESET_LOW : boolean := true; + CLK_INPUT : positive := 100000000; + CLK_FREQUENCY : positive := 100000000 ); port( ext_clk : in std_ulogic; @@ -43,6 +45,10 @@ begin ); clkgen: entity work.clock_generator + generic map( + CLK_INPUT_HZ => CLK_INPUT, + CLK_OUTPUT_HZ => CLK_FREQUENCY + ) port map( ext_clk => ext_clk, pll_rst_in => pll_rst, diff --git a/microwatt.core b/microwatt.core index b32148a..94ff0c1 100644 --- a/microwatt.core +++ b/microwatt.core @@ -81,7 +81,11 @@ targets: nexys_a7: default_tool: vivado filesets: [core, nexys_a7, soc, fpga, debug_xilinx] - parameters : [memory_size, ram_init_file] + parameters : + - memory_size + - ram_init_file + - clk_input + - clk_frequency tools: vivado: {part : xc7a100tcsg324-1} toplevel : toplevel @@ -89,7 +93,11 @@ targets: nexys_video: default_tool: vivado filesets: [core, nexys_video, soc, fpga, debug_xilinx] - parameters : [memory_size, ram_init_file] + parameters : + - memory_size + - ram_init_file + - clk_input + - clk_frequency tools: vivado: {part : xc7a200tsbg484-1} toplevel : toplevel @@ -97,7 +105,11 @@ targets: arty_a7-35: default_tool: vivado filesets: [core, arty_a7, soc, fpga, debug_xilinx] - parameters : [memory_size, ram_init_file] + parameters : + - memory_size + - ram_init_file + - clk_input + - clk_frequency tools: vivado: {part : xc7a35ticsg324-1L} toplevel : toplevel @@ -105,7 +117,11 @@ targets: arty_a7-100: default_tool: vivado filesets: [core, arty_a7, soc, fpga, debug_xilinx] - parameters : [memory_size, ram_init_file] + parameters : + - memory_size + - ram_init_file + - clk_input + - clk_frequency tools: vivado: {part : xc7a100ticsg324-1L} toplevel : toplevel @@ -113,7 +129,11 @@ targets: cmod_a7-35: default_tool: vivado filesets: [core, cmod_a7-35, soc, fpga, debug_xilinx] - parameters : [memory_size, ram_init_file, reset_low=false] + parameters : + - memory_size + - ram_init_file + - reset_low=false + - clk_input=12000000 tools: vivado: {part : xc7a35tcpg236-1} toplevel : toplevel @@ -139,3 +159,15 @@ parameters: datatype : bool description : External reset button polarity paramtype : generic + + clk_input: + datatype : int + description : Clock input frequency in HZ (for top-generic based boards) + paramtype : generic + default : 100000000 + + clk_frequency: + datatype : int + description : Generated system clock frequency in HZ (for top-generic based boards) + paramtype : generic + default : 50000000