diff --git a/soc/lib/config.vhd b/soc/lib/config.vhd index c666c48..1ecfe86 100644 --- a/soc/lib/config.vhd +++ b/soc/lib/config.vhd @@ -28,6 +28,7 @@ package config is constant CFG_DMEM : integer := CFG_MEM+1; constant CFG_LED : integer := CFG_DMEM+1; constant CFG_SW : integer := CFG_LED+1; + constant CFG_TIMER : integer := CFG_SW+1; ----------------------------- -- base address (BADR) & mask address (MADR) @@ -38,6 +39,7 @@ package config is --constant CFG_BADR_NEXTFREEADDRESS : generic_addr_type := 16#00000800#; constant CFG_BADR_LED : generic_addr_type := 16#000F0000#; constant CFG_BADR_SW : generic_addr_type := 16#000F0004#; + constant CFG_BADR_TIMER : generic_addr_type := 16#000F0008#; -- mask addr constant CFG_MADR_ZERO : generic_mask_type := 0; @@ -46,6 +48,7 @@ package config is constant CFG_MADR_DMEM : generic_mask_type := 16#3FFFFF# - (256 -1); -- uses 6 word-bits, size 256 byte constant CFG_MADR_LED : generic_mask_type := 16#3FFFFF#; -- size=1 byte constant CFG_MADR_SW : generic_mask_type := 16#3FFFFF# - (4 - 1); -- size=4 byte + constant CFG_MADR_TIMER : generic_mask_type := 16#3FFFFF# - (8 - 1); -- size=8 byte (2 words) end package config; diff --git a/soc/peripheral/peripherals.vhd b/soc/peripheral/peripherals.vhd index 1da3c38..4b0e185 100644 --- a/soc/peripheral/peripherals.vhd +++ b/soc/peripheral/peripherals.vhd @@ -28,8 +28,8 @@ package lt16soc_peripherals is component wb_switches is generic( - memaddr : generic_addr_type; --:= CFG_BADR_LED; - addrmask : generic_mask_type --:= CFG_MADR_LED; + memaddr : generic_addr_type; --:= CFG_BADR_SW; + addrmask : generic_mask_type --:= CFG_MADR_SW; ); port( clk : in std_logic; @@ -42,6 +42,21 @@ package lt16soc_peripherals is ); end component; + component wb_timer is + generic( + memaddr : generic_addr_type; --:= CFG_BADR_TIMER; + addrmask : generic_mask_type --:= CFG_MADR_TIMER; + ); + port( + clk : in std_logic; + rst : in std_logic; + wslvi : in wb_slv_in_type; + wslvo : out wb_slv_out_type; + + interrupt : out std_logic + ); + end component; + end lt16soc_peripherals; package body lt16soc_peripherals is diff --git a/soc/peripheral/timer.vhd b/soc/peripheral/timer.vhd new file mode 100644 index 0000000..ac7f829 --- /dev/null +++ b/soc/peripheral/timer.vhd @@ -0,0 +1,133 @@ +-- See the file "LICENSE" for the full license governing this code. -- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use work.lt16x32_global.all; +use work.wishbone.all; +use work.config.all; + +entity wb_timer is + generic( + memaddr : generic_addr_type; --:= CFG_BADR_TIMER; + addrmask : generic_mask_type --:= CFG_MADR_TIMER; + ); + port( + clk : in std_logic; + rst : in std_logic; + wslvi : in wb_slv_in_type; + wslvo : out wb_slv_out_type; + + interrupt : out std_logic + ); +end wb_timer; + +architecture Behavioral of wb_timer is + constant COUNT_MAX : integer := 32 - 1; + + signal ack : std_logic; + + signal counter : integer range 0 to COUNT_MAX; + + signal enable : std_logic; + signal repeat : std_logic; + signal reset : std_logic; + + signal counter_vector : std_logic_vector(31 downto 0); + signal status_register : std_logic_vector(31 downto 0); + + signal data_in : std_logic_vector(2 downto 0); + signal data_in_changed : std_logic; + +begin + + process(clk) + begin + if clk'event and clk='1' then + if rst = '1' then + counter <= 0; + else + if reset = '1' then -- reset register + counter <= 0; + else + if enable = '1' then + if counter = COUNT_MAX then + counter <= 0; + else + counter <= counter + 1; + end if; + end if; + end if; + end if; + end if; + end process; + + process(clk) + begin + if clk'event and clk='1' then + if rst = '1' then + enable <= '0'; + repeat <= '0'; + reset <= '0'; + else + reset <= '0'; + + if data_in_changed = '1' then + enable <= data_in(0); + repeat <= data_in(1); + reset <= data_in(2); + end if; + + -- Reset enable bit + if counter = COUNT_MAX and repeat = '0' then + enable <= '0'; + end if; + end if; + end if; + end process; + + process(clk) + begin + if clk'event and clk='1' then + if rst = '1' then + ack <= '0'; + data_in <= (others => '0'); + data_in_changed <= '0'; + else + data_in <= (others => '0'); + data_in_changed <= '0'; + + if wslvi.stb = '1' and wslvi.cyc = '1' then + if wslvi.we='1' and wslvi.adr(2) = '1' then + data_in <= dec_wb_dat(wslvi.sel,wslvi.dat)(2 downto 0); + data_in_changed <= '1'; + end if; + + if ack = '0' then + ack <= '1'; + else + ack <= '0'; + end if; + else + ack <= '0'; + end if; + end if; + end if; + end process; + + counter_vector <= std_logic_vector(to_unsigned(counter, counter_vector'length)); + + status_register(0) <= enable; -- enable + status_register(1) <= repeat; -- repeat + status_register(31 downto 2) <= (others => '0'); -- reset bit always reads as 0 + + wslvo.dat <= counter_vector when wslvi.adr(2) = '0' + else status_register when wslvi.adr(2) = '1' + else (others => '0'); + + interrupt <= '1' when counter = COUNT_MAX else '0'; + + wslvo.ack <= ack; + wslvo.wbcfg <= wb_membar(memaddr, addrmask); + +end Behavioral; diff --git a/soc/testbench/timer_tb.vhd b/soc/testbench/timer_tb.vhd new file mode 100644 index 0000000..f403740 --- /dev/null +++ b/soc/testbench/timer_tb.vhd @@ -0,0 +1,99 @@ +-- See the file "LICENSE" for the full license governing this code. -- +LIBRARY ieee; +USE ieee.std_logic_1164.ALL; +USE ieee.numeric_std.ALL; + +LIBRARY work; +USE work.lt16soc_peripherals.ALL; +USE work.wishbone.ALL; +USE work.wb_tp.ALL; +USE work.config.ALL; + +ENTITY timer_tb IS +END ENTITY; + +ARCHITECTURE sim OF timer_tb IS + + constant CLK_PERIOD : time := 10 ns; + + signal clk : std_logic := '0'; + signal rst : std_logic; + signal data : std_logic_vector(WB_PORT_SIZE-1 downto 0); + + signal interrupt : std_logic; + + signal slvi : wb_slv_in_type; + signal slvo : wb_slv_out_type; + +BEGIN + + SIM_SLV: wb_timer + generic map( + memaddr => CFG_BADR_TIMER, + addrmask => CFG_MADR_TIMER + ) + port map( + clk => clk, + rst => rst, + wslvi => slvi, + wslvo => slvo, + interrupt => interrupt + ); + + clk_gen: process + begin + clk <= not clk; + wait for CLK_PERIOD/2; + end process clk_gen; + + stimuli: process + begin + rst <= '1'; + wait for CLK_PERIOD; + rst <= '0'; + wait for CLK_PERIOD; + wait for CLK_PERIOD; + wait for CLK_PERIOD; + + -- Configure timer... + data <= (others => '0'); + data(0) <= '1'; -- enable + data(1) <= '1'; -- repeat + generate_sync_wb_single_write(slvi,slvo,clk,data, ADR_OFFSET => 4); + + wait until interrupt = '1'; + wait for CLK_PERIOD*20; + + -- Read counter value + data <= (others => '0'); + generate_sync_wb_single_read(slvi,slvo,clk,data); + + wait for CLK_PERIOD*4; + + -- Disable repeat and reset timer... + data <= (others => '0'); + data(1) <= '0'; -- repeat + data(2) <= '1'; -- reset + generate_sync_wb_single_write(slvi,slvo,clk,data, ADR_OFFSET => 4); + + wait until interrupt = '1'; + wait for CLK_PERIOD*20; + + -- Restart timer... + data <= (others => '0'); + data(0) <= '1'; -- enable + generate_sync_wb_single_write(slvi,slvo,clk,data, ADR_OFFSET => 4); + + wait for CLK_PERIOD*20; + + -- Read status register + data <= (others => '0'); + generate_sync_wb_single_read(slvi,slvo,clk,data, ADR_OFFSET => 4); + + wait for CLK_PERIOD * 2; + assert false report "Simulation terminated!" severity failure; + + wait; + end process stimuli; + +END ARCHITECTURE;