diff --git a/wave/makefile b/wave/makefile index b0dc89b..23410f3 100644 --- a/wave/makefile +++ b/wave/makefile @@ -1,12 +1,12 @@ all: sim -sim: test.ghw +sim: pdmout_test.ghw square_test.ghw -sim_sources = pdmout_test.vhdl -sources = pdmout.vhdl +sim_sources = pdmout_test.vhdl square_test.vhdl +sources = pdmout.vhdl square.vhdl -test.ghw: work-obj93.cf - ghdl -r pdmout_test --wave=$@ +%.ghw: work-obj93.cf + ghdl -r $* --wave=$@ work-obj93.cf: $(sim_sources) $(sources) diff --git a/wave/square.vhdl b/wave/square.vhdl new file mode 100644 index 0000000..0e5c75d --- /dev/null +++ b/wave/square.vhdl @@ -0,0 +1,130 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +-- some kind of square wave generator, writing 16-bit samples +-- to a memory address using DMA periodically +entity square is + port + ( + clk : in std_logic; + rst : in std_logic; + + -- bus slave interface + s_we : in std_logic; + s_addr : in std_logic_vector(15 downto 0); + s_din : in std_logic_vector(15 downto 0); + + -- bus master interface (DMA!!) + m_busy : in std_logic; + m_we : out std_logic; + m_addr : out std_logic_vector(15 downto 0); + m_dout : out std_logic_vector(15 downto 0) + ); +end square; + +-- +-- Mem layout: +-- 0x00: 16-bit unsigned period (units of 256 clock cycles) +-- 0x02: 16-bit unsigned high value +-- 0x04: 16-bit unsigned low value +-- 0x06: 16-bit output address +-- 0x08: flags: [enabled] + +architecture Behavioral of square is + + -- all registers + signal period, hi_val, lo_val, out_addr: std_logic_vector(15 downto 0); + signal enabled: std_logic; + + signal counter: unsigned(23 downto 0); + +begin + + -- counter process + -- drives counter + process(clk, rst) + begin + + if rst = '1' then + counter <= to_unsigned(0, 24); + elsif rising_edge(clk) then + if enabled = '0' or counter(22 downto 7) = unsigned(period) then + counter <= to_unsigned(0, 24); + else + counter <= counter + 1; + end if; + end if; + + end process; + + -- signal generation + -- drives m_we, m_addr, m_dout + process(clk, rst) + variable high: std_logic; + variable deferred: std_logic; + begin + + if rst = '1' then + m_we <= '0'; + m_addr <= x"0000"; + m_dout <= x"0000"; + high := '0'; + deferred := '0'; + + elsif rising_edge(clk) then + m_we <= '0'; + + if enabled = '1' then + if counter = 0 and m_busy = '1' then + deferred := '1'; + elsif deferred = '1' or (counter = 0 and m_busy = '0') then + m_we <= '1'; + m_addr <= out_addr; + if high = '1' then + m_dout <= hi_val; + else + m_dout <= lo_val; + end if; + + high := not high; + deferred := '0'; + end if; + end if; + end if; + + end process; + + -- Bus slave process + -- drives period, value, out_addr, enabled + process(clk, rst) + begin + + if rst = '1' then + period <= x"0000"; + hi_val <= x"0000"; + lo_val <= x"0000"; + out_addr <= x"0000"; + enabled <= '0'; + + elsif rising_edge(clk) then + if s_we = '1' then + case s_addr(3 downto 0) is + when x"0" => + period <= s_din; + when x"2" => + hi_val <= s_din; + when x"4" => + lo_val <= s_din; + when x"6" => + out_addr <= s_din; + when x"8" => + enabled <= s_din(0); + when others => + end case; + end if; + end if; + + end process; + +end Behavioral; diff --git a/wave/square_test.vhdl b/wave/square_test.vhdl new file mode 100644 index 0000000..a205c43 --- /dev/null +++ b/wave/square_test.vhdl @@ -0,0 +1,112 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use std.textio.all; + +entity square_test is +end square_test; + +architecture rtl of square_test is + + component square is + port + ( + clk : in std_logic; + rst : in std_logic; + + -- bus slave interface + s_we : in std_logic; + s_addr : in std_logic_vector(15 downto 0); + s_din : in std_logic_vector(15 downto 0); + + -- bus master interface (DMA!!) + m_busy : in std_logic; + m_we : out std_logic; + m_addr : out std_logic_vector(15 downto 0); + m_dout : out std_logic_vector(15 downto 0) + ); + end component; + + signal finished, clk, rst: std_logic := '0'; + + signal s_we, m_busy, m_we: std_logic; + signal s_addr, s_din, m_addr, m_dout: std_logic_vector(15 downto 0); + +begin + dut: square port map(clk => clk, rst => rst, + s_we => s_we, s_addr => s_addr, s_din => s_din, + m_busy => m_busy, m_we => m_we, m_addr => m_addr, m_dout => m_dout); + + -- tick tock + process + begin + if finished = '0' then + clk <= not clk; + wait for 5 ns; + else + clk <= '0'; + wait; + end if; + end process; + + process + begin + rst <= '1'; + + wait for 1 ns; + assert(m_we='0') report "Fail rst" severity error; + + rst <= '0'; + m_busy <= '0'; + + wait for 10 ns; + + s_we <= '1'; + s_addr <= x"0000"; -- period + s_din <= x"0001"; -- 256 cycles (2560 ns) + + wait for 10 ns; + + s_we <= '1'; + s_addr <= x"0002"; -- high + s_din <= x"0042"; + + wait for 10 ns; + + s_we <= '1'; + s_addr <= x"0004"; -- low + s_din <= x"0037"; + + wait for 10 ns; + + s_we <= '1'; + s_addr <= x"0006"; -- DNA address + s_din <= x"babe"; + + wait for 10 ns; + + s_we <= '1'; + s_addr <= x"0008"; -- enable + s_din <= x"0001"; + + wait for 20 ns; + + assert(m_addr = x"babe") report "Fail to write to mem addr" severity error; + assert(m_we = '1') report "Fail to write to mem we" severity error; + assert(m_dout = x"0037") report "Fail to write to mem dout" severity error; + + wait for 20 ns; + + assert(m_we = '0') report "Fail to stop m_we" severity error; + + wait for 1300 ns; + + assert(m_dout = x"0042") report "Fail to write to mem dout" severity error; + + assert false report "Test done." severity note; + + finished <= '1'; + wait; + + end process; +end rtl;