Skip to content

Instantly share code, notes, and snippets.

@purpl3F0x
Created April 29, 2024 11:31
Show Gist options
  • Save purpl3F0x/34676024f27b3f48af0aec49d3d4e177 to your computer and use it in GitHub Desktop.
Save purpl3F0x/34676024f27b3f48af0aec49d3d4e177 to your computer and use it in GitHub Desktop.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity mac is
generic (
SIZEIN : natural := 8; -- width of the inputs
SIZEOUT : natural := 19 -- width of the output
);
port (
clk : in std_logic;
init : in std_logic;
a : in std_logic_vector (SIZEIN-1 downto 0);
b : in std_logic_vector (SIZEIN-1 downto 0);
accum_out : out std_logic_vector (SIZEOUT-1 downto 0));
end entity;
architecture rtl of mac is
-- Declare registers for intermediate values
signal a_reg, b_reg : unsigned (SIZEIN-1 downto 0) := (others => '0');
signal init_reg : std_logic;
signal mult_reg : unsigned (2*SIZEIN-1 downto 0) := (others => '0');
signal adder_out, old_result : unsigned (SIZEOUT-1 downto 0) := (others => '0');
begin
process (adder_out, init_reg)
begin
if init_reg = '1' then
old_result <= (others => '0');
else
-- 'init' is now active (=low) and opens the accumulation loop.
-- The accumulator takes the next multiplier output in
-- the same cycle.
old_result <= adder_out;
end if;
end process;
process (clk)
begin
if rising_edge(clk) then
a_reg <= unsigned(a);
b_reg <= unsigned(b);
mult_reg <= a_reg * b_reg;
init_reg <= init;
-- Store accumulation result into a register
adder_out <= old_result + mult_reg;
end if;
end process;
-- Output accumulation result
accum_out <= std_logic_vector(adder_out);
end rtl;
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity mac_tb is
end mac_tb;
architecture Behavioral of mac_tb is
signal a, b : std_logic_vector(7 downto 0);
signal acc_out : std_logic_vector(18 downto 0);
signal clk : std_logic := '0';
signal init : std_logic := '0';
begin
uut: entity work.mac
Port map (
clk => clk,
a => a,
b => b,
init => init,
accum_out => acc_out
);
clk_proc: process is
begin
clk <= not clk;
wait for 5 ns;
end process;
stimulus: process is
begin
for i in 0 to 15 loop
a <= std_logic_vector(to_unsigned(i, a'length));
for j in 0 to 15 loop
b <= std_logic_vector(to_unsigned(j, b'length));
wait for 10 ns;
end loop;
end loop;
wait for 20 ns;
assert (unsigned(acc_out) = 14400) severity FAILURE;
Init <= '0';
a <= (others => '0');
b <= (others => '0');
wait for 10 ns;
Init <= '1';
wait for 10 ns;
Init <= '0';
assert (unsigned(acc_out) = 0) severity FAILURE;
a <= (others => '1');
b <= (others => '1');
wait for 10 * 8 ns;
assert (unsigned(acc_out) = 520200) severity FAILURE;
Init <= '1';
wait for 10 ns;
assert (unsigned(acc_out) = 65025) severity FAILURE;
std.env.finish;
end process;
end Behavioral;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment