------------------------------------------------------------------------------- -- JulianTimeDate.vhd -- Sydney Tang -- created: 1998 October 16 -- -- Time/Date-tracking entity -- -- Gregorian -- 331 logic cells, 57.7ns, 17.33MHz, when counters do increment bounds check? -- 374 logic cells, 50.7ns, 19.72MHz, when counters do bounds check on load -- -- Julian -- 328 (28%) 51.8ns, 17.21MHz (8.1, bounds check on load) -- 258 (22%) 42.1ns, 23.20MHz (8.1, no bounds check on BCD and bin counters) -- 258 (22%) 47.1ns, 21.23MHz (7.21, no bounds check on BCD and bin counters) -- -- This entity keeps track of time from seconds up to years. Its outputs are -- a number of std_logic_vectors corresponding to the year, month, day, hour, -- minute, and second. The hour is given in the 24-hour clock. -- -- All time fields are in BCD. -- -- The time/date output is incremented by 1 second whenever the count_enable -- input is high on a rising clock edge. Note that in the worst case, making a -- transition to a new year, it takes 6 clock cycles for the output to be -- completely updated. As time progresses, each of the time and date fields is -- updated appropriately, with leap years taken into consideration. -- -- On reset, the output is intitialized to midnight on January 1 in the year -- 1 A.D. It can go all they way up to 9999 A.D. -- -- To explicitly set the time to a certain value, set the new_year, new_month, -- etc. inputs to whatever time you wish to time-travel to, then hold the -- load_enable input high on a rising clock edge. The system time will then be -- set as specified, and it will be ready to start counting from there. -- -- big version: -- Any invalid input field will be reset to the minimum value for that field. -- (eg. hour = 25 will get reset to 00). -- -- compact version: -- The system is not designed to handle invalid times (eg. year = 16383, -- month = 15, hour = 25, minute = 61, second = 62). If supplied with one or -- more invalid values, it will just keep on counting until the bad field -- returns to a valid range. ------------------------------------------------------------------------------- library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.std_logic_unsigned.all; library lpm; use lpm.lpm_components.lpm_mult; library work; use work.Time_Package.all; -- include a bunch of constants use work.Counter_Package.all; -- include a useful counter use work.BCD_Package.all; entity JulianTimeDate is port( clock: in std_logic; reset: in std_logic; year: out std_logic_vector(YEAR_WIDTH-1 downto 0); month: out std_logic_vector(MONTH_WIDTH-1 downto 0); day: out std_logic_vector(DAY_WIDTH-1 downto 0); hour: out std_logic_vector(HOUR_WIDTH-1 downto 0); minute: out std_logic_vector(MINUTE_WIDTH-1 downto 0); second: out std_logic_vector(SECOND_WIDTH-1 downto 0); weekday: out std_logic_vector(WEEKDAY_WIDTH-1 downto 0); new_year: in std_logic_vector(YEAR_WIDTH-1 downto 0); new_month: in std_logic_vector(MONTH_WIDTH-1 downto 0); new_day: in std_logic_vector(DAY_WIDTH-1 downto 0); new_hour: in std_logic_vector(HOUR_WIDTH-1 downto 0); new_minute: in std_logic_vector(MINUTE_WIDTH-1 downto 0); new_second: in std_logic_vector(SECOND_WIDTH-1 downto 0); new_weekday: in std_logic_vector(WEEKDAY_WIDTH-1 downto 0); count_enable: in std_logic; load_enable: in std_logic ); end JulianTimeDate; ------------------------------------------------------------------------------- architecture Julian_Time_Date of JulianTimeDate is ---------------------------------------------------------- -- counter values signal BCDYearValue: std_logic_vector(YEAR_WIDTH-1 downto 0); signal BinaryDecadeYear: std_logic_vector(CENTURY_WIDTH-1 downto 0); signal MonthValue: std_logic_vector(MONTH_WIDTH-1 downto 0); ---------------------------------------------------------- -- counter overflow signals signal inc_year, inc_month, inc_day, inc_hour, inc_minute: std_logic; signal WeekdayOverflow: std_logic; signal YearOverflow1, YearOverFlow0: std_logic; signal BinaryYearOverflow1, BinaryYearOverflow0: std_logic; ---------------------------------------------------------- -- max and min signals, acting as "parameters" to some counters signal Min_Year: std_logic_vector(YEAR_WIDTH-1 downto 0); signal Min_Month: std_logic_vector(MONTH_WIDTH-1 downto 0); signal Min_Day: std_logic_vector(DAY_WIDTH-1 downto 0); signal Min_Hour: std_logic_vector(HOUR_WIDTH-1 downto 0); signal Min_Minute_Second: std_logic_vector(MINUTE_WIDTH-1 downto 0); signal Min_Weekday: std_logic_vector(WEEKDAY_WIDTH-1 downto 0); signal Max_Year: std_logic_vector(YEAR_WIDTH-1 downto 0); signal Max_Month: std_logic_vector(MONTH_WIDTH-1 downto 0); signal Max_Day: std_logic_vector(DAY_WIDTH-1 downto 0); signal Max_Hour: std_logic_vector(HOUR_WIDTH-1 downto 0); signal Max_Minute_Second: std_logic_vector(MINUTE_WIDTH-1 downto 0); signal Max_Weekday: std_logic_vector(WEEKDAY_WIDTH-1 downto 0); signal Min_Binary00to99: std_logic_vector(CENTURY_WIDTH-1 downto 0); signal Max_Binary00to99: std_logic_vector(CENTURY_WIDTH-1 downto 0); ---------------------------------------------------------- -- new_year BCD to binary conversion signals signal BinaryInputDecadeYear, BinaryInputMilleniumCentury: std_logic_vector(CENTURY_WIDTH-1 downto 0); signal BinaryInputDecade, BinaryInputMillenium: std_logic_vector(CENTURY_WIDTH-1 downto 0); signal BinaryInputDecadeProduct, BinaryInputMilleniumProduct: std_logic_vector(2*BCD_WIDTH-1 downto 0); signal Ten_Factor: std_logic_vector(BCD_WIDTH-1 downto 0); begin ---------------------------------------------------------- -- wire the max and min values Min_Year <= MININUM_YEAR; Min_Month <= MININUM_MONTH; Min_Day <= MININUM_DAY; Min_Hour <= MININUM_HOUR; Min_Minute_Second <= MININUM_MINUTE_SECOND; Min_Weekday <= MINIMUM_WEEKDAY; Max_Year <= MAXIMUM_YEAR; -- 9999 Max_Month <= MAXIMUM_MONTH; -- 12 --Max_Day <= --must be selected dynamically Max_Hour <= MAXIMUM_HOUR; -- 12 Max_Minute_Second <= MAXIMUM_MINUTE_SECOND; -- 59 Max_Weekday <= MAXIMUM_WEEKDAY; -- 7 Min_Binary00to99 <= (others => '0'); -- 00 Max_Binary00to99 <= NINETY_NINE; -- 99 ---------------------------------------------------------- -- Instantiate counters for each of the time/date fields -- and do some other necessary wiring. MilleniumCenturyCounter: BCDtwoDigitCounter port map( clock => clock, reset => reset, overflow => YearOverflow1, count_enable => YearOverflow0, load_enable => load_enable, input_count => new_year(4*BCD_WIDTH-1 downto 2*BCD_WIDTH), Min_Count => Min_Year(4*BCD_WIDTH-1 downto 2*BCD_WIDTH), Max_Count => Max_Year(4*BCD_WIDTH-1 downto 2*BCD_WIDTH), count => BCDYearValue(4*BCD_WIDTH-1 downto 2*BCD_WIDTH) -- not wired directly to year; -- need it for MaximumDaySelector as well. ); DecadeYearCounter: BCDtwoDigitCounter port map( clock => clock, reset => reset, overflow => YearOverflow0, count_enable => inc_year, load_enable => load_enable, input_count => new_year(2*BCD_WIDTH-1 downto 0), Min_Count => Min_Year(2*BCD_WIDTH-1 downto 0), Max_Count => Max_Year(2*BCD_WIDTH-1 downto 0), count => BCDYearValue(2*BCD_WIDTH-1 downto 0) -- not wired directly to year; -- need it for MaximumDaySelector as well. ); year <= BCDYearValue; DecadeYearBinaryCounter: counter generic map( COUNTER_WIDTH => CENTURY_WIDTH ) port map( clock => clock, reset => reset, overflow => BinaryYearOverflow0, count_enable => inc_year, load_enable => load_enable, input_count => BinaryInputDecadeYear, Min_Count => Min_Binary00to99, Max_Count => Max_Binary00to99, count => BinaryDecadeYear ); -- This component dynamically selects a value for Max_Day according to -- the month and year. Why oh why couldn't all the months have the same -- number of days? MaximumDaySelector: JulianMaxDaySelector port map( Month => MonthValue(BCD_WIDTH downto 0), Year2LSB => BinaryDecadeYear(1 downto 0), MaxDay => Max_Day ); MonthCounter: BCDtwoDigitCounter port map( clock => clock, reset => reset, overflow => inc_year, count_enable => inc_month, load_enable => load_enable, input_count => new_month, Min_Count => Min_Month, Max_Count => Max_Month, count => MonthValue -- note: not wired directly to month ); month <= MonthValue; DayCounter: BCDtwoDigitCounter port map( clock => clock, reset => reset, overflow => inc_month, count_enable => inc_day, load_enable => load_enable, input_count => new_day, Min_Count => Min_Day, Max_Count => Max_Day, count => day ); HourCounter: BCDtwoDigitCounter port map( clock => clock, reset => reset, overflow => inc_day, count_enable => inc_hour, load_enable => load_enable, input_count => new_hour, Min_Count => Min_Hour, Max_Count => Max_Hour, count => hour ); MinuteCounter: BCDtwoDigitCounter port map( clock => clock, reset => reset, overflow => inc_hour, count_enable => inc_minute, load_enable => load_enable, input_count => new_minute, Min_Count => Min_Minute_Second, Max_Count => Max_Minute_Second, count => minute ); SecondCounter: BCDtwoDigitCounter port map( clock => clock, reset => reset, overflow => inc_minute, count_enable => count_enable, load_enable => load_enable, input_count => new_second, Min_Count => Min_Minute_Second, Max_Count => Max_Minute_Second, count => second ); weekDayCounter: counter generic map( COUNTER_WIDTH => WEEKDAY_WIDTH ) port map( clock => clock, reset => reset, overflow => WeekdayOverflow, count_enable => inc_day, load_enable => load_enable, input_count => new_weekday, Min_Count => Min_Weekday, Max_Count => Max_Weekday, count => weekday ); ---------------------------------------------------------- -- BCD to binary conversion on new_year to provide inputs to MaxDaySelector Ten_Factor <= TEN; BCDtoBinaryDecadeConverter: lpm_mult GENERIC map( LPM_WIDTHA => BCD_WIDTH, LPM_WIDTHB => BCD_WIDTH, LPM_WIDTHS => 1, LPM_WIDTHP => 2*BCD_WIDTH, LPM_REPRESENTATION => "UNSIGNED", --LPM_HINT => "INPUT_B_IS_CONSTANT", LPM_PIPELINE => 0 ) PORT map( dataa => new_year(2*BCD_WIDTH-1 downto BCD_WIDTH), datab => Ten_Factor, result => BinaryInputDecadeProduct ); BinaryInputDecade <= BinaryInputDecadeProduct(CENTURY_WIDTH-1 downto 0); BinaryInputDecadeYear <= BinaryInputDecade + new_year(BCD_WIDTH-1 downto 0); end Julian_Time_Date;