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

📄 uart.vhd

📁 Toplevel VHDL Structural model of a system containing 8051
💻 VHD
📖 第 1 页 / 共 2 页
字号:
-- EE301B Semester Project, Winter 1998
-- 8051 UART (Universal Asynchronous Receiver/Transmitter) model

-- Source : Intel 8051 Family Microprocessors Manual

-- Author : Lingfeng Yuan, Prajakta Kurvey

-- Revision history:

-- 04/05
-- Started writing the code for the UART

-- 04/08
-- implemented the transmission and reception of mode 0 and 1
-- still a lot of errors and assumptions

-- 04/09
-- finished mode 2 and 3
-- looks correct except for the assumptions

-- 19/09
-- changed the divide-by-16 counters

-- 23/09
-- changed the transmitter and receiver processes to be sentitive to a list
-- eliminated all wait statements in them
-- eliminated all bus contention problems

-- package to define some types
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;

package mc8051_UART_pkg is
  subtype byte is unsigned (7 downto 0);
  constant sbuf_addr : byte := "10011001";
  constant scon_addr : byte := "10011000";
  constant all_0 : byte := "00000000";
  constant hi_imp : byte := "ZZZZZZZZ";

-- the following type is used to break up the machine cycle
-- into 6 states, with 2 pulses for each state
-- copied from Mayer's program
--  type machine_cycle_states is (init, s1p1, s1p2, s2p1, s2p2, s3p1, s3p2,
--s4p1, s4p2, s5p1, s5p2, s6p1, s6p2);

end mc8051_UART_pkg;

-- main program for the UART
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use work.mc8051_UART_pkg.all;
use work.pack8051.all;

-- these are the interface signals for our stand-alone UART
entity mc8051_UART is
  port (
        cycle_state : in machine_cycle_states;
        p2clk : in std_logic;           -- phase 2 clock
        addr_gb : in byte;              -- global address bus
        data_gb : inout byte := hi_imp; -- global data bus
        rd_gb : in std_logic;           -- global read signal, active high
        wr_gb : in std_logic;           -- global write signal, active high
        indirect_sel : in std_logic;    -- direct or indirect address mode
        tf1 : in std_logic := '0';      -- tf1 is the timer 1 overflow flag
        smod : in std_logic := '0';     -- smod is pcon.7
        scon_out : out byte;                 -- serial port control SFR
        sbuf_out : out byte;
        rxd : inout std_logic := 'H';
        txd : out std_logic := '1';

        acknow : out std_logic := 'L');
end entity;

architecture behave of mc8051_UART is

signal to_send, write_to_sbuf : std_logic := '0';

-- serial control - should it be all_0 at default?
signal scon     : unsigned(7 DOWNTO 0) := (OTHERS => '0');
signal tb8_set, tb8_reset : std_logic := '0';
signal rb8_set, rb8_reset : std_logic := '0';
signal ti_set, ri_set : std_logic := '0';

-- some aliases to decompose scon
-- sm_r is reversed serial port mode  OR IS IT? -MRM
alias sm_r : unsigned (2 downto 0) is scon(7 downto 5);
alias ren : std_logic is scon(4);
alias tb8 : std_logic is scon(3);
alias rb8 : std_logic is scon(2);
alias ti : std_logic is scon(1);
alias ri : std_logic is scon(0);

-- serial port buffers
signal sbuf_wr, sbuf_rd : byte := all_0;

-- divide-by-16 counters and their reset signals (rising edge sensitive)
-- tf1_16 is for timer 1 overflow signal
-- p2clk_16 is for phase 2 clock
subtype cnt_type is natural range 0 to 16;
signal tf1_16, rf1_16, p2clk_16 : cnt_type := 0;
signal tf1_16_reset, rf1_16_reset, p2clk_16_reset : std_logic := '0';

signal acknow_wr, acknow_rd : std_logic := 'L';
signal txd_wr, txd_rd : std_logic := '1';

begin

sbuf_out <= sbuf_rd;
scon_out <= scon;

-- process to detect write_to_sbuf operation
-- we still need to verify the timing of the execution of the instruction
process begin
wait until wr_gb = '1';
if addr_gb = sbuf_addr and indirect_sel = '0' then      -- CPU writes to serial port
  sbuf_wr <= data_gb;
  to_send <= not to_send;
  wait for 2 ns;
  acknow_wr <= '1';
  wait until to_x01(wr_gb) = '0';
  acknow_wr <= 'L';
end if;
end process;

-- process to detect write_to_scon operation
-- we still need to verify the timing of the execution of the instruction
PROCESS BEGIN
IF tb8_set = '1' THEN
   scon(3) <= '1';
END IF;

IF tb8_reset = '1' THEN
   scon(3) <= '0';
END IF;

IF rb8_set = '1' THEN
   scon(2) <= '1';
END IF;

IF rb8_reset = '1' THEN
   scon(2) <= '1';
END IF;

IF ti_set = '1' THEN
   scon(1) <= '1';
END IF;

If ri_set = '1' THEN
   scon(0) <= '1';
END IF;

IF wr_gb = '1' THEN
  IF addr_gb = scon_addr and indirect_sel = '0' THEN    -- CPU writes to serial port
     scon <= data_gb;
     wait for 2 ns;
     acknow_wr <= '1';
     wait until to_x01(wr_gb) = '0';
     acknow_wr <= 'L';
  END IF;
END IF;

WAIT ON tb8_set, tb8_reset, rb8_set, rb8_reset, ti_set, ri_set, wr_gb;
--WAIT ON ti_set, ri_set, wr_gb;
END PROCESS;

-- we assume that the write_to_sbuf pulse always occurs in s6p2
-- process to align to_send with s6p2 and convert it to a pulse
process begin
  wait on to_send;
  wait until cycle_state = s6p2;
  write_to_sbuf <= '1';
  -- wait for a cycle state
  wait on cycle_state;
  write_to_sbuf <= '0';
end process;

-- process to detect read_from_sbuf operation
-- we still need to verify the timing of the execution of the instruction
process begin
wait until rd_gb = '1';
if addr_gb = sbuf_addr and indirect_sel = '0' then      -- CPU reads from serial port
  data_gb <= sbuf_rd;
  acknow_rd <= '1';
  wait until rd_gb = '0';
  data_gb <= hi_imp;
  acknow_rd <= 'L';
end if;
end process;

-- process to detect read_from_scon operation
-- we still need to verify the timing of the execution of the instruction
process begin
wait until rd_gb = '1';
if addr_gb = scon_addr and indirect_sel = '0' then      -- CPU reads from serial control
  data_gb <= scon;
  acknow_rd <= '1';
  wait until rd_gb = '0';
  data_gb <= hi_imp;
  acknow_rd <= 'L';
end if;
end process;



-- process to resolve acknow_wr and acknow_rd to get acknow
acknow <= acknow_wr or acknow_rd;

-- transmitter process
-- initiated by rising edge of write_to_sbuf generated when CPU writes to sbuf
process (sm_r(2 downto 1), write_to_sbuf, cycle_state, tf1_16, p2clk_16)

variable i : integer := 0;              -- iteration counter
variable sbuf_dup : byte := all_0;      -- internal buffer for sbuf
variable to_send, no_start : bit := '0';

begin

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

if rising_edge(write_to_sbuf) then      -- initiate transmission
  to_send := '1';       -- this signal means transmission in progress
  sbuf_dup := sbuf_wr;  -- fill internal buffer
  i := 0;               -- clear iteration counter
  no_start := '1';      -- still in the write_to_sbuf cycle, don't start
  ti_set <= '0';        -- lower the ti_set signal to create an edge later
end if;

if to_send = '1' then

-- sm_r is reversed sm
-- so mode 1 is "10", mode 2 is "01"   OR IS IT? -MRM
  case sm_r(2 downto 1) is

  when "00" =>

    -- mode 0, 8-bit shift register, Fxtal1/12 (one bit every machine cycle)
    -- shift clock is output through txd
    -- shift clock is low during s3, s4, s5, high during s6, s1, s2
    -- actual data is output through rxd

    if cycle_state'event then
      case cycle_state is
        when s1p1 => if i = 0 then no_start := '0';     -- start iteration
                     elsif i = 9 then                   -- time to stop
                        rxd <= 'H';
                        ti_set <= '1';
                        to_send := '0';
                     end if;
        when s3p1 => if i /= 0 then txd_wr <= '0'; end if;
        when s6p1 => if i /= 0 then txd_wr <= '1'; end if;
        when s6p2 => if no_start = '0' then
                        if i < 8 then rxd <= sbuf_dup(i); end if;
                        i := i + 1;
                     end if;
        when others => null;
      end case;
    end if;

  when "01" =>

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

    -- 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 <= '1';        -- 9th bit ('1')
                  -- not sure when ti goes high, 9 or 10
                  ti_set <= '1';
        when 10 => null;                -- stop bit, keep high
        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 "10" =>

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

    -- assumes that shift happens at the rollovers
    if p2clk_16'event and p2clk_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 "11" =>

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

⌨️ 快捷键说明

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