From 55c6be3d00ff7ba5b73c44a7b91ab0151236de33 Mon Sep 17 00:00:00 2001 From: Paul Mathieu Date: Thu, 30 Oct 2025 07:54:33 -0400 Subject: [PATCH] wave: axi4-compliant wave --- wave/pdm.vhdl | 46 ++++++++++++ wave/wave.vhdl | 175 ++++++++++++++++++++++++++++++++++++++++++++ wave/wave_test.vhdl | 165 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 386 insertions(+) create mode 100644 wave/pdm.vhdl create mode 100644 wave/wave.vhdl create mode 100644 wave/wave_test.vhdl diff --git a/wave/pdm.vhdl b/wave/pdm.vhdl new file mode 100644 index 0000000..dc37c28 --- /dev/null +++ b/wave/pdm.vhdl @@ -0,0 +1,46 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +entity pdm is + port + ( + clk : in std_logic; + rst : in std_logic; + + -- hardware + out_pin : out std_logic; + + -- input interface + enabled : in std_logic; + sample : in std_logic_vector(15 downto 0) + ); +end pdm; + +architecture Behavioral of pdm is + + signal feedback: signed(16 downto 0); + +begin + + -- PDM process + -- drives pin_out, feedback + process(clk, rst) + begin + + if rst = '1' then + feedback <= to_signed(0, 17); + out_pin <= '0'; + elsif rising_edge(clk) and enabled = '1' then + if feedback > 0 then + out_pin <= '1'; + feedback <= feedback + signed("0" & sample) - ("0" & x"ffff"); + else + out_pin <= '0'; + feedback <= feedback + signed("0" & sample); + end if; + end if; + + end process; + +end Behavioral; diff --git a/wave/wave.vhdl b/wave/wave.vhdl new file mode 100644 index 0000000..05bf8df --- /dev/null +++ b/wave/wave.vhdl @@ -0,0 +1,175 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +-- some kind of square wave generator, with PDM output +entity wave is + port + ( + -- AXI4 slave interface + aclk : in std_logic; + aresetn : in std_logic; + + -- read addr + araddr : in std_logic_vector(31 downto 0); + arvalid : in std_logic; + arready : out std_logic; + + -- read data + rdata : out std_logic_vector(31 downto 0); + rresp : out std_logic; + rvalid : out std_logic; + rready : in std_logic; + + -- write addr + awaddr : in std_logic_vector(31 downto 0); + awvalid : in std_logic; + awready : out std_logic; + + -- write data + wdata : in std_logic_vector(31 downto 0); + wstrb : in std_logic_vector(3 downto 0); + + -- write resp + bresp : out std_logic; + bvalid : out std_logic; + bready : in std_logic; + + + -- PDM output! + pdmout : out std_logic + ); +end wave; + +-- +-- Mem layout: +-- 0x00: control: [bit0: enabled] +-- 0x04: 32-bit unsigned period (in clock cycles) +-- 0x08: 16-bit unsigned high value (high 16 bits ignored) +-- 0x0c: 16-bit unsigned low value (high 16 bits ignored) + +architecture Behavioral of wave is + + component pdm is + port + ( + clk : in std_logic; + rst : in std_logic; + + -- hardware + out_pin : out std_logic; + + -- input interface + enabled : in std_logic; + sample : in std_logic_vector(15 downto 0) + ); + end component; + + -- all registers + signal period, hi_val, lo_val, sample: std_logic_vector(15 downto 0); + signal enabled, rst, onwrite: std_logic; + signal counter: unsigned(23 downto 0); + +begin + + arready <= '1'; + awready <= '1'; + rst <= not aresetn; + + pdm0: pdm port map(clk => aclk, rst => rst, out_pin => pdmout, + sample => sample, enabled => enabled); + + -- main process + -- drives counter, sample + process(aclk, aresetn) + variable high: std_logic; + begin + + if aresetn = '0' then + counter <= to_unsigned(0, 24); + sample <= x"0000"; + high := '0'; + elsif rising_edge(aclk) then + counter <= to_unsigned(0, 24); + if high = '1' then + sample <= hi_val; + else + sample <= lo_val; + end if; + + if enabled = '1' and unsigned(period) /= 0 and onwrite = '0' then + if counter(22 downto 7) = unsigned(period) - 1 + and counter(6 downto 0) = x"7f" then + high := not high; + else + counter <= counter + 1; + end if; + end if; + end if; + + end process; + + -- Bus slave process + -- drives period, value, out_addr, enabled, onwrite + process(aclk, aresetn) + -- 00: control, 01: period, 02: high, 03: low + variable waddr: std_logic_vector(2 downto 0); + variable raddr: std_logic_vector(2 downto 0); + begin + + if aresetn = '0' then + period <= x"0000"; + hi_val <= x"0000"; + lo_val <= x"0000"; + enabled <= '0'; + waddr := "000"; + + elsif rising_edge(aclk) then + + rvalid <= '0'; + rdata <= x"00000000"; + rresp <= '0'; + bvalid <= '0'; + bresp <= '0'; + onwrite <= '0'; + + if arvalid = '1' then + raddr := araddr(4 downto 2); + end if; + if awvalid = '1' then + waddr := awaddr(4 downto 2); + end if; + if arvalid = '1' then + case waddr(1 downto 0) is + when "00" => + rdata(0) <= enabled; + when "01" => + rdata(23 downto 8) <= period; + when "10" => + rdata(15 downto 0) <= hi_val; + when "11" => + rdata(15 downto 0) <= lo_val; + when others => + end case; + rvalid <= '1'; + end if; + if unsigned(wstrb) > 0 then + case waddr(1 downto 0) is + when "00" => + enabled <= wdata(0); + when "01" => + period <= wdata(23 downto 8); + when "10" => + hi_val <= wdata(15 downto 0); + when "11" => + lo_val <= wdata(15 downto 0); + when others => + end case; + bvalid <= '1'; + onwrite <= '1'; + end if; + end if; + + end process; + +end Behavioral; diff --git a/wave/wave_test.vhdl b/wave/wave_test.vhdl new file mode 100644 index 0000000..0405303 --- /dev/null +++ b/wave/wave_test.vhdl @@ -0,0 +1,165 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use std.textio.all; + +entity wave_test is +end wave_test; + +architecture rtl of wave_test is + + component wave is + port + ( + -- AXI4 slave interface + aclk : in std_logic; + aresetn : in std_logic; + + -- read addr + araddr : in std_logic_vector(31 downto 0); + arvalid : in std_logic; + arready : out std_logic; + + -- read data + rdata : out std_logic_vector(31 downto 0); + rresp : out std_logic; + rvalid : out std_logic; + rready : in std_logic; + + -- write addr + awaddr : in std_logic_vector(31 downto 0); + awvalid : in std_logic; + awready : out std_logic; + + -- write data + wdata : in std_logic_vector(31 downto 0); + wstrb : in std_logic_vector(3 downto 0); + + -- write resp + bresp : out std_logic; + bvalid : out std_logic; + bready : in std_logic; + + + -- PDM output! + pdmout : out std_logic + ); + end component; + + signal finished, clk, rst, rstn: std_logic := '0'; + + signal arvalid, arready, awvalid, awready: std_logic; + signal rresp, rvalid, rready, bresp, bvalid, bready: std_logic; + signal wstrb: std_logic_vector(3 downto 0); + signal araddr, rdata, awaddr, wdata: std_logic_vector(31 downto 0); + + signal pdmout: std_logic; + + constant period: integer := 7 * 256; + constant half_time: time := 1280 ns * period; + +begin + rstn <= not rst; + dut: wave port map(aclk => clk, aresetn => rstn, + arvalid => arvalid, arready => arready, awvalid => awvalid, awready => awready, + rresp => rresp, rvalid => rvalid, rready => rready, bresp => bresp, bvalid => bvalid, bready => bready, + wstrb => wstrb, araddr => araddr, rdata => rdata, awaddr => awaddr, wdata => wdata, + pdmout => pdmout + ); + + -- 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'; + + arvalid <= '0'; + awvalid <= '0'; + wstrb <= "0000"; + + wait for 1 ns; +-- assert(='0') report "Fail rst" severity error; + + rst <= '0'; + + wait for 10 ns; + + awvalid <= '1'; + awaddr <= x"00000000"; -- enable + wstrb <= "1111"; + wdata <= x"00000001"; + bready <= '1'; + + wait for 10 ns; + assert(bvalid = '1') report "Write error" severity error; + assert(bresp = '0') report "Write fail" severity error; + assert(awready = '1') report "Write error" severity error; + + awaddr <= x"00000004"; -- period + wdata <= std_logic_vector(to_unsigned(period, 32)); + + wait for 10 ns; + + -- read back + wstrb <= "0000"; + awvalid <= '0'; + arvalid <= '1'; + araddr <= x"00000004"; + rready <= '1'; + + wait for 10 ns; + assert(unsigned(rdata) = period) report "Period readback failed" severity error; + + arvalid <= '0'; + awvalid <= '1'; + wstrb <= "1111"; + + awaddr <= x"00000008"; -- high + wdata <= x"00008000"; + + wait for 10 ns; + + awaddr <= x"0000000c"; -- low + wdata <= x"00004000"; + + wait for 10 ns; + + wstrb <= "0000"; + awvalid <= '0'; + + wait for 30 ns; + assert(pdmout = '1') report "wrong pdmout" severity error; + wait for 10 ns; + assert(pdmout = '0') report "wrong pdmout" severity error; + wait for 10 ns; + assert(pdmout = '0') report "wrong pdmout" severity error; + wait for 10 ns; + assert(pdmout = '1') report "wrong pdmout" severity error; + wait for 10 ns; + assert(pdmout = '0') report "wrong pdmout" severity error; + wait for 10 ns; + assert(pdmout = '0') report "wrong pdmout" severity error; + wait for 10 ns; + assert(pdmout = '0') report "wrong pdmout" severity error; + wait for 10 ns; + assert(pdmout = '1') report "wrong pdmout" severity error; + + wait for 100 us; + + assert false report "Test done." severity note; + + finished <= '1'; + wait; + + end process; +end rtl;