library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_arith.all;

entity arithm_top is
  port ( clk: in bit;
         SW1_1, SW1_2, SW1_3, SW1_4: in std_logic; -- 4-switch
         SW2, SW3: in std_logic;                   -- buttons
         LED_A, LED_B, LED_C, LED_D, LED_E,        -- XSA 7-segm
           LED_F, LED_G, LED_DP: out std_logic;
         DIPSW_1, DIPSW_2, DIPSW_3, DIPSW_4,       -- 8-switch
           DIPSW_5, DIPSW_6, DIPSW_7, DIPSW_8: in std_logic;
         PB1, PB2, PB3, PB4: in std_logic;         -- buttons
         BAR_4, BAR_5, BAR_6, BAR_7,               -- led-bar
           BAR_8, BAR_9, BAR_10: out std_logic;
         LED1_A, LED1_B, LED1_C, LED1_D,           -- XST left 7-segm
           LED1_E, LED1_F, LED1_G, LED1_DP: out std_logic;
         LED2_A, LED2_B, LED2_C, LED2_D,           -- XST left 7-segm
           LED2_E, LED2_F, LED2_G: out std_logic );
end entity arithm_top;

library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_arith.all;

architecture top_level of arithm_top is

  signal sw1, dec1_in, dec2_in: std_logic_vector(3 downto 0);
  signal dipsw_bf: std_logic_vector(7 downto 0);
  signal dipsw, reg_a, reg_b, dec_bf: unsigned(7 downto 0);
  signal add_out, reg_add, sub_out, reg_sub, reg_mul0: unsigned(7 downto 0);
  signal mul0_out, mul1_out, mul2_out, mul3_out: unsigned(7 downto 0);
  signal mul4_out, mul5_out, mul6_out, mul7_out: unsigned(7 downto 0);
  signal mul0_tmp, mul1_tmp, mul2_tmp, mul3_tmp: unsigned(15 downto 0);
  signal mul4_tmp, mul5_tmp, mul7_tmp: unsigned(15 downto 0);
  signal led1_bf, led2_bf, dec1_out, dec2_out: std_logic_vector(0 to 6);

  component decoder
    port ( c3, c2, c1, c0: in std_logic;
           led_a, led_b, led_c, led_d,
             led_e, led_f, led_g: out std_logic );
  end component decoder;

  -- Sequential multiplier (radix-2)
  component multiplier
    port ( clk: in bit;
           a, b: in unsigned(7 downto 0);
           c: out unsigned(15 downto 0) );
  end component multiplier;

  -- Sequential multiplier (radix-4)
  component multiplier2
    port ( clk: in bit;
           a, b: in unsigned(7 downto 0);
           c: out unsigned(15 downto 0) );
  end component multiplier2;

  -- Sequential multiplier (radix-4, ~90% RTL)
  component multiplier3
    port ( clk: in bit;
           a, b: in unsigned(7 downto 0);
           c: out unsigned(15 downto 0) );
  end component multiplier3;

  -- Sequential multiplier (radix-4, 100% RTL)
  component multiplier4
    port ( clk: in bit;
           a, b: in unsigned(7 downto 0);
           c: out unsigned(15 downto 0) );
  end component multiplier4;

  -- Sequential multiplier (radix-4, ver.2)
  component multiplier5
    port ( clk: in bit;
           a, b: in unsigned(7 downto 0);
           c: out unsigned(15 downto 0) );
  end component multiplier5;

  -- Sequential multiplier (radix-4, ver.2, 100% RTL)
  component multiplier7
    port ( clk: in bit;
           a, b: in unsigned(7 downto 0);
           c: out unsigned(15 downto 0) );
  end component multiplier7;

begin

  dipsw_bf <= not ( DIPSW_1 & DIPSW_2 & DIPSW_3 & DIPSW_4 &
                    DIPSW_5 & DIPSW_6 & DIPSW_7 &  DIPSW_8 );
  dipsw <= unsigned(dipsw_bf);
  sw1 <= not ( SW1_1 & SW1_2 & SW1_3 & SW1_4 );

  process
  begin -- registers
    wait on clk until clk='1';
    if  PB1='0'  then    reg_a <= dipsw;    end if;
    if  PB2='0'  then    reg_b <= dipsw;    end if;
    reg_add <= add_out;
    reg_sub <= sub_out;
    reg_mul0 <= mul0_out;
  end process;

  -- Adder & subtracter
  add_out <= reg_a + reg_b;
  sub_out <= reg_a - reg_b;
  -- Multipliers
  mul0_tmp <= reg_a * reg_b;
  mul0_out <= mul0_tmp(7 downto 0);
  M1: multiplier port map ( clk, reg_a, reg_b, mul1_tmp );
  mul1_out <= mul1_tmp(7 downto 0);
  M2: multiplier2 port map ( clk, reg_a, reg_b, mul2_tmp );
  mul2_out <= mul2_tmp(7 downto 0);
  M3: multiplier3 port map ( clk, reg_a, reg_b, mul3_tmp );
  mul3_out <= mul3_tmp(7 downto 0);
  M4: multiplier4 port map ( clk, reg_a, reg_b, mul4_tmp );
  mul4_out <= mul4_tmp(7 downto 0);
  M5: multiplier5 port map ( clk, reg_a, reg_b, mul5_tmp );
  mul5_out <= mul5_tmp(9 downto 2);
  mul6_out <= mul5_tmp(7 downto 0);
  M7: multiplier7 port map ( clk, reg_a, reg_b, mul7_tmp );
  mul7_out <= mul7_tmp(9 downto 2);

  -- Display selectors & decoders
  DC0: decoder port map ( not SW1_1, not SW1_2, not SW1_3, not SW1_4,
                          LED_A, LED_F, LED_B, LED_G, LED_E, LED_C, LED_D );
  process (sw1, reg_a, reg_b, reg_add, reg_sub,
           mul1_out, mul2_out, mul3_out, mul4_out, mul5_out,
           mul6_out, mul7_out, reg_mul0, dec1_out, dec2_out)
    variable led_unused: boolean;
  begin
    led_unused := false;
    case sw1 is
    when "0000" =>  dec_bf <= reg_a;
    when "0001" =>  dec_bf <= reg_b;
    when "0010" =>  dec_bf <= reg_add;
    when "0011" =>  dec_bf <= reg_sub;
    when "1000" =>  dec_bf <= reg_mul0;
    when "1001" =>  dec_bf <= mul1_out;
    when "1010" =>  dec_bf <= mul2_out;
    when "1011" =>  dec_bf <= mul3_out;
    when "1100" =>  dec_bf <= mul4_out;
    when "1101" =>  dec_bf <= mul5_out;
    when "1110" =>  dec_bf <= mul6_out;
    when "1111" =>  dec_bf <= mul7_out;
    when others =>  dec_bf <= "00000000";  led_unused := true;
    end case;
    if  led_unused  then    led1_bf <= "0001000";  led2_bf <= "0001000";
    else                    led1_bf <= dec1_out;   led2_bf <= dec2_out;
    end if;
  end process;

  dec1_in <= std_logic_vector(dec_bf(7 downto 4));
  DC1: decoder port map ( dec1_in(3), dec1_in(2), dec1_in(1), dec1_in(0),
                          dec1_out(0), dec1_out(1), dec1_out(2), dec1_out(3),
                          dec1_out(4), dec1_out(5), dec1_out(6) );
  LED1_A <= led1_bf(0);  LED1_F <= led1_bf(1);  LED1_B <= led1_bf(2);
  LED1_G <= led1_bf(3);  LED1_E <= led1_bf(4);  LED1_C <= led1_bf(5);
  LED1_D <= led1_bf(6);

  dec2_in <= std_logic_vector(dec_bf(3 downto 0));
  DC2: decoder port map ( dec2_in(3), dec2_in(2), dec2_in(1), dec2_in(0),
                          dec2_out(0), dec2_out(1), dec2_out(2), dec2_out(3),
                          dec2_out(4), dec2_out(5), dec2_out(6) );
  LED2_A <= led2_bf(0);  LED2_F <= led2_bf(1);  LED2_B <= led2_bf(2);
  LED2_G <= led2_bf(3);  LED2_E <= led2_bf(4);  LED2_C <= led2_bf(5);
  LED2_D <= led2_bf(6);

  -- Buttons & unused outputs
  BAR_4 <= not SW2;  BAR_5 <= not SW3;
  BAR_6 <= not PB1;  BAR_7 <= not PB2;  BAR_8 <= not PB3;  BAR_9 <= not PB4; 

  LED_DP <= '0';  LED1_DP <= '0';  BAR_10 <= '0';

end architecture top_level;
