-----------------------------------------------------------------------------------------
-- uart transmit module
--
-----------------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;

entity uartTx is
  port ( clr       : in  std_logic;                    -- global reset input
         clk       : in  std_logic;                    -- global clock input
         ce16      : in  std_logic;                    -- baud rate multiplyed by 16 - generated by baud module
         txData    : in  std_logic_vector(7 downto 0); -- data byte to transmit
         newTxData : in  std_logic;                    -- asserted to indicate that there is a new data byte for transmission
         serOut    : out std_logic;                    -- serial data output
         txBusy    : out std_logic);                   -- signs that transmitter is busy
end uartTx;

architecture Behavioral of uartTx is

  signal iTxBusy  : std_logic;
  signal ce1      : std_logic; -- clock enable at bit rate
  signal count16  : std_logic_vector(3 downto 0);
  signal bitCount : std_logic_vector(3 downto 0);
  signal dataBuf  : std_logic_vector(8 downto 0);

  begin
    -- a counter to count 16 pulses of ce_16 to generate the ce_1 pulse
    process (clr, clk)
    begin
      if (clr = '1') then
        count16 <= (others => '0');
      elsif (rising_edge(clk)) then
        if ((iTxBusy = '1') and (ce16 = '1')) then
          count16 <= count16 + 1;
        elsif (iTxBusy = '0') then
          count16 <= (others => '0');
        end if;
      end if;
    end process;
    -- tx_busy flag
    process (clr, clk)
    begin
      if (clr = '1') then
        iTxBusy <= '0';
      elsif (rising_edge(clk)) then
        if ((iTxBusy = '0') and (newTxData = '1')) then
          iTxBusy <= '1';
        elsif ((iTxBusy = '1') and (bitCount = "1001") and (ce1 = '1')) then
          iTxBusy <= '0';
        end if;
      end if;
    end process;
    -- output bit counter
    process (clr, clk)
    begin
      if (clr = '1') then
        bitCount <= (others => '0');
      elsif (rising_edge(clk)) then
        if ((iTxBusy = '1') and (ce1 = '1')) then
          bitCount <= bitCount + 1;
        elsif (iTxBusy = '0') then
          bitCount <= (others => '0');
        end if;
      end if;
    end process;
    -- data shift register
    process (clr, clk)
    begin
      if (clr = '1') then
        dataBuf <= (others => '0');
      elsif (rising_edge(clk)) then
        if (iTxBusy = '0') then
          dataBuf <= txData & '0';
        elsif ((iTxBusy = '1') and (ce1 = '1')) then
          dataBuf <= '1' & dataBuf(8 downto 1);
        end if;
      end if;
    end process;
    -- output data bit
    process (clr, clk)
    begin
      if (clr = '1') then
        serOut <= '1';
      elsif (rising_edge(clk)) then
        if (iTxBusy = '1') then
          serOut <= dataBuf(0);
        else
          serOut <= '1';
        end if;
      end if;
    end process;
    -- ce_1 pulse indicating output data bit should be updated
    ce1 <= '1' when ((count16 = "1111") and (ce16 = '1')) else '0';
    txBusy <= iTxBusy;
  end Behavioral;
