----------------------------------------------------------------------------------
-- Company: 
-- Engineer: 
-- 
-- Create Date:    
-- Design Name: 
-- Module Name:    ASCIIToBin - Behavioral 
-- Project Name: 
-- Target Devices: 
-- Tool versions: 
-- Description: 
--
-- Dependencies: 
--
-- Revision: 
-- Revision 0.01 - File Created
-- Additional Comments: 
--
----------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

-- This code converts the sign_char and 4 ASCII digits into a binary value when
-- start_convert is asserted. It saves the values into registers, performs the
-- conversion and then asserts convert_done_tick for one clock cycle when completed
entity ASCIIToBin is
   port(
      clk: in std_logic;
      reset: in std_logic;
      ready, convert_done_tick: out std_logic;
      start_convert: in std_logic;
      op_binary_val: out std_logic_vector(11 downto 0);
      dig0, dig1, dig2, dig3: in std_logic_vector(7 downto 0);
      sign_char : in std_logic_vector(7 downto 0)
   );
end ASCIIToBin;


ARCHITECTURE beh of ASCIIToBin is
   type state_type is (idle, convert, done);
   signal state_reg, state_next: state_type;
   signal A_reg0, A_next0 : std_logic_vector(7 downto 0);
   signal A_reg1, A_next1 : std_logic_vector(7 downto 0);
   signal A_reg2, A_next2 : std_logic_vector(7 downto 0);
   signal A_reg3, A_next3 : std_logic_vector(7 downto 0);

-- Need to make this 1-bit larger to prevent large positive numbers
-- for example > 2047 from becoming negative and converted to two's
-- complement. I'm debugging this so I'm guessing -- the problem I'm
-- having could be related to the timing violation and this may work 
-- just fine with 12 bits, e.g., (11 downto 0). 
   signal binary_reg, binary_next : signed(12 downto 0);
   signal cnt_reg, cnt_next : unsigned(1 downto 0);
   signal operand_sign_reg, operand_sign_next : std_logic;

   begin

-- state and register logic
   process(clk, reset)
      begin
      if (reset = '1') then
         state_reg <= idle;
         binary_reg <= to_signed(0, 13);
         cnt_reg <= to_unsigned(0, 2);
         A_reg0 <= std_logic_vector(to_unsigned(character'pos('#'), 8));
         A_reg1 <= std_logic_vector(to_unsigned(character'pos('#'), 8));
         A_reg2 <= std_logic_vector(to_unsigned(character'pos('#'), 8));
         A_reg3 <= std_logic_vector(to_unsigned(character'pos('#'), 8));
         operand_sign_reg <= '0';
      elsif (clk'event and clk = '1') then
         state_reg <= state_next;
         binary_reg <= binary_next;
         cnt_reg <= cnt_next;
         A_reg0 <= A_next0;
         A_reg1 <= A_next1;
         A_reg2 <= A_next2;
         A_reg3 <= A_next3;
         operand_sign_reg <= operand_sign_next;
      end if; 
   end process;

-- Combo logic for state machine, iteration cnter and shift operations in data path
   process(state_reg, binary_reg, cnt_reg, A_reg0, A_reg1, A_reg2, A_reg3, start_convert, sign_char, operand_sign_reg,
      dig0, dig1, dig2, dig3)
      variable tmp : signed(25 downto 0);		
      begin
      ready <= '0';
      convert_done_tick <= '0';
      state_next <= state_reg;
      binary_next <= binary_reg;
      cnt_next <= cnt_reg;
      A_next0 <= A_reg0;
      A_next1 <= A_reg1;
      A_next2 <= A_reg2;
      A_next3 <= A_reg3;
      operand_sign_next <= operand_sign_reg;

      case state_reg is
         when idle =>

-- set output 'ready' in idle state -- otherwise, we are carrying out a binary number of ASCII translation
            ready <= '1';
            if (start_convert = '1') then

-- clear binary register
               binary_next <= (others => '0');

-- Latch the ascii data on the inputs
               A_next0 <= dig0;
               A_next1 <= dig1;
               A_next2 <= dig2;
               A_next3 <= dig3;

-- set sign flag -- use 1 for negative and 0 for positive
               if ( sign_char = std_logic_vector(to_unsigned(character'pos('-'), 8)) ) then
                  operand_sign_next <= '1';
               else
                  operand_sign_next <= '0';
               end if;

-- initialize cnter
               cnt_next <= to_unsigned(0, 2);

-- start conversion
               state_next <= convert;
            end if;

-- Conversion from ASCII to binary is easier than the opposite operation -- just involves multiplication
-- dig0 has low order digit and dig3 has high order
         when convert =>
            cnt_next <= cnt_reg + 1;

-- If user hit fewer than 4 characters before hitting enter, skip this byte
            if ( cnt_reg = 0 and signed(A_reg3) /= 0 ) then
               binary_next <= "00000" & (signed(A_reg3) - character'pos('0'));
            end if;

-- If user hit fewer than 3 characters before hitting enter, skip this byte
            if ( cnt_reg = 1 and signed(A_reg2) /= 0 ) then
               tmp := 10*binary_reg;
               binary_next <= tmp(12 downto 0) + ("00000" & (signed(A_reg2) - character'pos('0')));
            end if;
            if ( cnt_reg = 2 and signed(A_reg1) /= 0 ) then
	       tmp := 10*binary_reg;
               binary_next <= tmp(12 downto 0) + ("00000" & (signed(A_reg1) - character'pos('0')));
            end if;
            if ( cnt_reg = 3 and signed(A_reg0) /= 0 ) then
               tmp := 10*binary_reg;
-- Invert the number (2's compliment) if sign bit is 1 (negative number)
               if ( operand_sign_reg = '1' ) then
                  binary_next <= -(tmp(12 downto 0) + ("00000" & (signed(A_reg0) - character'pos('0'))));
               else
                  binary_next <= tmp(12 downto 0) + ("00000" & (signed(A_reg0) - character'pos('0')));
               end if;
               state_next <= done;
            end if;
         when done =>
            state_next <= idle;
            convert_done_tick <= '1';
      end case;
   end process;

   op_binary_val <= std_logic_vector(binary_reg(11 downto 0));

end beh;
