Commit 1efb9d7b authored by Tomasz Wlostowski's avatar Tomasz Wlostowski

wishbone: added a clock frequency monitor core. LICENSING TO BE FIXED

parent 0af08792
files = [
"clock_monitor_wbgen2_pkg.vhd",
"clock_monitor_wb.vhd",
"xwb_clock_monitor.vhd"];
---------------------------------------------------------------------------------------
-- Title : Wishbone slave core for Clock Frequency Monitor
---------------------------------------------------------------------------------------
-- File : clock_monitor_wb.vhd
-- Author : auto-generated by wbgen2 from clock_monitor_wb.wb
-- Created : Mon Jun 17 18:28:42 2019
-- Standard : VHDL'87
---------------------------------------------------------------------------------------
-- THIS FILE WAS GENERATED BY wbgen2 FROM SOURCE FILE clock_monitor_wb.wb
-- DO NOT HAND-EDIT UNLESS IT'S ABSOLUTELY NECESSARY!
---------------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.wishbone_pkg.all;
use work.cm_wbgen2_pkg.all;
entity clock_monitor_wb is
port (
rst_n_i : in std_logic;
clk_sys_i : in std_logic;
slave_i : in t_wishbone_slave_in;
slave_o : out t_wishbone_slave_out;
int_o : out std_logic;
regs_i : in t_cm_in_registers;
regs_o : out t_cm_out_registers
);
end clock_monitor_wb;
architecture syn of clock_monitor_wb is
signal cm_cr_cnt_rst_dly0 : std_logic ;
signal cm_cr_cnt_rst_int : std_logic ;
signal cm_cr_presc_int : std_logic_vector(7 downto 0);
signal cm_cr_refsel_int : std_logic_vector(3 downto 0);
signal cm_refdr_refdr_int : std_logic_vector(31 downto 0);
signal cm_cnt_sel_sel_int : std_logic_vector(3 downto 0);
signal ack_sreg : std_logic_vector(9 downto 0);
signal rddata_reg : std_logic_vector(31 downto 0);
signal wrdata_reg : std_logic_vector(31 downto 0);
signal bwsel_reg : std_logic_vector(3 downto 0);
signal rwaddr_reg : std_logic_vector(1 downto 0);
signal ack_in_progress : std_logic ;
signal wr_int : std_logic ;
signal rd_int : std_logic ;
signal allones : std_logic_vector(31 downto 0);
signal allzeros : std_logic_vector(31 downto 0);
begin
-- Some internal signals assignments
wrdata_reg <= slave_i.dat;
--
-- Main register bank access process.
process (clk_sys_i, rst_n_i)
begin
if (rst_n_i = '0') then
ack_sreg <= "0000000000";
ack_in_progress <= '0';
rddata_reg <= "00000000000000000000000000000000";
cm_cr_cnt_rst_int <= '0';
cm_cr_presc_int <= "00000000";
cm_cr_refsel_int <= "0000";
cm_refdr_refdr_int <= "00000000000000000000000000000000";
cm_cnt_sel_sel_int <= "0000";
regs_o.cnt_val_valid_load_o <= '0';
elsif rising_edge(clk_sys_i) then
-- advance the ACK generator shift register
ack_sreg(8 downto 0) <= ack_sreg(9 downto 1);
ack_sreg(9) <= '0';
if (ack_in_progress = '1') then
if (ack_sreg(0) = '1') then
cm_cr_cnt_rst_int <= '0';
regs_o.cnt_val_valid_load_o <= '0';
ack_in_progress <= '0';
else
regs_o.cnt_val_valid_load_o <= '0';
end if;
else
if ((slave_i.cyc = '1') and (slave_i.stb = '1')) then
case rwaddr_reg(1 downto 0) is
when "00" =>
if (slave_i.we = '1') then
cm_cr_cnt_rst_int <= wrdata_reg(0);
cm_cr_presc_int <= wrdata_reg(8 downto 1);
cm_cr_refsel_int <= wrdata_reg(12 downto 9);
end if;
rddata_reg(0) <= '0';
rddata_reg(8 downto 1) <= cm_cr_presc_int;
rddata_reg(12 downto 9) <= cm_cr_refsel_int;
rddata_reg(13) <= 'X';
rddata_reg(14) <= 'X';
rddata_reg(15) <= 'X';
rddata_reg(16) <= 'X';
rddata_reg(17) <= 'X';
rddata_reg(18) <= 'X';
rddata_reg(19) <= 'X';
rddata_reg(20) <= 'X';
rddata_reg(21) <= 'X';
rddata_reg(22) <= 'X';
rddata_reg(23) <= 'X';
rddata_reg(24) <= 'X';
rddata_reg(25) <= 'X';
rddata_reg(26) <= 'X';
rddata_reg(27) <= 'X';
rddata_reg(28) <= 'X';
rddata_reg(29) <= 'X';
rddata_reg(30) <= 'X';
rddata_reg(31) <= 'X';
ack_sreg(2) <= '1';
ack_in_progress <= '1';
when "01" =>
if (slave_i.we = '1') then
cm_refdr_refdr_int <= wrdata_reg(31 downto 0);
end if;
rddata_reg(31 downto 0) <= cm_refdr_refdr_int;
ack_sreg(0) <= '1';
ack_in_progress <= '1';
when "10" =>
if (slave_i.we = '1') then
cm_cnt_sel_sel_int <= wrdata_reg(3 downto 0);
end if;
rddata_reg(3 downto 0) <= cm_cnt_sel_sel_int;
rddata_reg(4) <= 'X';
rddata_reg(5) <= 'X';
rddata_reg(6) <= 'X';
rddata_reg(7) <= 'X';
rddata_reg(8) <= 'X';
rddata_reg(9) <= 'X';
rddata_reg(10) <= 'X';
rddata_reg(11) <= 'X';
rddata_reg(12) <= 'X';
rddata_reg(13) <= 'X';
rddata_reg(14) <= 'X';
rddata_reg(15) <= 'X';
rddata_reg(16) <= 'X';
rddata_reg(17) <= 'X';
rddata_reg(18) <= 'X';
rddata_reg(19) <= 'X';
rddata_reg(20) <= 'X';
rddata_reg(21) <= 'X';
rddata_reg(22) <= 'X';
rddata_reg(23) <= 'X';
rddata_reg(24) <= 'X';
rddata_reg(25) <= 'X';
rddata_reg(26) <= 'X';
rddata_reg(27) <= 'X';
rddata_reg(28) <= 'X';
rddata_reg(29) <= 'X';
rddata_reg(30) <= 'X';
rddata_reg(31) <= 'X';
ack_sreg(0) <= '1';
ack_in_progress <= '1';
when "11" =>
if (slave_i.we = '1') then
regs_o.cnt_val_valid_load_o <= '1';
end if;
rddata_reg(30 downto 0) <= regs_i.cnt_val_value_i;
rddata_reg(31) <= regs_i.cnt_val_valid_i;
ack_sreg(0) <= '1';
ack_in_progress <= '1';
when others =>
-- prevent the slave from hanging the bus on invalid address
ack_in_progress <= '1';
ack_sreg(0) <= '1';
end case;
end if;
end if;
end if;
end process;
-- Drive the data output bus
slave_o.dat <= rddata_reg;
-- Reset counters
process (clk_sys_i, rst_n_i)
begin
if (rst_n_i = '0') then
cm_cr_cnt_rst_dly0 <= '0';
regs_o.cr_cnt_rst_o <= '0';
elsif rising_edge(clk_sys_i) then
cm_cr_cnt_rst_dly0 <= cm_cr_cnt_rst_int;
regs_o.cr_cnt_rst_o <= cm_cr_cnt_rst_int and (not cm_cr_cnt_rst_dly0);
end if;
end process;
-- Prescaler
regs_o.cr_presc_o <= cm_cr_presc_int;
-- Reference Select
regs_o.cr_refsel_o <= cm_cr_refsel_int;
-- Reference Division Ratio
regs_o.refdr_refdr_o <= cm_refdr_refdr_int;
-- Counter Select
regs_o.cnt_sel_sel_o <= cm_cnt_sel_sel_int;
-- Counter Value
-- Counter Value Valid/Clear
regs_o.cnt_val_valid_o <= wrdata_reg(31);
rwaddr_reg <= slave_i.adr(3 downto 2);
slave_o.stall <= (not ack_sreg(0)) and (slave_i.stb and slave_i.cyc);
slave_o.err <= '0';
slave_o.rty <= '0';
-- ACK signal generation. Just pass the LSB of ACK counter.
slave_o.ack <= ack_sreg(0);
end syn;
-- -*- Mode: LUA; tab-width: 2 -*-
peripheral {
name = "Clock Frequency Monitor";
hdl_entity = "clock_monitor_wb";
prefix = "cm";
reg {
name = "Control Register";
prefix = "CR";
field {
name = "Reset counters";
description = "write 1: resets the counters\
write 0: no effect";
prefix = "CNT_RST";
type = MONOSTABLE;
};
field {
name = "Prescaler";
prefix = "PRESC";
type = SLV;
size = 8;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
field {
name = "Reference Select";
prefix = "REFSEL"; -- 0..n-1: channel n, 14:ext PPS, 15:system clock
type = SLV;
size = 4;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
};
reg {
name = "Reference Divider Register";
prefix = "REFDR";
field {
name = "Reference Division Ratio";
prefix = "REFDR";
type = SLV;
size = 32;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
};
reg {
name = "Counter Select Register";
prefix = "CNT_SEL";
field {
name = "Counter Select";
prefix = "SEL";
type = SLV;
size = 4;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
};
reg {
name = "Counter Value Register";
prefix = "CNT_VAL";
field {
name = "Counter Value";
prefix = "VALUE";
type = SLV;
size = 31;
access_bus = READ_ONLY;
access_dev = WRITE_ONLY;
};
field {
name = "Counter Value Valid/Clear";
prefix = "VALID";
type = BIT;
size = 1;
access_bus = READ_WRITE;
access_dev = READ_WRITE;
load = LOAD_EXT;
};
};
};
---------------------------------------------------------------------------------------
-- Title : Wishbone slave core for Clock Frequency Monitor
---------------------------------------------------------------------------------------
-- File : clock_monitor_wbgen2_pkg.vhd
-- Author : auto-generated by wbgen2 from clock_monitor_wb.wb
-- Created : Mon Jun 17 18:28:42 2019
-- Standard : VHDL'87
---------------------------------------------------------------------------------------
-- THIS FILE WAS GENERATED BY wbgen2 FROM SOURCE FILE clock_monitor_wb.wb
-- DO NOT HAND-EDIT UNLESS IT'S ABSOLUTELY NECESSARY!
---------------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.wishbone_pkg.all;
package cm_wbgen2_pkg is
-- Input registers (user design -> WB slave)
type t_cm_in_registers is record
cnt_val_value_i : std_logic_vector(30 downto 0);
cnt_val_valid_i : std_logic;
end record;
constant c_cm_in_registers_init_value: t_cm_in_registers := (
cnt_val_value_i => (others => '0'),
cnt_val_valid_i => '0'
);
-- Output registers (WB slave -> user design)
type t_cm_out_registers is record
cr_cnt_rst_o : std_logic;
cr_presc_o : std_logic_vector(7 downto 0);
cr_refsel_o : std_logic_vector(3 downto 0);
refdr_refdr_o : std_logic_vector(31 downto 0);
cnt_sel_sel_o : std_logic_vector(3 downto 0);
cnt_val_valid_o : std_logic;
cnt_val_valid_load_o : std_logic;
end record;
constant c_cm_out_registers_init_value: t_cm_out_registers := (
cr_cnt_rst_o => '0',
cr_presc_o => (others => '0'),
cr_refsel_o => (others => '0'),
refdr_refdr_o => (others => '0'),
cnt_sel_sel_o => (others => '0'),
cnt_val_valid_o => '0',
cnt_val_valid_load_o => '0'
);
function "or" (left, right: t_cm_in_registers) return t_cm_in_registers;
function f_x_to_zero (x:std_logic) return std_logic;
function f_x_to_zero (x:std_logic_vector) return std_logic_vector;
component clock_monitor_wb is
port (
rst_n_i : in std_logic;
clk_sys_i : in std_logic;
slave_i : in t_wishbone_slave_in;
slave_o : out t_wishbone_slave_out;
int_o : out std_logic;
regs_i : in t_cm_in_registers;
regs_o : out t_cm_out_registers
);
end component;
end package;
package body cm_wbgen2_pkg is
function f_x_to_zero (x:std_logic) return std_logic is
begin
if x = '1' then
return '1';
else
return '0';
end if;
end function;
function f_x_to_zero (x:std_logic_vector) return std_logic_vector is
variable tmp: std_logic_vector(x'length-1 downto 0);
begin
for i in 0 to x'length-1 loop
if(x(i) = 'X' or x(i) = 'U') then
tmp(i):= '0';
else
tmp(i):=x(i);
end if;
end loop;
return tmp;
end function;
function "or" (left, right: t_cm_in_registers) return t_cm_in_registers is
variable tmp: t_cm_in_registers;
begin
tmp.cnt_val_value_i := f_x_to_zero(left.cnt_val_value_i) or f_x_to_zero(right.cnt_val_value_i);
tmp.cnt_val_valid_i := f_x_to_zero(left.cnt_val_valid_i) or f_x_to_zero(right.cnt_val_valid_i);
return tmp;
end function;
end package body;
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.gencores_pkg.all;
use work.wishbone_pkg.all;
use work.cm_wbgen2_pkg.all;
entity xwb_clock_monitor is
generic (
g_NUM_CLOCKS : integer := 1;
g_CLK_SYS_FREQ : integer := 62500000;
g_WITH_INTERNAL_TIMEBASE : boolean := TRUE
);
port (
rst_n_i : in std_logic;
clk_sys_i : in std_logic;
clk_in_i : in std_logic_vector(g_num_clocks-1 downto 0);
pps_p1_i : in std_logic := '0';
slave_i : in t_wishbone_slave_in;
slave_o : out t_wishbone_slave_out
);
end xwb_clock_monitor;
architecture rtl of xwb_clock_monitor is
signal regs_in : t_cm_in_registers;
signal regs_out : t_cm_out_registers;
type t_clock_state is record
presc_cnt : unsigned(4 downto 0);
clk_in : std_logic;
clk_presc : std_logic;
pulse : std_logic;
counter : unsigned(30 downto 0);
valid_sreg : std_logic_vector(1 downto 0);
freq : unsigned(30 downto 0);
ack : std_logic;
end record;
type t_clock_state_array is array (integer range <>) of t_clock_state;
signal clks : t_clock_state_array(0 to g_num_clocks);
signal rst_n_a : std_logic;
signal ref_pulse_p : std_logic;
signal gate_p : std_logic;
signal gate_cnt : unsigned(31 downto 0);
signal pps_p_sysclk : std_logic;
signal cntr_gate : unsigned(30 downto 0) := (others => '0');
signal gate_pulse, gate_pulse_synced : std_logic := '0';
begin
gen_ext_pps : if g_WITH_INTERNAL_TIMEBASE = false generate
U_PPS_Pulse_Detect : gc_sync_ffs
generic map (
g_sync_edge => "positive")
port map (
clk_i => clk_sys_i,
rst_n_i => rst_n_i,
data_i => pps_p1_i,
ppulse_o => pps_p_sysclk);
end generate gen_ext_pps;
gen_int_pps : if g_WITH_INTERNAL_TIMEBASE = true generate
p_gate_counter : process(clk_sys_i)
begin
if rising_edge(clk_sys_i) then
if rst_n_i = '0' then
cntr_gate <= (others => '0');
pps_p_sysclk <= '0';
else
if cntr_gate = g_CLK_SYS_FREQ-1 then
cntr_gate <= (others => '0');
pps_p_sysclk <= '1';
else
cntr_gate <= cntr_gate + 1;
pps_p_sysclk <= '0';
end if;
end if;
end if;
end process;
end generate gen_int_pps;
process(clk_sys_i)
begin
if rising_edge(clk_sys_i) then
if rst_n_i = '0' or regs_out.cr_cnt_rst_o = '1' then
gate_cnt <= (others => '0');
gate_p <= '0';
else
ref_pulse_p <= clks(to_integer(unsigned(regs_out.cr_refsel_o))).pulse;
if unsigned(regs_out.cr_refsel_o) /= 15 then
if ref_pulse_p = '1' then
if gate_cnt = unsigned(regs_out.refdr_refdr_o) then
gate_cnt <= (others => '0');
gate_p <= '1';
else
gate_cnt <= gate_cnt + 1;
gate_p <= '0';
end if;
else
gate_p <= '0';
end if;
else
gate_p <= pps_p_sysclk;
end if;
end if;
end if;
end process;
rst_n_a <= rst_n_i;
U_WB_Slave : entity work.clock_monitor_wb
port map (
rst_n_i => rst_n_i,
clk_sys_i => clk_sys_i,
slave_i => slave_i,
slave_o => slave_o,
regs_i => regs_in,
regs_o => regs_out);
clks(g_num_clocks).clk_in <= clk_sys_i;
gen1 : for i in 0 to g_num_clocks-1 generate
clks(i).clk_in <= clk_in_i(i);
end generate gen1;
gen2 : for i in 0 to g_num_clocks generate
p_clk_prescaler : process(clks(i).clk_in, rst_n_a)
begin
if rst_n_a = '0' then
clks(i).presc_cnt <= (others => '0');
clks(i).clk_presc <= '0';
elsif rising_edge(clks(i).clk_in) then
if(clks(i).presc_cnt = unsigned(regs_out.cr_presc_o)) then
clks(i).presc_cnt <= (others => '0');
clks(i).clk_presc <= not clks(i).clk_presc;
else
clks(i).presc_cnt <= clks(i).presc_cnt + 1;
end if;
end if;
end process;
U_Edge_Detect : gc_sync_ffs
generic map (
g_sync_edge => "positive")
port map (
clk_i => clk_sys_i,
rst_n_i => rst_n_i,
data_i => clks(i).clk_presc,
ppulse_o => clks(i).pulse);
end generate gen2;
gen3 : for i in 0 to g_num_clocks generate
p_counter : process(clk_sys_i)
variable cnt_idx : integer range 0 to g_num_clocks;
begin
if rising_edge(clk_sys_i) then
if rst_n_i = '0' or regs_out.cr_cnt_rst_o = '1' then
clks(i).counter <= (others => '0');
clks(i).valid_sreg <= (others => '0');
else
if(gate_p = '1') then
clks(i).valid_sreg <= clks(i).valid_sreg(0) & '1';
clks(i).freq <= clks(i).counter;
clks(i).counter <= (others => '0');
elsif clks(i).pulse = '1' then
clks(i).counter <= clks(i).counter + 1;
end if;
if clks(i).ack = '1' then
clks(i).valid_sreg(1) <= '0';
end if;
cnt_idx := to_integer(unsigned(regs_out.cnt_sel_sel_o));
if (i = cnt_idx) then
clks(i).ack <= regs_out.cnt_val_valid_o and regs_out.cnt_val_valid_load_o;
else
clks(i).ack <= '0';
end if;
end if;
end if;
end process;
end generate gen3;
p_regs : process(clk_sys_i)
variable cnt_idx : integer range 0 to g_num_clocks;
begin
if rising_edge(clk_sys_i) then
if rst_n_i = '0' then
regs_in.cnt_val_valid_i <= '0';
else
cnt_idx := to_integer(unsigned(regs_out.cnt_sel_sel_o));
regs_in.cnt_val_value_i <= std_logic_vector(clks(cnt_idx).freq);
regs_in.cnt_val_valid_i <= clks(cnt_idx).valid_sreg(1);
end if;
end if;
end process;
end rtl;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment