synth/wave/square.vhdl
2021-03-13 15:46:20 -08:00

138 lines
3.0 KiB
VHDL

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);
signal active: std_logic;
begin
-- counter process
-- drives counter, active
process(clk, rst)
begin
if rst = '1' then
counter <= to_unsigned(0, 24);
active <= '0';
elsif rising_edge(clk) then
active <= '0';
counter <= to_unsigned(0, 24);
if enabled = '1' and unsigned(period) /= 0 then
if counter(22 downto 7) = unsigned(period) then
active <= '1';
else
counter <= counter + 1;
end if;
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 active = '1' and m_busy = '1' then
deferred := '1';
elsif deferred = '1' or (active = '1' 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;