------------------------------------------------------------------------- -- HD-6402 UART Model -- Author: Matt Pennybacker ------------------------------------------------------------------------- -- Notes: -- Transmitter implements 1.5 stop bits at 2 bits -- FE and DR are asserted as the Recieve Buffer Register is latched -- OE, PE, and FE are latched until the next byte is recieved -- TRE is high for 1 clock cycle between successive bytes instead of 1/2 -- Settings other than 8N1 are untested ------------------------------------------------------------------------- -- Library Functions ------------------------------------------------------------------------- library ieee; use ieee.std_logic_1164.all; package hd6402_lib is function parity(inputs: std_logic_vector(7 downto 0)) return std_logic; end hd6402_lib; package body hd6402_lib is function parity(inputs: std_logic_vector(7 downto 0)) return std_logic is variable temp: std_logic; begin temp := '0'; for i in 7 downto 0 loop temp := temp xor inputs(i); end loop; return temp; end parity; end hd6402_lib; ------------------------------------------------------------------------- -- Receiver Description ------------------------------------------------------------------------- library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.std_logic_unsigned.all; use work.hd6402_lib.all; entity receiver is port( MR: in std_logic; RRC: in std_logic; RRI: in std_logic; SFD: in std_logic; RRD: in std_logic; DRR: in std_logic; CRL: in std_logic; CTRLWORD: in std_logic_vector(4 downto 0); OE: out std_logic; PE: out std_logic; FE: out std_logic; DR: out std_logic; RBR: out std_logic_vector(7 downto 0) ); end receiver; architecture behavior of receiver is signal CTRLWORD_reg: std_logic_vector(4 downto 0); signal OE_sig, PE_sig, FE_sig, DR_sig: std_logic; signal DR_set: std_logic; signal BUFFER_reg: std_logic_vector(7 downto 0); signal RECEIVE_reg: std_logic_vector(10 downto 0); signal active: std_logic; begin -- asynchronous assignments OE <= OE_sig when SFD = '0' else 'Z'; PE <= PE_sig when SFD = '0' else 'Z'; FE <= FE_sig when SFD = '0' else 'Z'; DR <= DR_sig when SFD = '0' else 'Z'; RBR <= BUFFER_reg when RRD = '0' else "ZZZZZZZZ"; -- load control register on CRL = '1' CTRLWORD_reg <= CTRLWORD when CRL = '1'; -- manage RECEIVE_reg, PE_sig, FE_sig process(active, MR) begin if MR = '1' then PE_sig <= '0'; FE_sig <= '0'; elsif falling_edge(active) then case CTRLWORD_reg(4 downto 2) is -- 5 bits, no parity when "001" => BUFFER_reg <= "000" & RECEIVE_reg(9 downto 5); -- 5 bits, parity when "000" => BUFFER_reg <= "000" & RECEIVE_reg(8 downto 4); -- 6 bits, no parity when "011" => BUFFER_reg <= "00" & RECEIVE_reg(9 downto 4); -- 6 bits, parity when "010" => BUFFER_reg <= "00" & RECEIVE_reg(8 downto 3); -- 7 bits, no parity when "101" => BUFFER_reg <= '0' & RECEIVE_reg(9 downto 3); -- 7 bits, parity when "100" => BUFFER_reg <= '0' & RECEIVE_reg(8 downto 2); -- 8 bits, no parity when "111" => BUFFER_reg <= RECEIVE_reg(9 downto 2); -- 8 bits, parity when "110" => BUFFER_reg <= RECEIVE_reg(8 downto 1); end case; if parity(BUFFER_reg) = '1' and CTRLWORD(2 downto 1) = "01" then PE_sig <= '1'; elsif parity(BUFFER_reg) = '0' and CTRLWORD(2 downto 1) = "00" then PE_sig <= '1'; else PE_sig <= '0'; end if; if RECEIVE_reg(10) /= '1' then FE_sig <= '1'; else FE_sig <= '0'; end if; end if; end process; -- manage DR_sig process(DR_set, DRR, MR) begin if MR = '1' then DR_sig <= '0'; elsif DR_set = '1' and DR_sig = '0' then DR_sig <= '1'; elsif falling_edge(DRR) then DR_sig <= '0'; end if; end process; -- receiver control process(RRC, MR) variable clock16: integer range 0 to 15; begin if MR = '1' then active <= '0'; OE_sig <= '0'; elsif rising_edge(RRC) then DR_set <= '0'; -- begin receiving a new character if active = '0' and RRI = '0' then clock16 := 0; active <= '1'; RECEIVE_reg <= "11111111111"; elsif active = '1' and clock16 = 7 then RECEIVE_reg <= RRI & RECEIVE_reg(10 downto 1); clock16 := clock16 + 1; elsif clock16 = 15 then clock16 := 0; else clock16 := clock16 + 1; end if; case CTRLWORD_reg(4 downto 2) is -- 5 bits, no parity when "001" => if active = '1' and RECEIVE_reg(4) = '0' then active <= '0'; DR_set <= '1'; end if; -- 5 bits, parity -- 6 bits, no parity when "000"|"011" => if active = '1' and RECEIVE_reg(3) = '0' then if DR_sig = '1' then OE_sig <= '1'; else OE_sig <= '0'; end if; active <= '0'; DR_set <= '1'; end if; -- 6 bits, parity -- 7 bits, no parity when "010"|"101" => if active = '1' and RECEIVE_reg(2) = '0' then if DR_sig = '1' then OE_sig <= '1'; else OE_sig <= '0'; end if; active <= '0'; DR_set <= '1'; end if; -- 7 bits, parity -- 8 bits, no parity when "100"|"111" => if active = '1' and RECEIVE_reg(1) = '0' then if DR_sig = '1' then OE_sig <= '1'; else OE_sig <= '0'; end if; active <= '0'; DR_set <= '1'; end if; -- 8 bits, parity when "110" => if active = '1' and RECEIVE_reg(0) = '0' then if DR_sig = '1' then OE_sig <= '1'; else OE_sig <= '0'; end if; active <= '0'; DR_set <= '1'; end if; end case; end if; end process; end behavior; ------------------------------------------------------------------------- -- Transmitter Description ------------------------------------------------------------------------- library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.std_logic_unsigned.all; use work.hd6402_lib.all; entity transmitter is port( MR: in std_logic; TRC: in std_logic; TBRL: in std_logic; SFD: in std_logic; CRL: in std_logic; CTRLWORD: in std_logic_vector(4 downto 0); TBR: in std_logic_vector(7 downto 0); TRE: out std_logic; TBRE: out std_logic; TRO: out std_logic ); end transmitter; architecture behavior of transmitter is signal CTRLWORD_reg: std_logic_vector(4 downto 0); signal BUFFER_reg: std_logic_vector(7 downto 0); signal BUFFER_parity: std_logic; signal TRANSMIT_reg: std_logic_vector(11 downto 0); signal TRANSMIT_latch: std_logic; signal TRE_sig, TBRE_sig, TRE_reset, TBRE_reset: std_logic; shared variable count: integer range 0 to 11; shared variable last_bit: integer range 6 to 11; begin -- asynchronous assignments TBRE <= TBRE_sig when SFD = '0' else 'Z'; TRE <= TRE_sig; TRO <= TRANSMIT_reg(count) when TRE_sig = '0' else '1'; -- load control register on CRL = '1' CTRLWORD_reg <= CTRLWORD when CRL = '1'; -- manage TBRE, BUFFER_reg process(TBRL, MR, TBRE_reset) begin if MR = '1' then TBRE_sig <= '1'; elsif TBRE_sig = '0' and TBRE_reset = '1' then TBRE_sig <= '1'; elsif rising_edge(TBRL) then BUFFER_reg <= TBR; TBRE_sig <= '0'; end if; end process; -- manage TRE, TRANSMIT_reg process(TRANSMIT_latch, MR, TRE_reset) begin if MR = '1' then TRE_sig <= '1'; elsif TRE_sig = '0' and TRE_reset = '1' then TRE_sig <= '1'; elsif rising_edge(TRANSMIT_latch) then BUFFER_parity <= parity(BUFFER_reg); case CTRLWORD_reg is -- 5 bits, no parity, 1 stop bit when "00100"|"00110" => TRANSMIT_reg <= "11111" & '1' & BUFFER_reg(4 downto 0) & '0'; last_bit := 6; -- 5 bits, parity, 1 stop bit when "00000"|"00010" => TRANSMIT_reg <= "1111" & '1' & BUFFER_parity & BUFFER_reg(4 downto 0) & '0'; last_bit := 7; -- 5 bits, no parity, 1.5 stop bits when "00101"|"00111" => TRANSMIT_reg <= "1111" & "11" & BUFFER_reg(4 downto 0) & '0'; last_bit := 7; -- 5 bits, parity, 1.5 stop bits when "00001"|"00011" => TRANSMIT_reg <= "111" & "11" & BUFFER_parity & BUFFER_reg(4 downto 0) & '0'; last_bit := 8; -- 6 bits, no parity, 1 stop bit when "01100"|"01110" => TRANSMIT_reg <= "1111" & '1' & BUFFER_reg(5 downto 0) & '0'; last_bit := 7; -- 6 bits, parity, 1 stop bit when "01000"|"01010" => TRANSMIT_reg <= "111" & '1' & BUFFER_parity & BUFFER_reg(5 downto 0) & '0'; last_bit := 8; -- 6 bits, no parity, 2 stop bits when "01101"|"01111" => TRANSMIT_reg <= "111" & "11" & BUFFER_reg(5 downto 0) & '0'; last_bit := 8; -- 6 bits, parity, 2 stop bits when "01001"|"01011" => TRANSMIT_reg <= "11" & "11" & BUFFER_parity & BUFFER_reg(5 downto 0) & '0'; last_bit := 9; -- 7 bits, no parity, 1 stop bit when "10100"|"10110" => TRANSMIT_reg <= "111" & '1' & BUFFER_reg(6 downto 0) & '0'; last_bit := 8; -- 7 bits, parity, 1 stop bit when "10000"|"10010" => TRANSMIT_reg <= "11" & '1' & BUFFER_parity & BUFFER_reg(6 downto 0) & '0'; last_bit := 9; -- 7 bits, no parity, 2 stop bits when "10101"|"10111" => TRANSMIT_reg <= "11" & "11" & BUFFER_reg(6 downto 0) & '0'; last_bit := 9; -- 7 bits, parity, 2 stop bits when "10001"|"10011" => TRANSMIT_reg <= "1" & "11" & BUFFER_parity & BUFFER_reg(6 downto 0) & '0'; last_bit := 10; -- 8 bits, no parity, 1 stop bit when "11100"|"11110" => TRANSMIT_reg <= "11" & '1' & BUFFER_reg(7 downto 0) & '0'; last_bit := 9; -- 8 bits, parity, 1 stop bit when "11000"|"11010" => TRANSMIT_reg <= "1" & '1' & BUFFER_parity & BUFFER_reg(7 downto 0) & '0'; last_bit := 10; -- 8 bits, no parity, 2 stop bits when "11101"|"11111" => TRANSMIT_reg <= "1" & "11" & BUFFER_reg(7 downto 0) & '0'; last_bit := 10; -- 8 bits, parity, 2 stop bits when "11001"|"11011" => TRANSMIT_reg <= "11" & BUFFER_parity & BUFFER_reg(7 downto 0) & '0'; last_bit := 11; end case; TRE_sig <= '0'; end if; end process; -- transmitter control process(TRC) variable clock16: integer range 0 to 15; begin if rising_edge(TRC) then TRE_reset <= '0'; if clock16 /= 15 then clock16 := clock16 + 1; else clock16 := 0; count := count + 1; end if; if TRE_sig = '1' and TBRE_sig = '0' then TRANSMIT_latch <= '1'; TBRE_reset <= '1'; clock16 := 0; count := 0; else TRANSMIT_latch <= '0'; TBRE_reset <= '0'; end if; if clock16 = 15 and count = last_bit then TRE_reset <= '1'; end if; end if; end process; end behavior; ------------------------------------------------------------------------- -- Top Level Description ------------------------------------------------------------------------- library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.std_logic_unsigned.all; use work.hd6402_lib.all; entity hd6402 is port( MR: in std_logic; TRC: in std_logic; TBRL: in std_logic; SFD: in std_logic; CRL: in std_logic; RRC: in std_logic; RRI: in std_logic; RRD: in std_logic; DRR: in std_logic; CLS2: in std_logic; CLS1: in std_logic; PI: in std_logic; EPE: in std_logic; SBS: in std_logic; TBR: in std_logic_vector(7 downto 0); TRE: out std_logic; TBRE: out std_logic; TRO: out std_logic; OE: out std_logic; PE: out std_logic; FE: out std_logic; DR: out std_logic; RBR: out std_logic_vector(7 downto 0) ); end hd6402; architecture structure of hd6402 is component receiver port( MR: in std_logic; RRC: in std_logic; RRI: in std_logic; SFD: in std_logic; RRD: in std_logic; DRR: in std_logic; CRL: in std_logic; CTRLWORD: in std_logic_vector(4 downto 0); OE: out std_logic; PE: out std_logic; FE: out std_logic; DR: out std_logic; RBR: out std_logic_vector(7 downto 0) ); end component; component transmitter port( MR: in std_logic; TRC: in std_logic; TBRL: in std_logic; SFD: in std_logic; CRL: in std_logic; CTRLWORD: in std_logic_vector(4 downto 0); TBR: in std_logic_vector(7 downto 0); TRE: out std_logic; TBRE: out std_logic; TRO: out std_logic ); end component; signal CTRLWORD: std_logic_vector(4 downto 0); begin CTRLWORD(4) <= CLS2; CTRLWORD(3) <= CLS1; CTRLWORD(2) <= PI; CTRLWORD(1) <= EPE; CTRLWORD(0) <= SBS; U1: transmitter port map(MR,TRC,TBRL,SFD,CRL,CTRLWORD,TBR,TRE,TBRE,TRO); U2: receiver port map(MR,RRC,RRI,SFD,RRD,DRR,CRL,CTRLWORD,OE,PE,FE,DR,RBR); end structure;