----------------------------------------------------------------------------------
-- Company: 
-- Engineer: 
-- 
-- Create Date:    
-- Design Name: 
-- Module Name:    BinToASCII - 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;

entity BinToASCII is
   port(
      clk:in std_logic;
      reset:in std_logic;
      ready, convert_done_tick: out std_logic;
      start_convert: in std_logic;
      result_binary_val: in std_logic_vector(11 downto 0);
      dig0, dig1, dig2, dig3: out std_logic_vector(7 downto 0);
      sign_char : out std_logic_vector(7 downto 0)
   );
end BinToASCII;

ARCHITECTURE beh of BinToASCII 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);
   signal binary_reg, binary_next : std_logic_vector(11 downto 0);
   signal cnt_reg, cnt_next : unsigned(1 downto 0);
   signal start_div, divider_avail, division_complete : std_logic;
   signal divisor, dividend  : std_logic_vector(11 downto 0);
   signal quo, rmd : std_logic_vector(11 downto 0);
   signal rmd_ascii : std_logic_vector(7 downto 0);
   signal binary_val_pos : std_logic_vector(11 downto 0);
   signal operand_sign_reg, operand_sign_next : std_logic;

   begin

-- instantiate divider
   DividerComponent: entity work.Divider(beh)
      generic map (DIV_WIDTH=>12, ITER_REG_WIDTH=>4)
      port map (clk=>clk, reset=>reset, start=>start_div, dvsr=>divisor, dvnd=>dividend,
         ready=>divider_avail, done_tick=>division_complete, quo=>quo, rmd=>rmd);

-- state and register logic
   process(clk, reset)
      begin
      if (reset = '1') then
         state_reg <= idle;
         binary_reg <= (others => '0');
         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;

-- Connect divisor to constant decimal 10 and dividend to binary_reg, which is updated after
-- each successive division by 10
   divisor <= std_logic_vector(to_unsigned(10, 12));
   dividend <= binary_reg; 

-- Make the number positive if incoming operand has sign bit set -- assume we are in 2's compliment
-- Actual sign bit is saved in register in idle state below. binary_val_pos value is actually latched into
-- binary_reg below
   with result_binary_val(11) select
      binary_val_pos <= result_binary_val when '0',
                        std_logic_vector(unsigned(NOT result_binary_val) + 1) when others;

-- Combo logic for state machine, iteration cnter and shift operations in data path
   process(state_reg, binary_reg, cnt_reg, start_div, divisor, dividend, divider_avail, division_complete, 
      quo, rmd_ascii, A_reg0, A_reg1, A_reg2, A_reg3, start_convert, result_binary_val, binary_val_pos, operand_sign_reg) 
      begin
      ready <= '0';
      convert_done_tick <= '0';
      state_next <= state_reg;
      binary_next <= binary_reg;
      cnt_next <= cnt_reg;
      start_div <= '0';
      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

-- latch binary value to convert
               binary_next <= binary_val_pos;

-- Save high order (sign) bit of operand
               operand_sign_next <= result_binary_val(11);

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

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

-- divider_avail becomes 1 AFTER the division_complete pulse used below. For one clock cycle, 
-- make start_div a '1' to start the division state machine
            if ( divider_avail = '1' ) then
               start_div <= '1';
            end if;

-- Wait for the divider to complete it's operation, save results -- this is a one-clk cycle pulse
            if ( division_complete = '1' ) then
               cnt_next <= cnt_reg + to_unsigned(1, 2);

-- Put quotient into binary register for next iteration
               binary_next <= quo;

-- Load up the ASCII values into the 4 registers

               if ( cnt_reg = to_unsigned(0, 2) ) then
                  A_next0 <= rmd_ascii;
               end if;
               if ( cnt_reg = to_unsigned(1, 2) ) then
                  A_next1 <= rmd_ascii; 
               end if;
               if ( cnt_reg = to_unsigned(2, 2) ) then
                  A_next2 <= rmd_ascii; 
               end if;

-- If we have converted all four bytes, we are done.
               if ( cnt_reg = to_unsigned(3, 2) ) then
                  A_next3 <= rmd_ascii; 
                  state_next <= done;
               end if;
            end if;
         when done =>
            state_next <= idle;
            convert_done_tick <= '1';
      end case;
   end process;

-- Convert remainder into an ascii char by adding 48 (the ASCII value for char '0')
   rmd_ascii <= std_logic_vector(unsigned(rmd(7 downto 0)) + to_unsigned(character'pos('0'), 8));

   with operand_sign_reg select
      sign_char <= std_logic_vector(to_unsigned(character'pos('+'), 8)) when '0',
                   std_logic_vector(to_unsigned(character'pos('-'), 8)) when others;
   dig0 <= A_reg0;
   dig1 <= A_reg1;
   dig2 <= A_reg2;
   dig3 <= A_reg3;
end beh;
