📄 uart.vhd
字号:
-- 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 typeslibrary 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 UARTlibrary 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 UARTentity 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 issignal 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? -MRMalias 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 bufferssignal 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 clocksubtype 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';beginsbuf_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 instructionprocess beginwait 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 instructionPROCESS BEGINIF 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 pulseprocess 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 instructionprocess beginwait 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 instructionprocess beginwait 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 acknowacknow <= acknow_wr or acknow_rd;-- transmitter process-- initiated by rising edge of write_to_sbuf generated when CPU writes to sbufprocess (sm_r(2 downto 1), write_to_sbuf, cycle_state, tf1_16, p2clk_16)variable i : integer := 0; -- iteration countervariable sbuf_dup : byte := all_0; -- internal buffer for sbufvariable to_send, no_start : bit := '0';begin-- if sm_r(2 downto 1) is changed, clear the current processif 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 laterend 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 + -