⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 uart.vhd

📁 Toplevel VHDL Structural model of a system containing 8051
💻 VHD
📖 第 1 页 / 共 2 页
字号:

    -- assumes that shift happens at the rollovers
    if tf1_16'event and tf1_16 = 0 then
      case i is
        when 0 => txd_wr <= '0';        -- start bit
        when 9 => txd_wr <= tb8;        -- 9th bit
        when 10 => txd_wr <= '1';       -- stop bit
                   ti_set <= '1';
        when 11 => to_send := '0';      -- time to stop
        when others => txd_wr <= sbuf_dup(i-1);         -- shift the byte out
      end case;
      i := i+1;
    end if;

  when others => null;

  end case;

end if;

end process;

-- process to receive data from outside
-- reception start conditions:
-- for mode 0 the condition is ri = '0' and ren = '1'
-- for other modes the condition is ren = '1' and falling edge of rxd
process (sm_r(2 downto 1), cycle_state, rf1_16, p2clk_16, rxd)

variable i : integer := 0;              -- iteration counter
variable samp1, samp2, samp3, rcvd_bit : std_logic;
variable sbuf_dup : byte;               -- internal buffer for sbuf
-- indicate whether reception is in session
variable rcv_in_session : std_logic := '0';

begin

-- if sm_r(2 downto 1) is changed, clear the current process
if sm_r(2 downto 1)'event then rcv_in_session := '0'; end if;

case sm_r(2 downto 1) is

  when "00" =>

    -- mode 0, 8-bit shift register, Fxtal1/12
    -- shift clock is output through txd
    -- shift clock is low during s3, s4, s5, high during s6, s1, s2
    -- actual data is sampled in through rxd during s5p2

  if cycle_state'event and ri = '0' and ren = '1' then
    if rcv_in_session = '0' then        -- initiate reception
      rcv_in_session := '1';
      i := 0;
      ri_set <= '0';    -- lower ri_set signal to create an edge later
    else                                -- already in reception
      case cycle_state is
        when s1p1 => if i = 9 then      -- time to stop
                        sbuf_rd <= sbuf_dup;
                        ri_set <= '1';  -- set ri
                        rcv_in_session := '0';
                     end if;
        when s3p1 => if i /= 0 then txd_rd <= '0'; end if;
        -- assume that ri is cleared after s5p2 in the cycle
        when s5p2 => if i /= 0 then sbuf_dup(i-1) := rxd; end if;
                     i := i + 1;
        when s6p1 => if i /= 0 then txd_rd <= '1'; end if;
        when others => null;
      end case;
    end if;
  end if;

  when "01" =>

    -- mode 1, 8-bit UART, baud rate set by timer 1

    -- we can change this falling edge detection into sampling
    if falling_edge(rxd) and (ren = '1') and (rcv_in_session = '0') then
      rcv_in_session := '1';
      rf1_16_reset <= '1';      -- reset the counter immediately
      i := 0;
      rb8_set <= '0';
      rb8_reset <= '0';
      ri_set <= '0';
    end if;

    if rf1_16'event and (rcv_in_session = '1') then
      case rf1_16 is
      when 7 => samp1 := rxd;           -- first sample
      when 8 => samp2 := rxd;           -- second sample
      when 9 =>
        samp3 := rxd;           -- third sample

        -- take the value which appears at least twice, for noise rejection
        if samp1 = samp2 or samp2 = samp3 then rcvd_bit := samp2;
        else rcvd_bit := samp1;
        end if;

        if i = 0 then                   -- start bit
          if rcvd_bit /= '0' then       -- false start bit, start over
            rcv_in_session := '0';
            rf1_16_reset <= '0';
          end if;
        elsif i = 9 then                -- stop bit
          -- two conditions to meet for successful reception completion
          if ri = '0' and (sm_r(0) = '0' or rcvd_bit = '1') then
            sbuf_rd <= sbuf_dup;
            -- save rcvd_bit in rb8
            if rcvd_bit = '1' then rb8_set <= '1';
            else rb8_reset <= '1';
            end if;
            ri_set <= '1';
          end if;
          rcv_in_session := '0';
          rf1_16_reset <= '0';
        else sbuf_dup(i-1) := rcvd_bit; -- data bits
        end if;

        i := i + 1;
      when others => null;
      end case;
    end if;

  when "10" =>

    -- mode 2, 9-bit UART, Fxtal1/64 or Fxtal1/32

    -- we can change this falling edge detection into sampling
    if falling_edge(rxd) and (ren = '1') and (rcv_in_session = '0') then
      rcv_in_session := '1';
      p2clk_16_reset <= '1';    -- reset the counter
      i := 0;
      rb8_set <= '0';
      rb8_reset <= '0';
      ri_set <= '0';
    end if;

    if p2clk_16'event and (rcv_in_session = '1') then
      case p2clk_16 is
      when 7 => samp1 := rxd;           -- first sample
      when 8 => samp2 := rxd;           -- second sample
      when 9 =>
        samp3 := rxd;           -- third sample

        -- take the value which appears at least twice, for noise rejection
        if samp1 = samp2 or samp2 = samp3 then rcvd_bit := samp2;
        else rcvd_bit := samp1;
        end if;

        if i = 0 then                   -- start bit
          if rcvd_bit /= '0' then       -- false start bit, start over
            rcv_in_session := '0';
            p2clk_16_reset <= '0';
          end if;
        elsif i = 9 then                -- stop bit
          -- two conditions to meet for successful reception completion
          if ri = '0' and (sm_r(0) = '0' or rcvd_bit = '1') then
            sbuf_rd <= sbuf_dup;
            -- save rcvd_bit in rb8
            if rcvd_bit = '1' then rb8_set <= '1';
            else rb8_reset <= '1';
            end if;
            ri_set <= '1';
          end if;
          rcv_in_session := '0';
          p2clk_16_reset <= '0';
        else sbuf_dup(i-1) := rcvd_bit; -- data bits
        end if;

        i := i + 1;
      when others => null;
      end case;
    end if;

  when "11" =>

    -- mode 3, 9-bit UART, baud rate set by timer 1

    -- we can change this falling edge detection into sampling
    if falling_edge(rxd) and (ren = '1') and (rcv_in_session = '0') then
      rcv_in_session := '1';
      rf1_16_reset <= '1';      -- reset the counter
      i := 0;
      rb8_set <= '0';
      rb8_reset <= '0';
      ri_set <= '0';
    end if;

    if rf1_16'event and (rcv_in_session = '1') then
      case rf1_16 is
      when 7 => samp1 := rxd;           -- first sample
      when 8 => samp2 := rxd;           -- second sample
      when 9 =>
        samp3 := rxd;           -- third sample

        -- take the value which appears at least twice, for noise rejection
        if samp1 = samp2 or samp2 = samp3 then rcvd_bit := samp2;
        else rcvd_bit := samp1;
        end if;

        if i = 0 then                   -- start bit
          if rcvd_bit /= '0' then       -- false start bit, start over
            rcv_in_session := '0';
            rf1_16_reset <= '0';
          end if;
        elsif i = 9 then                -- stop bit
          -- two conditions to meet for successful reception completion
          if ri = '0' and (sm_r(0) = '0' or rcvd_bit = '1') then
            sbuf_rd <= sbuf_dup;
            -- save rcvd_bit in rb8
            if rcvd_bit = '1' then rb8_set <= '1';
            else rb8_reset <= '1';
            end if;
            ri_set <= '1';
          end if;
          rcv_in_session := '0';
          rf1_16_reset <= '0';
        else sbuf_dup(i-1) := rcvd_bit; -- data bits
        end if;

        i := i + 1;
      when others => null;
      end case;
    end if;

  when others => null;

end case;

end process;

-- the rxd signal has got two drivers: outside and transmitter
-- in mode 0 both can drive rxd
-- in other modes only outside drives rxd
-- when transmitter is not driving it outputs 'H'

-- process to resolve the txd signal
-- it's got two drivers: transmitter and receiver
-- in mode 0 both transmitter and receiver can drive txd
-- in other modes only transmitter drives txd
-- when one is not driving txd, it outputs '1'
txd <= txd_wr and txd_rd;

-- process to generate the divide-by-16 counter of timer 1 overflow signal
-- the clock of this counter is 16 times slower than the timer 1 overflow signal
-- we don't know in which cycle_state tf1 will be set
-- so have to synchronize it with s1p1
process (tf1, cycle_state, tf1_16_reset, rf1_16_reset)
variable tf1_flag : bit := '0';
variable tf1_half : bit := '0';
begin

-- rising edge of tf1_16_reset clears the counter
-- could be level-triggered
if rising_edge(tf1_16_reset) then tf1_16 <= 0; end if;
if rising_edge(rf1_16_reset) then rf1_16 <= 0; end if;

--if rising_edge(tf1) then tf1_flag := '1'; end if;

--if cycle_state'event and cycle_state = s1p1 and tf1_flag = '1' then
if rising_edge(tf1) then
  if smod = '0' then                    -- cut the frequency in half
    tf1_half := not tf1_half;
  end if;

  if not (smod = '0' and tf1_half = '1') then   -- increment the counter
    tf1_16 <= (tf1_16 + 1) mod 16;
    rf1_16 <= (rf1_16 + 1) mod 16;
    --tf1_flag := '0';
  end if;
end if;

end process;

-- process to generate the divide-by-16 counter of the phase 2 clock
-- phase 2 clock is twice as slow as the xtal1 clock
process (p2clk, p2clk_16_reset)
variable p2clk_half : bit := '0';
begin

-- rising edge of p2clk_16_reset clears the counter
-- could be level-triggered
if rising_edge(p2clk_16_reset) then p2clk_16 <= 0; end if;

-- it could be rising edge depending on how it aligns with cycle_state
if falling_edge(p2clk) then
  if smod = '0' then            -- cut the frequency in half
    p2clk_half := not p2clk_half;
  end if;

  if not (smod = '0' and p2clk_half = '1') then -- increment the counter
    p2clk_16 <= (p2clk_16 + 1) mod 16;
  end if;
end if;

end process;

end behave;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -