]> rtime.felk.cvut.cz Git - fpga/uart.git/blobdiff - uart.vhd
Early initialization of all relevant signals.
[fpga/uart.git] / uart.vhd
index a5999089a11135173158276724b9db9ee5b7e5f8..09450f91f1bc0ada7428853220b7ad17ca45573b 100644 (file)
--- a/uart.vhd
+++ b/uart.vhd
@@ -5,41 +5,25 @@ use ieee.std_logic_unsigned.all;
 
 entity uart is
   generic (
-    output_fifo_width : integer := 2
+    output_fifo_width : integer := 2;
+    input_fifo_width  : integer := 2
   );
   port (
     mclk        : in  std_logic;
-    per_addr    : in  std_logic_vector (7  downto 0);
-    per_din     : in  std_logic_vector (15 downto 0);  -- unused
+    per_addr    : in  std_logic_vector (7 downto 0);
+    per_din     : in  std_logic_vector (15 downto 0);
     per_en      : in  std_logic;
-    per_wen     : in  std_logic_vector (1  downto 0);  -- unused
-    puc         : in  std_logic;                       -- unused
-    --per_irq_acc : in  std_logic;                       -- unused
-    --per_irq     : out std_logic;
+    per_wen     : in  std_logic_vector (1 downto 0);
+    puc         : in  std_logic;
+    per_irq_acc : in  std_logic;
+    per_irq     : out std_logic;
     per_dout    : out std_logic_vector (15 downto 0);
 
+    rxd         : in  std_logic;
     txd         : out std_logic
   );
 end uart;
 
--- Registers:
---  - Prescaler .16b
---  - Modulator .8b
---  - TX data .8b
---  - TX enable
---  - TX buffer full .1b
---  - TX buffer empty .1b
---  - TX buffer empty IE 1.b
---  - RX data .8b
---  - RX enable
---  - RX buffer empty .1b
---  - RX buffer half full .1b
---  - RX buffer full .1b
---  - RX buffer half full IE .1b
---  - RX buffer full IE .1b
---  - RX framing error .1b
---  - RX buffer overflow .1b
-
 --------------------------------------------------------------------------------
 
 architecture dataflow of uart is
@@ -66,6 +50,34 @@ architecture dataflow of uart is
     );
   end component;
 
+  component rx_control is
+    port (
+      clk           : in  std_logic;
+      reset         : in  std_logic;
+      rx            : in  std_logic;
+      bad_start_bit : in  std_logic;
+      bad_stop_bit  : in  std_logic;
+      rx_ready      : in  std_logic;
+      rx_reset      : out std_logic;
+      rx_en         : out std_logic;
+      fifo_we       : out std_logic;
+      clk_en        : out std_logic
+    );
+  end component rx_control;
+
+  component receiver is
+    port (
+      clk           : in  std_logic;
+      reset         : in  std_logic;
+      en            : in  std_logic;
+      rx            : in  std_logic;
+      ready         : out std_logic;
+      bad_start_bit : out std_logic;
+      bad_stop_bit  : out std_logic;
+      data          : out std_logic_vector (7 downto 0)
+    );
+  end component receiver;
+  
   component fifo is
     generic (
       width : integer := 2
@@ -88,47 +100,82 @@ architecture dataflow of uart is
   component baud_gen is
     port (
       clk      : in  std_logic;
+      ce       : in  std_logic;
       reset    : in  std_logic;
-      scale    : in std_logic_vector (15 downto 0);
-      clk_baud : out  std_logic
+      scale    : in  std_logic_vector (15 downto 0);
+      clk_baud : out std_logic
     );
   end component;
 
 --------------------------------------------------------------------------------
 
+  alias per_din_low  : std_logic_vector (7 downto 0) is per_din (7 downto 0);
+  alias per_din_high : std_logic_vector (7 downto 0) is per_din (15 downto 8);
+  
   type boolean_vector is array (natural range <>) of boolean;
 
 --------------------------------------------------------------------------------
   
   constant base_addr : integer := 16#0100#;
   
-  constant UBAUD : integer := base_addr + 00;
-  constant UTX   : integer := base_addr + 02;
+  constant UBAUD : integer := base_addr + 00;  -- 2B - Baud rate generator
+  constant UTX   : integer := base_addr + 02;  -- 1B - Transmit data
+  constant URX   : integer := base_addr + 04;  -- 1B - Read data
+  constant USTAT : integer := base_addr + 06;  -- 1B - Rx & Tx status
+  constant UIE   : integer := base_addr + 07;  -- 1B - Interrupt enable
 
-  signal reg_we : std_logic_vector (511 downto 0);
-  signal reg_re : boolean_vector (511 downto 0);
+  signal reg_we   : std_logic_vector (511 downto 0);
+  signal reg_re   : std_logic_vector (511 downto 0);
+  signal reg_re_b : boolean_vector (512 downto 0);
 
-  signal tx_clk : std_logic;
-  signal tx_data : std_logic_vector (7 downto 0);
-  signal tx_we : std_logic;
-  signal tx_ready : std_logic;
+  
+  signal reg_baud : std_logic_vector (15 downto 0) := (others => '0');
+  signal reg_stat : std_logic_vector (7 downto 0);
+  signal reg_ie   : std_logic_vector (7 downto 0) := (others => '0');
 
+  
+  signal tx_clk        : std_logic;
+  signal tx_data       : std_logic_vector (7 downto 0);
+  signal tx_we         : std_logic;
+  signal tx_ready      : std_logic;
+  signal tx_fifo_full  : std_logic;
+  signal tx_fifo_hfull : std_logic;
   signal tx_fifo_empty : std_logic;
-  signal tx_fifo_re : std_logic;
-  signal tx_fifo_we : std_logic;
+  signal tx_fifo_re    : std_logic;
 
+  signal rx_clk           : std_logic;
+  signal rx_clk_en        : std_logic;
+  signal rx_en            : std_logic;
+  signal rx_ready         : std_logic;
+  signal rx_reset         : std_logic;
+  signal rx_data          : std_logic_vector (7 downto 0);
+  signal rx_bad_start_bit : std_logic;
+  signal rx_bad_stop_bit  : std_logic;
+  signal rx_fifo_we       : std_logic;
+  signal rx_fifo_out      : std_logic_vector (7 downto 0);
+  signal rx_fifo_full     : std_logic;
+  signal rx_fifo_hfull    : std_logic;
+  signal rx_fifo_empty    : std_logic;
+  signal rx_fifo_ow       : std_logic;
+  signal rx_fifo_ow_clear : std_logic;
+  
 --------------------------------------------------------------------------------
 
 begin
 
+  -- Address decoder
   process (per_addr, per_wen, per_en)
   begin
     for i in reg_re'range loop
-      reg_re (i) <= false;
-      reg_we (i) <= '0';
+      reg_re_b (i) <= false;
+      reg_re (i)   <= '0';
+      reg_we (i)   <= '0';
       
       if (per_en = '1' and per_addr = i/2) then
-        reg_re (i) <= true;
+        -- Register of the corresponding address is always read, so
+        -- read-modify-write operation in one cycle is possible.
+        reg_re_b (i) <= true;
+        reg_re (i)   <= '1';
         
         if (per_wen (i mod 2) = '1') then
           reg_we (i) <= '1';
@@ -137,6 +184,9 @@ begin
     end loop;
   end process;
   
+--------------------------------------------------------------------------------
+-- TX MODULE
+--------------------------------------------------------------------------------
 
   tx_control_0 : tx_control port map (
     clk        => mclk,
@@ -147,7 +197,7 @@ begin
     fifo_pop   => tx_fifo_re
   );
 
-  transmitter_0 : transmitter port map (
+  tx_transmitter_0 : transmitter port map (
     clk    => tx_clk,
     reset  => puc,
     data   => tx_data,
@@ -156,31 +206,125 @@ begin
     tx     => txd
   );
 
-  tx_fifo : fifo port map (
+  tx_fifo_0 : fifo port map (
     clk      => mclk,
     reset    => puc,
-    we       => tx_fifo_we,
+    we       => reg_we (UTX),
     re       => tx_fifo_re,
     clear_ow => '0',
     d_in     => per_din (7 downto 0),
     d_out    => tx_data,
-    full     => open,
-    hfull    => open,
+    full     => tx_fifo_full,
+    hfull    => tx_fifo_hfull,
     empty    => tx_fifo_empty,
     overflow => open
-  );
+    );
 
-  baud_gen_0 : baud_gen port map (
+  tx_baud_gen_0 : baud_gen port map (
     clk      => mclk,
+    ce       => '1',
     reset    => puc,
-    scale    => "0000000000000000",
+    scale    => reg_baud,
     clk_baud => tx_clk
-  );
+    );
+
+--------------------------------------------------------------------------------
+-- RX MODULE
+--------------------------------------------------------------------------------
 
+  rx_control_0 : rx_control
+    port map (
+      clk           => mclk,
+      reset         => puc,
+      rx            => rxd,
+      bad_start_bit => rx_bad_start_bit,
+      bad_stop_bit  => rx_bad_stop_bit,
+      rx_ready      => rx_ready,
+      rx_reset      => rx_reset,
+      rx_en         => rx_en,
+      fifo_we       => rx_fifo_we,
+      clk_en        => rx_clk_en);
 
+  rx_receiver_0 : receiver
+    port map (
+      clk           => rx_clk,
+      reset         => puc,
+      en            => rx_en,
+      rx            => rxd,
+      ready         => rx_ready,
+      bad_start_bit => rx_bad_start_bit,
+      bad_stop_bit  => rx_bad_stop_bit,
+      data          => rx_data);
+
+  rx_fifo_0 : fifo
+    port map (
+      clk      => mclk,
+      reset    => puc,
+      we       => rx_fifo_we,
+      re       => reg_re (URX),
+      clear_ow => rx_fifo_ow_clear,
+      d_in     => rx_data,
+      d_out    => rx_fifo_out,
+      full     => rx_fifo_full,
+      hfull    => rx_fifo_hfull,
+      empty    => rx_fifo_empty,
+      overflow => rx_fifo_ow);
+
+  rx_baud_gen_0 : baud_gen
+    port map (
+      clk      => mclk,
+      ce       => rx_clk_en,
+      reset    => puc,
+      scale    => reg_baud,
+      clk_baud => rx_clk);
+  
 --------------------------------------------------------------------------------
+-- OTHER LOGIC
+--------------------------------------------------------------------------------
+  
+  process (mclk, puc) is
+  begin
+    if puc = '1' then
+      reg_baud <= (others => '0');
+      reg_ie   <= (others => '0');
+      
+    elsif mclk'event and mclk = '1' then
+      if reg_we (UBAUD) = '1' then
+        reg_baud (7 downto 0) <= per_din_low;
+      end if;
+
+      if reg_we (UBAUD+1) = '1' then
+        reg_baud (15 downto 8) <= per_din_high;
+      end if;
 
-  tx_fifo_we <= reg_we (UTX);
+      if reg_we (USTAT) = '1' then
+        reg_ie <= per_din_low;
+      end if;
+    end if;
+  end process;
+
+
+  reg_stat <= tx_fifo_empty &
+              tx_fifo_hfull &
+              tx_fifo_full &
+              not rx_fifo_empty &
+              rx_fifo_hfull &
+              rx_fifo_full &
+              rx_fifo_ow &
+              '0';
+
+  
+  per_irq <= '1' when (reg_stat and reg_ie and "10011100") /= "00000000" else '0' ;
+
+  per_dout <= reg_baud                 when reg_re_b (UBAUD) else
+              "00000000" & tx_data     when reg_re_b (UTX) else
+              "00000000" & rx_fifo_out when reg_re_b (URX) else
+              reg_ie & reg_stat        when reg_re_b (USTAT) else
+              (others => '0');
+  
+--------------------------------------------------------------------------------
+  
+  rx_fifo_ow_clear <= per_din (1) and reg_we (USTAT);
   
 end dataflow;