URL
https://opencores.org/ocsvn/open8_urisc/open8_urisc/trunk
Subversion Repositories open8_urisc
Compare Revisions
- This comparison shows the changes necessary to convert path
/open8_urisc/trunk
- from Rev 167 to Rev 168
- ↔ Reverse comparison
Rev 167 → Rev 168
/VHDL/Open8.vhd
324,7 → 324,8
type SP_MODES is ( SP_IDLE, SP_RSET, SP_POP, SP_PUSH ); |
|
type DP_MODES is ( DATA_BUS_IDLE, DATA_RD_MEM, |
DATA_WR_REG, DATA_WR_FLAG, DATA_WR_PC ); |
DATA_WR_REG, DATA_WR_FLAG, |
DATA_WR_PC_LOWER, DATA_WR_PC_UPPER ); |
|
type DP_CTRL_TYPE is record |
Src : DP_MODES; |
418,7 → 419,6
IC := CACHE_IDLE; |
SP := SP_IDLE; |
DP.Src := DATA_RD_MEM; |
DP.Reg := ACCUM; |
Ack_D := '0'; |
INT.Mask_Set := '0'; |
INT.Soft_Ints := x"00"; |
532,8 → 532,7
when SOP_JSR => |
IC := CACHE_OPER1; |
PC := PC_IDLE; |
DP.Src := DATA_WR_PC; |
DP.Reg := ACCUM+1; |
DP.Src := DATA_WR_PC_UPPER; |
CPU.State <= JSR_C1; |
|
when others => null; |
858,8 → 857,7
IC := CACHE_OPER1; |
PC := PC_IDLE; |
SP := SP_PUSH; |
DP.Src := DATA_WR_PC; |
DP.Reg := ACCUM+1; |
DP.Src := DATA_WR_PC_UPPER; |
Ack_D := '1'; |
CPU.A_Oper <= ALU_STP; |
CPU.A_Reg <= INT_FLAG; |
869,8 → 867,7
IC := CACHE_OPER2; |
PC := PC_IDLE; |
SP := SP_PUSH; |
DP.Src := DATA_WR_PC; |
DP.Reg := ACCUM; |
DP.Src := DATA_WR_PC_LOWER; |
CPU.State <= JSR_C2; |
|
when JSR_C2 => |
1256,12 → 1253,13
Wr_Enable <= '1'; |
Wr_Data <= Flags; |
|
when DATA_WR_PC => |
when DATA_WR_PC_LOWER => |
Wr_Enable <= '1'; |
Wr_Data <= CPU.Program_Ctr(7 downto 0); |
|
when DATA_WR_PC_UPPER => |
Wr_Enable <= '1'; |
Wr_Data <= CPU.Program_Ctr(15 downto 8); |
if( DP.Reg = ACCUM )then |
Wr_Data <= CPU.Program_Ctr(7 downto 0); |
end if; |
|
when others => |
null; |
/VHDL/o8_rtc.vhd
1,348 → 1,405
-- Copyright (c)2013 Jeremy Seth Henry |
-- All rights reserved. |
-- |
-- Redistribution and use in source and binary forms, with or without |
-- modification, are permitted provided that the following conditions are met: |
-- * Redistributions of source code must retain the above copyright |
-- notice, this list of conditions and the following disclaimer. |
-- * Redistributions in binary form must reproduce the above copyright |
-- notice, this list of conditions and the following disclaimer in the |
-- documentation and/or other materials provided with the distribution, |
-- where applicable (as part of a user interface, debugging port, etc.) |
-- |
-- THIS SOFTWARE IS PROVIDED BY JEREMY SETH HENRY ``AS IS'' AND ANY |
-- EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
-- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
-- DISCLAIMED. IN NO EVENT SHALL JEREMY SETH HENRY BE LIABLE FOR ANY |
-- DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
-- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
-- LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
-- ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
-- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
-- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
-- |
-- VHDL Units : realtime_clock |
-- Description: Provides automatically updated registers that maintain the |
-- : time of day. Keeps track of the day of week, hours, minutes |
-- : seconds, and tenths of a second. Module is doubled buffered |
-- : to ensure time consistency during accesses. Also provides |
-- : a programmable periodic interrupt timer, as well as a uSec |
-- : tick for external use. |
-- |
-- Register Map: |
-- Offset Bitfield Description Read/Write |
-- 0x0 AAAAAAAA Periodic Interval Timer in uS (RW) |
-- 0x1 -AAAAAAA Tenths (0x00 - 0x63) (RW) |
-- 0x2 --AAAAAA Seconds (0x00 - 0x3B) (RW) |
-- 0x3 --AAAAAA Minutes (0x00 - 0x3B) (RW) |
-- 0x4 ---AAAAA Hours (0x00 - 0x17) (RW) |
-- 0x5 -----AAA Day of Week (0x00 - 0x06) (RW) |
-- 0x6 -------- Update RTC regs from Shadow Regs (WO) |
-- 0x7 A------- Update Shadow Regs from RTC regs (RW) |
-- A = Update is Busy |
|
library ieee; |
use ieee.std_logic_1164.all; |
use ieee.std_logic_unsigned.all; |
use ieee.std_logic_arith.all; |
use ieee.std_logic_misc.all; |
|
library work; |
use work.open8_pkg.all; |
|
entity o8_rtc is |
generic( |
Sys_Freq : real; |
Reset_Level : std_logic; |
Address : ADDRESS_TYPE |
); |
port( |
Clock : in std_logic; |
Reset : in std_logic; |
uSec_Tick : out std_logic; |
-- |
Bus_Address : in ADDRESS_TYPE; |
Wr_Enable : in std_logic; |
Wr_Data : in DATA_TYPE; |
Rd_Enable : in std_logic; |
Rd_Data : out DATA_TYPE; |
-- |
Interrupt_PIT : out std_logic; |
Interrupt_RTC : out std_logic |
); |
end entity; |
|
architecture behave of o8_rtc is |
|
-- The ceil_log2 function returns the minimum register width required to |
-- hold the supplied integer. |
function ceil_log2 (x : in natural) return natural is |
variable retval : natural; |
begin |
retval := 1; |
while ((2**retval) - 1) < x loop |
retval := retval + 1; |
end loop; |
return retval; |
end ceil_log2; |
|
constant User_Addr : std_logic_vector(15 downto 3) |
:= Address(15 downto 3); |
alias Comp_Addr is Bus_Address(15 downto 3); |
signal Addr_Match : std_logic; |
|
alias Reg_Addr is Bus_Address(2 downto 0); |
signal Reg_Addr_q : std_logic_vector(2 downto 0); |
|
signal Wr_En : std_logic; |
signal Wr_Data_q : DATA_TYPE; |
signal Rd_En : std_logic; |
|
constant DLY_1USEC_VAL: integer := integer(Sys_Freq / 1000000.0); |
constant DLY_1USEC_WDT: integer := ceil_log2(DLY_1USEC_VAL - 1); |
constant DLY_1USEC : std_logic_vector := |
conv_std_logic_vector( DLY_1USEC_VAL - 1, DLY_1USEC_WDT); |
|
signal uSec_Cntr : std_logic_vector( DLY_1USEC_WDT - 1 downto 0 ) |
:= (others => '0'); |
signal uSec_Tick_i : std_logic; |
|
signal interval : DATA_TYPE; |
signal timer_cnt : DATA_TYPE; |
signal timer_ro : std_logic; |
|
signal rtc_frac : std_logic_vector(15 downto 0); |
signal frac_ro : std_logic; |
|
signal rtc_tens : DATA_TYPE; |
signal tens_ro : std_logic; |
|
signal rtc_secs : DATA_TYPE; |
signal secs_ro : std_logic; |
|
signal rtc_mins : DATA_TYPE; |
signal mins_ro : std_logic; |
|
signal rtc_hours : DATA_TYPE; |
signal hours_ro : std_logic; |
|
signal rtc_dow : DATA_TYPE; |
|
signal shd_tens : DATA_TYPE; |
signal shd_secs : DATA_TYPE; |
signal shd_mins : DATA_TYPE; |
signal shd_hours : DATA_TYPE; |
signal shd_dow : DATA_TYPE; |
|
signal update_rtc : std_logic; |
signal update_shd : std_logic; |
signal update_ctmr : std_logic_vector(3 downto 0); |
|
begin |
|
uSec_Tick <= uSec_Tick_i; |
Addr_Match <= '1' when Comp_Addr = User_Addr else '0'; |
|
Interrupt_PIT <= timer_ro; |
Interrupt_RTC <= frac_ro; |
|
io_reg: process( Clock, Reset ) |
begin |
if( Reset = Reset_Level )then |
uSec_Cntr <= (others => '0'); |
uSec_Tick_i <= '0'; |
|
interval <= x"00"; |
timer_cnt <= x"00"; |
timer_ro <= '0'; |
|
rtc_frac <= (others => '0'); |
frac_ro <= '0'; |
|
rtc_tens <= (others => '0'); |
tens_ro <= '0'; |
|
rtc_secs <= (others => '0'); |
secs_ro <= '0'; |
|
rtc_mins <= (others => '0'); |
mins_ro <= '0'; |
|
rtc_hours <= (others => '0'); |
hours_ro <= '0'; |
|
rtc_dow <= (others => '0'); |
|
shd_tens <= (others => '0'); |
shd_secs <= (others => '0'); |
shd_mins <= (others => '0'); |
shd_hours <= (others => '0'); |
shd_dow <= (others => '0'); |
|
update_rtc <= '0'; |
update_shd <= '0'; |
update_ctmr <= (others => '0'); |
|
Wr_Data_q <= (others => '0'); |
Reg_Addr_q <= (others => '0'); |
Wr_En <= '0'; |
Rd_En <= '0'; |
Rd_Data <= x"00"; |
|
elsif( rising_edge( Clock ) )then |
|
uSec_Cntr <= uSec_Cntr - 1; |
uSec_Tick_i <= '0'; |
if( uSec_Cntr = 0 )then |
uSec_Cntr <= DLY_1USEC; |
uSec_Tick_i <= or_reduce(Interval); |
end if; |
|
timer_ro <= '0'; |
frac_ro <= '0'; |
tens_ro <= '0'; |
secs_ro <= '0'; |
mins_ro <= '0'; |
hours_ro <= '0'; |
|
-- Periodic Interval Timer |
timer_cnt <= timer_cnt - uSec_Tick_i; |
if( or_reduce(timer_cnt) = '0' )then |
timer_cnt <= interval; |
timer_ro <= or_reduce(interval); -- Only issue output on Int > 0 |
end if; |
|
-- Fractional decisecond counter - cycles every 10k microseconds |
rtc_frac <= rtc_frac - uSec_Tick_i; |
if( or_reduce(rtc_frac) = '0' or update_rtc = '1' )then |
rtc_frac <= x"2710"; |
frac_ro <= not update_rtc; |
end if; |
|
-- Decisecond counter |
rtc_tens <= rtc_tens + frac_ro; |
if( update_rtc = '1' )then |
rtc_tens <= shd_tens; |
elsif( rtc_tens = x"64")then |
rtc_tens <= (others => '0'); |
tens_ro <= '1'; |
end if; |
|
-- Second counter |
rtc_secs <= rtc_secs + tens_ro; |
if( update_rtc = '1' )then |
rtc_secs <= shd_secs; |
elsif( rtc_secs = x"3C")then |
rtc_secs <= (others => '0'); |
secs_ro <= '1'; |
end if; |
|
-- Minute counter |
rtc_mins <= rtc_mins + secs_ro; |
if( update_rtc = '1' )then |
rtc_mins <= shd_mins; |
elsif( rtc_mins = x"3C")then |
rtc_mins <= (others => '0'); |
mins_ro <= '1'; |
end if; |
|
-- Hour counter |
rtc_hours <= rtc_hours + mins_ro; |
if( update_rtc = '1' )then |
rtc_hours <= shd_hours; |
elsif( rtc_hours = x"18")then |
rtc_hours <= (others => '0'); |
hours_ro <= '1'; |
end if; |
|
-- Day of Week counter |
rtc_dow <= rtc_dow + hours_ro; |
if( update_rtc = '1' )then |
rtc_dow <= shd_dow; |
elsif( rtc_dow = x"07")then |
rtc_dow <= (others => '0'); |
end if; |
|
-- Coherency timer - ensures that the shadow registers are updated with |
-- valid time data by delaying updates until the rtc registers have |
-- finished cascading. |
update_rtc <= '0'; |
update_ctmr <= update_ctmr - or_reduce(update_ctmr); |
if( frac_ro = '1' )then |
update_ctmr <= x"9"; |
end if; |
|
-- Copy the RTC registers to the shadow registers when the coherency |
-- timer is zero (RTC registers are static) |
if( update_shd = '1' and or_reduce(update_ctmr) = '0' )then |
shd_tens <= rtc_tens; |
shd_secs <= rtc_secs; |
shd_mins <= rtc_mins; |
shd_hours <= rtc_hours; |
shd_dow <= rtc_dow; |
update_shd <= '0'; |
end if; |
|
Reg_Addr_q <= Reg_Addr; |
Wr_Data_q <= Wr_Data; |
|
Wr_En <= Addr_Match and Wr_Enable; |
if( Wr_En = '1' )then |
case( Reg_Addr_q )is |
when "000" => |
interval <= Wr_Data_q; |
|
when "001" => |
shd_tens <= '0' & Wr_Data_q(6 downto 0); |
|
when "010" => |
shd_secs <= "00" & Wr_Data_q(5 downto 0); |
|
when "011" => |
shd_mins <= "00" & Wr_Data_q(5 downto 0); |
|
when "100" => |
shd_hours <= "000" & Wr_Data_q(4 downto 0); |
|
when "101" => |
shd_dow <= "00000" & Wr_Data_q(2 downto 0); |
|
when "110" => |
update_rtc <= '1'; |
|
when "111" => |
|
update_shd <= '1'; |
|
when others => null; |
end case; |
end if; |
|
Rd_Data <= (others => '0'); |
Rd_En <= Addr_Match and Rd_Enable; |
if( Rd_En = '1' )then |
case( Reg_Addr_q )is |
when "000" => |
Rd_Data <= interval; |
when "001" => |
Rd_Data <= shd_tens; |
when "010" => |
Rd_Data <= shd_secs; |
when "011" => |
Rd_Data <= shd_mins; |
when "100" => |
Rd_Data <= shd_hours; |
when "101" => |
Rd_Data <= shd_dow; |
when "110" => |
null; |
when "111" => |
Rd_Data <= update_shd & "0000000"; |
when others => null; |
end case; |
end if; |
|
end if; |
end process; |
|
end architecture; |
-- VHDL Units : realtime_clock |
-- Description: Provides automatically updated registers that maintain the |
-- : time of day. Keeps track of the day of week, hours, minutes |
-- : seconds, and tenths of a second. Module is doubled buffered |
-- : to ensure time consistency during accesses. Also provides |
-- : a programmable periodic interrupt timer, as well as a uSec |
-- : tick for external use. |
-- |
-- Register Map: |
-- Offset Bitfield Description Read/Write |
-- 0x0 AAAAAAAA Periodic Interval Timer in uS (RW) |
-- 0x1 -AAAAAAA Tenths (0x00 - 0x63) (RW) |
-- 0x2 --AAAAAA Seconds (0x00 - 0x3B) (RW) |
-- 0x3 --AAAAAA Minutes (0x00 - 0x3B) (RW) |
-- 0x4 ---AAAAA Hours (0x00 - 0x17) (RW) |
-- 0x5 -----AAA Day of Week (0x00 - 0x06) (RW) |
-- 0x6 -------- Update RTC regs from Shadow Regs (WO) |
-- 0x7 A------- Update Shadow Regs from RTC regs (RW) |
-- A = Update is Busy |
|
library ieee; |
use ieee.std_logic_1164.all; |
use ieee.std_logic_unsigned.all; |
use ieee.std_logic_arith.all; |
use ieee.std_logic_misc.all; |
|
library work; |
use work.open8_pkg.all; |
|
entity o8_rtc is |
generic( |
Sys_Freq : real; |
Reset_Level : std_logic; |
Address : ADDRESS_TYPE |
); |
port( |
Clock : in std_logic; |
Reset : in std_logic; |
uSec_Tick : out std_logic; |
-- |
Bus_Address : in ADDRESS_TYPE; |
Wr_Enable : in std_logic; |
Wr_Data : in DATA_TYPE; |
Rd_Enable : in std_logic; |
Rd_Data : out DATA_TYPE; |
-- |
Interrupt_PIT : out std_logic; |
Interrupt_RTC : out std_logic |
); |
end entity; |
|
architecture behave of o8_rtc is |
|
-- The ceil_log2 function returns the minimum register width required to |
-- hold the supplied integer. |
function ceil_log2 (x : in natural) return natural is |
variable retval : natural; |
begin |
retval := 1; |
while ((2**retval) - 1) < x loop |
retval := retval + 1; |
end loop; |
return retval; |
end ceil_log2; |
|
constant User_Addr : std_logic_vector(15 downto 3) |
:= Address(15 downto 3); |
alias Comp_Addr is Bus_Address(15 downto 3); |
signal Addr_Match : std_logic; |
|
alias Reg_Addr is Bus_Address(2 downto 0); |
signal Reg_Addr_q : std_logic_vector(2 downto 0); |
|
signal Wr_En : std_logic; |
signal Wr_Data_q : DATA_TYPE; |
signal Rd_En : std_logic; |
|
constant DLY_1USEC_VAL: integer := integer(Sys_Freq / 1000000.0); |
constant DLY_1USEC_WDT: integer := ceil_log2(DLY_1USEC_VAL - 1); |
constant DLY_1USEC : std_logic_vector := |
conv_std_logic_vector( DLY_1USEC_VAL - 1, DLY_1USEC_WDT); |
|
signal uSec_Cntr : std_logic_vector( DLY_1USEC_WDT - 1 downto 0 ) |
:= (others => '0'); |
signal uSec_Tick_i : std_logic; |
|
type PIT_TYPE is record |
timer_cnt : DATA_TYPE; |
timer_ro : std_logic; |
end record; |
|
signal pit : PIT_TYPE; |
|
type RTC_TYPE is record |
frac : std_logic_vector(15 downto 0); |
frac_ro : std_logic; |
|
tens_l : std_logic_vector(3 downto 0); |
tens_l_ro : std_logic; |
|
tens_u : std_logic_vector(3 downto 0); |
tens_u_ro : std_logic; |
|
secs_l : std_logic_vector(3 downto 0); |
secs_l_ro : std_logic; |
|
secs_u : std_logic_vector(3 downto 0); |
secs_u_ro : std_logic; |
|
mins_l : std_logic_vector(3 downto 0); |
mins_l_ro : std_logic; |
|
mins_u : std_logic_vector(3 downto 0); |
mins_u_ro : std_logic; |
|
hours_l : std_logic_vector(3 downto 0); |
hours_l_ro : std_logic; |
|
hours_u : std_logic_vector(3 downto 0); |
hours_u_ro : std_logic; |
|
dow : std_logic_vector(2 downto 0); |
end record; |
|
constant DECISEC : std_logic_vector(15 downto 0) := |
conv_std_logic_vector(10000,16); |
|
signal rtc : RTC_TYPE; |
|
signal interval : DATA_TYPE; |
|
signal shd_tens : DATA_TYPE; |
signal shd_secs : DATA_TYPE; |
signal shd_mins : DATA_TYPE; |
signal shd_hours : DATA_TYPE; |
signal shd_dow : DATA_TYPE; |
|
signal update_rtc : std_logic; |
signal update_shd : std_logic; |
signal update_ctmr : std_logic_vector(3 downto 0); |
|
begin |
|
uSec_Tick <= uSec_Tick_i; |
Addr_Match <= '1' when Comp_Addr = User_Addr else '0'; |
|
Interrupt_PIT <= pit.timer_ro; |
Interrupt_RTC <= rtc.frac_ro; |
|
io_reg: process( Clock, Reset ) |
begin |
if( Reset = Reset_Level )then |
uSec_Cntr <= (others => '0'); |
uSec_Tick_i <= '0'; |
|
pit.timer_cnt <= x"00"; |
pit.timer_ro <= '0'; |
|
rtc.frac <= DECISEC; |
rtc.frac_ro <= '0'; |
|
rtc.tens_l <= (others => '0'); |
rtc.tens_l_ro <= '0'; |
|
rtc.tens_u <= (others => '0'); |
rtc.tens_u_ro <= '0'; |
|
rtc.secs_l <= (others => '0'); |
rtc.secs_l_ro <= '0'; |
|
rtc.secs_u <= (others => '0'); |
rtc.secs_u_ro <= '0'; |
|
rtc.mins_l <= (others => '0'); |
rtc.mins_l_ro <= '0'; |
|
rtc.mins_u <= (others => '0'); |
rtc.mins_u_ro <= '0'; |
|
rtc.hours_l <= (others => '0'); |
rtc.hours_l_ro <= '0'; |
|
rtc.hours_u <= (others => '0'); |
rtc.hours_u_ro <= '0'; |
|
rtc.dow <= (others => '0'); |
|
shd_tens <= (others => '0'); |
shd_secs <= (others => '0'); |
shd_mins <= (others => '0'); |
shd_hours <= (others => '0'); |
shd_dow <= (others => '0'); |
|
update_rtc <= '0'; |
update_shd <= '0'; |
update_ctmr <= (others => '0'); |
|
interval <= x"00"; |
|
Wr_Data_q <= (others => '0'); |
Reg_Addr_q <= (others => '0'); |
Wr_En <= '0'; |
Rd_En <= '0'; |
Rd_Data <= x"00"; |
|
elsif( rising_edge( Clock ) )then |
|
uSec_Cntr <= uSec_Cntr - 1; |
uSec_Tick_i <= '0'; |
if( uSec_Cntr = 0 )then |
uSec_Cntr <= DLY_1USEC; |
uSec_Tick_i <= or_reduce(Interval); |
end if; |
|
pit.timer_ro <= '0'; |
|
rtc.frac_ro <= '0'; |
rtc.tens_l_ro <= '0'; |
rtc.tens_u_ro <= '0'; |
rtc.secs_l_ro <= '0'; |
rtc.secs_u_ro <= '0'; |
rtc.mins_l_ro <= '0'; |
rtc.mins_u_ro <= '0'; |
rtc.hours_l_ro <= '0'; |
rtc.hours_u_ro <= '0'; |
|
-- Periodic Interval Timer |
pit.timer_cnt <= pit.timer_cnt - uSec_Tick_i; |
if( or_reduce(pit.timer_cnt) = '0' )then |
pit.timer_cnt <= interval; |
pit.timer_ro <= or_reduce(interval); -- Only issue output on Int > 0 |
end if; |
|
-- Fractional decisecond counter - cycles every 10k microseconds |
rtc.frac <= rtc.frac - uSec_Tick_i; |
if( or_reduce(rtc.frac) = '0' or update_rtc = '1' )then |
rtc.frac <= DECISEC; |
rtc.frac_ro <= not update_rtc; |
end if; |
|
-- Decisecond counter (lower) |
rtc.tens_l <= rtc.tens_l + rtc.frac_ro; |
if( update_rtc = '1' )then |
rtc.tens_l <= shd_tens(3 downto 0); |
elsif( rtc.tens_l > x"9")then |
rtc.tens_l <= (others => '0'); |
rtc.tens_l_ro <= '1'; |
end if; |
|
-- Decisecond counter (upper) |
rtc.tens_u <= rtc.tens_u + rtc.tens_l_ro; |
if( update_rtc = '1' )then |
rtc.tens_u <= shd_tens(7 downto 4); |
elsif( rtc.tens_u > x"9")then |
rtc.tens_u <= (others => '0'); |
rtc.tens_u_ro <= '1'; |
end if; |
|
-- Second counter (lower) |
rtc.secs_l <= rtc.secs_l + rtc.tens_u_ro; |
if( update_rtc = '1' )then |
rtc.secs_l <= shd_secs(3 downto 0); |
elsif( rtc.secs_l > x"9")then |
rtc.secs_l <= (others => '0'); |
rtc.secs_l_ro <= '1'; |
end if; |
|
-- Second counter (upper) |
rtc.secs_u <= rtc.secs_u + rtc.secs_l_ro; |
if( update_rtc = '1' )then |
rtc.secs_u <= shd_secs(7 downto 4); |
elsif( rtc.secs_u > x"5")then |
rtc.secs_u <= (others => '0'); |
rtc.secs_u_ro <= '1'; |
end if; |
|
-- Minutes counter (lower) |
rtc.mins_l <= rtc.mins_l + rtc.secs_u_ro; |
if( update_rtc = '1' )then |
rtc.mins_l <= shd_mins(3 downto 0); |
elsif( rtc.mins_l > x"9")then |
rtc.mins_l <= (others => '0'); |
rtc.mins_l_ro <= '1'; |
end if; |
|
-- Minutes counter (upper) |
rtc.mins_u <= rtc.mins_u + rtc.mins_l_ro; |
if( update_rtc = '1' )then |
rtc.mins_u <= shd_mins(7 downto 4); |
elsif( rtc.mins_u > x"5")then |
rtc.mins_u <= (others => '0'); |
rtc.mins_u_ro <= '1'; |
end if; |
|
-- Hour counter (lower) |
rtc.hours_l <= rtc.hours_l + rtc.mins_u_ro; |
if( update_rtc = '1' )then |
rtc.hours_l <= shd_hours(3 downto 0); |
elsif( rtc.hours_l > x"9")then |
rtc.hours_l <= (others => '0'); |
rtc.hours_l_ro <= '1'; |
end if; |
|
-- Hour counter (upper) |
rtc.hours_u <= rtc.hours_u + rtc.hours_l_ro; |
if( update_rtc = '1' )then |
rtc.hours_u <= shd_hours(7 downto 4); |
end if; |
|
if( rtc.hours_u >= x"2" and rtc.hours_l > x"3" )then |
rtc.hours_l <= (others => '0'); |
rtc.hours_u <= (others => '0'); |
rtc.hours_u_ro <= '1'; |
end if; |
|
-- Day of Week counter |
rtc.dow <= rtc.dow + rtc.hours_u_ro; |
if( update_rtc = '1' )then |
rtc.dow <= shd_dow(2 downto 0); |
elsif( rtc.dow = x"07")then |
rtc.dow <= (others => '0'); |
end if; |
|
-- Copy the RTC registers to the shadow registers when the coherency |
-- timer is zero (RTC registers are static) |
if( update_shd = '1' and or_reduce(update_ctmr) = '0' )then |
shd_tens <= rtc.tens_u & rtc.tens_l; |
shd_secs <= rtc.secs_u & rtc.secs_l; |
shd_mins <= rtc.mins_u & rtc.mins_l; |
shd_hours <= rtc.hours_u & rtc.hours_l; |
shd_dow <= "00000" & rtc.dow; |
update_shd <= '0'; |
end if; |
|
Reg_Addr_q <= Reg_Addr; |
Wr_Data_q <= Wr_Data; |
|
Wr_En <= Addr_Match and Wr_Enable; |
update_rtc <= '0'; |
if( Wr_En = '1' )then |
case( Reg_Addr_q )is |
when "000" => |
interval <= Wr_Data_q; |
|
when "001" => |
shd_tens <= Wr_Data_q; |
|
when "010" => |
shd_secs <= Wr_Data_q; |
|
when "011" => |
shd_mins <= Wr_Data_q; |
|
when "100" => |
shd_hours <= Wr_Data_q; |
|
when "101" => |
shd_dow <= Wr_Data_q; |
|
when "110" => |
update_rtc <= '1'; |
|
when "111" => |
update_shd <= '1'; |
|
when others => null; |
end case; |
end if; |
|
-- Coherency timer - ensures that the shadow registers are updated with |
-- valid time data by delaying updates until the rtc registers have |
-- finished cascading. |
update_ctmr <= update_ctmr - or_reduce(update_ctmr); |
if( rtc.frac_ro = '1' )then |
update_ctmr <= (others => '1'); |
end if; |
|
Rd_Data <= (others => '0'); |
Rd_En <= Addr_Match and Rd_Enable; |
if( Rd_En = '1' )then |
case( Reg_Addr_q )is |
when "000" => |
Rd_Data <= interval; |
when "001" => |
Rd_Data <= shd_tens; |
when "010" => |
Rd_Data <= shd_secs; |
when "011" => |
Rd_Data <= shd_mins; |
when "100" => |
Rd_Data <= shd_hours; |
when "101" => |
Rd_Data <= shd_dow; |
when "110" => |
null; |
when "111" => |
Rd_Data <= update_shd & "0000000"; |
when others => null; |
end case; |
end if; |
|
end if; |
end process; |
|
end architecture; |