timer.vhd 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. --+-----------------------------------+-------------------------------------+--
  2. --| ___ ___ | (c) 2013-2014 William R Sowerbutts |--
  3. --| ___ ___ ___ ___( _ ) / _ \ | will@sowerbutts.com |--
  4. --| / __|/ _ \ / __|_ / _ \| | | | | |--
  5. --| \__ \ (_) | (__ / / (_) | |_| | | A Z80 FPGA computer, just for fun |--
  6. --| |___/\___/ \___/___\___/ \___/ | |--
  7. --| | http://sowerbutts.com/ |--
  8. --+-----------------------------------+-------------------------------------+--
  9. --| A simple timer peripheral for timing intervals and generating periodic |--
  10. --| interrupts. |--
  11. --+-------------------------------------------------------------------------+--
  12. --
  13. -- There are two timers; a 1MHz 32-bit counter which always counts up (unless reset to 0)
  14. -- and whose value can be transferred atomically to a 32-bit latch, and a 1MHz 24-bit down
  15. -- counter which triggers an interrupt and is reset to a programmable value upon reaching
  16. -- zero. Writes to the register at base+1 perform timer operations according to the value
  17. -- written. The 1MHz is derived by prescaling the system clock.
  18. --
  19. -- register layout:
  20. --
  21. -- address read value write operation
  22. -- --------- ------------------------------------ -------------------------------------
  23. -- base+0 status register set status register
  24. -- base+1 (unused) perform operation according to value written
  25. -- base+2 (unused) (no operation)
  26. -- base+3 (unused) (no operation)
  27. -- base+4 muxed register value (low byte) update muxed register value
  28. -- base+5 muxed register value update muxed register value
  29. -- base+6 muxed register value update muxed register value
  30. -- base+7 muxed register value (high byte) update muxed register value
  31. --
  32. --
  33. -- operation values (for writes to base+1):
  34. -- 00 -- acknowledge interrupt
  35. -- 01 -- reset upcounter value to zero
  36. -- 02 -- update latched value from upcounter value
  37. -- 03 -- reset downcounter
  38. -- 10 -- set register mux select to upcounter current
  39. -- 11 -- set register mux select to upcounter latched
  40. -- 12 -- set register mux select to downcounter current
  41. -- 13 -- set register mux select to downcountre reset
  42. --
  43. --
  44. -- control/status register layout:
  45. -- bits 0, 1, -- register mux select (controls which register is visible in registers at base+4 through base+7):
  46. -- 0 0 upcounter current value
  47. -- 0 1 upcounter latched value
  48. -- 1 0 downcounter current value
  49. -- 1 1 downcounter reset value
  50. -- (bits 2, 3, 4, 5 are currently unused)
  51. -- bit 6 -- countdown timer interrupt enable (0=disable, 1=enable)
  52. -- bit 7 -- interrupt flag (0=no interrupt, 1=one or interrupts occurred but not yet acknowledged)
  53. --
  54. library IEEE;
  55. use IEEE.STD_LOGIC_1164.ALL;
  56. use IEEE.NUMERIC_STD.ALL;
  57. entity timer is
  58. generic (
  59. clk_frequency : natural := (128 * 1000000)
  60. );
  61. port ( clk : in std_logic;
  62. reset : in std_logic;
  63. cpu_address : in std_logic_vector(2 downto 0);
  64. data_in : in std_logic_vector(7 downto 0);
  65. data_out : out std_logic_vector(7 downto 0);
  66. enable : in std_logic;
  67. req_read : in std_logic;
  68. req_write : in std_logic;
  69. interrupt : out std_logic
  70. );
  71. end timer;
  72. architecture Behavioral of timer is
  73. signal upcounter_value : unsigned(31 downto 0) := (others => '0');
  74. signal upcounter_latch : unsigned(31 downto 0) := (others => '0');
  75. signal downcounter_value : unsigned(31 downto 0) := (others => '0');
  76. signal downcounter_start : unsigned(31 downto 0) := (others => '0');
  77. -- if using frequencies > 128MHz this counter will need to be wider than 7 bits
  78. signal counter_prescale : unsigned(6 downto 0) := (others => '0');
  79. constant prescale_wrap : unsigned(6 downto 0) := to_unsigned((clk_frequency / 1000000) - 1, 7); -- aim for a 1MHz counter
  80. signal interrupt_enable : std_logic := '0';
  81. signal interrupt_signal : std_logic := '0';
  82. signal regmux_select : std_logic_vector(1 downto 0) := "00";
  83. signal regmux_output : std_logic_vector(31 downto 0);
  84. signal regmux_updated : std_logic_vector(31 downto 0);
  85. signal status_register_value: std_logic_vector(7 downto 0);
  86. begin
  87. interrupt <= (interrupt_signal and interrupt_enable);
  88. with cpu_address select
  89. data_out <=
  90. status_register_value when "000",
  91. regmux_output(7 downto 0) when "100",
  92. regmux_output(15 downto 8) when "101",
  93. regmux_output(23 downto 16) when "110",
  94. regmux_output(31 downto 24) when "111",
  95. status_register_value when others;
  96. status_register_value <= interrupt_signal & interrupt_enable & "0000" & regmux_select;
  97. with regmux_select select
  98. regmux_output <=
  99. std_logic_vector(upcounter_value ) when "00",
  100. std_logic_vector(upcounter_latch ) when "01",
  101. std_logic_vector(downcounter_value) when "10",
  102. std_logic_vector(downcounter_start) when "11",
  103. std_logic_vector(downcounter_start) when others;
  104. with cpu_address(1 downto 0) select
  105. regmux_updated <=
  106. regmux_output(31 downto 8) & data_in when "00",
  107. regmux_output(31 downto 16) & data_in & regmux_output(7 downto 0) when "01",
  108. regmux_output(31 downto 24) & data_in & regmux_output(15 downto 0) when "10",
  109. data_in & regmux_output(23 downto 0) when "11",
  110. data_in & regmux_output(23 downto 0) when others;
  111. counter_proc: process(clk)
  112. begin
  113. if rising_edge(clk) then
  114. if reset = '1' then
  115. upcounter_value <= (others => '0');
  116. upcounter_latch <= (others => '0');
  117. downcounter_value <= (others => '0');
  118. downcounter_start <= (others => '0');
  119. counter_prescale <= (others => '0');
  120. interrupt_enable <= '0';
  121. interrupt_signal <= '0';
  122. regmux_select <= "00";
  123. else
  124. -- prescaled counter
  125. if counter_prescale = prescale_wrap then
  126. counter_prescale <= (others => '0'); -- reset prescale counter
  127. upcounter_value <= upcounter_value + 1;
  128. if downcounter_value = 0 then
  129. downcounter_value <= downcounter_start;
  130. interrupt_signal <= '1';
  131. else
  132. downcounter_value <= downcounter_value - 1;
  133. end if;
  134. else
  135. counter_prescale <= counter_prescale + 1;
  136. end if;
  137. if enable = '1' and req_write = '1' then
  138. if cpu_address = "000" then
  139. interrupt_signal <= data_in(7);
  140. interrupt_enable <= data_in(6);
  141. regmux_select <= data_in(1 downto 0);
  142. elsif cpu_address = "001" then
  143. case data_in is
  144. when "00000000" => interrupt_signal <= '0';
  145. when "00000001" => upcounter_value <= (others => '0');
  146. when "00000010" => upcounter_latch <= upcounter_value;
  147. when "00000011" => downcounter_value <= downcounter_start;
  148. when "00010000" => regmux_select <= "00";
  149. when "00010001" => regmux_select <= "01";
  150. when "00010010" => regmux_select <= "10";
  151. when "00010011" => regmux_select <= "11";
  152. when others =>
  153. end case;
  154. elsif cpu_address(2) = '1' then
  155. case regmux_select is
  156. when "00" => upcounter_value <= unsigned(regmux_updated);
  157. when "01" => upcounter_latch <= unsigned(regmux_updated);
  158. when "10" => downcounter_value <= unsigned(regmux_updated);
  159. when "11" => downcounter_start <= unsigned(regmux_updated);
  160. when others =>
  161. end case;
  162. end if;
  163. end if;
  164. end if;
  165. end if;
  166. end process;
  167. end Behavioral;