OpenCores
URL https://opencores.org/ocsvn/artec_dongle_ii_fpga/artec_dongle_ii_fpga/trunk

Subversion Repositories artec_dongle_ii_fpga

[/] [artec_dongle_ii_fpga/] [trunk/] [src/] [serial_usb/] [serial_usb.vhd] - Rev 9

Compare with Previous | Blame | View Log

library ieee;
use ieee.std_logic_1164.all;
use IEEE.std_logic_unsigned.all;
use IEEE.std_logic_arith.all;
use work.serial_usb_package.all;
use work.dongle_arch.all;
 
 
entity serial_usb is
	port(
		clock		: in  std_logic;
		reset_n		: in  std_logic;
		--VCI Port
		vci_in		: in vci_slave_in;
		vci_out		: out vci_slave_out;
		--FTDI fifo interface
		uart_ena	: in usbser_ctrl;
		fifo_out	: out usb_out;
		fifo_in		: in usb_in
	);
end entity serial_usb;
 
architecture rtl of serial_usb is
 
	type reg_type is
	record
		uart	 	: uart_registers;
		fifo		: usb_out;
		fifo_sync: usb_in;
		vci		: vci_slave_out;
		pc_loop  :  boolean;
		vci_write_pending :  boolean;
		vci_read_pending :  boolean;
		tx_timer :  std_logic_vector(2 downto 0);
		rx_timer :  std_logic_vector(2 downto 0);
		ftdi_precharge :  std_logic_vector(2 downto 0);	--time between cycles
	end record;
 
	signal reg, reg_in : reg_type;
 
begin
 
	-- Design pattern process 1 Implementation 
	comb : process (vci_in,uart_ena,reg)
			variable reg_v : reg_type;
		begin
			-- Design pattern 
			reg_v:=reg; --pre set default var state
 
 
			--
			--Debug code send repeating "0123456789" to UART
			--
--			if reg_v.uart.lsr.reg(SEL_LSR_EMPTY_TXH)='1' then
--				reg_v.uart.lsr.reg(SEL_LSR_EMPTY_TXH):='0';  --set TX filled
--				reg_v.uart.txhold.reg(3 downto 0):= reg_v.uart.txhold.reg(3 downto 0)+1;
--				if reg_v.uart.txhold.reg(3 downto 0)=x"A" then
--					reg_v.uart.txhold.reg(3 downto 0):=x"0";
--				end if;
--				reg_v.uart.txhold.reg(7 downto 4):=x"3";
--			end if;
 
			------------------------------------
			---  <implementation>			---
			------------------------------------
 
 
			--reduce precharge counter always
			if reg_v.ftdi_precharge>"000" then
				reg_v.ftdi_precharge:=reg_v.ftdi_precharge - 1;
			end if;
 
			--VCI write access request			
			if vci_in.lpc_val='1' and vci_in.lpc_wr='1' and reg_v.vci.lpc_ack='0'  then
				reg_v.vci_write_pending:=true;
			end if;			
 
			--VCI read access request
			if vci_in.lpc_val='1' and vci_in.lpc_wr='0' and reg_v.vci.lpc_ack='0' then
				reg_v.vci_read_pending:=true;
			end if;			
 
			--Writable conf registers
			if reg_v.vci_write_pending then --write decode			
				case vci_in.lpc_addr(2 downto 0) is
					when "000" => 
						--select DLAB or not
						if reg_v.uart.lcr.reg(SEL_LCR_DLAB)='0' then --Line Control Register (LCR) SEL_LCR_DLAB   
							reg_v.uart.txhold.reg:=vci_in.lpc_data_o;  --Transmitter Holding Buffer
							clr_uart_tx_int(reg_v.uart); --clear tx on tx buff write
							if reg_v.uart.mcr.reg(SEL_MCR_LOOP)='0'  then --loop not endabled
								reg_v.uart.lsr.reg(SEL_LSR_EMPTY_TXH):='0'; -- TX not empty
								reg_v.uart.lsr.reg(SEL_LSR_EMPTY_DH):='0'; -- TX not empty
							else --do local loop
								reg_v.uart.rxbuff.reg:=reg_v.uart.txhold.reg;
								reg_v.uart.lsr.reg(SEL_LSR_DATARDY):='1'; --set data ready in register
								set_uart_rx_int(reg_v.uart);								
							end if;
						else
							reg_v.uart.div_low.reg:=vci_in.lpc_data_o; --Divisor Latch Low Byte
						end if;			
					when "001" => 
						--select DLAB or not
						if reg_v.uart.lcr.reg(SEL_LCR_DLAB)='0' then --Line Control Register (LCR) SEL_LCR_DLAB   
							reg_v.uart.ier.reg:=vci_in.lpc_data_o; --Interrupt Enable Register
						else
							reg_v.uart.div_high.reg:=vci_in.lpc_data_o; --Divisor Latch High Byte
						end if;
					when "011" => -- +3
						reg_v.uart.lcr.reg:=vci_in.lpc_data_o; --Line Control Register (don't care except DLA bit)
					when "100" => -- +4
						reg_v.uart.mcr.reg:=vci_in.lpc_data_o; --Modem Control Register (don't care except loopback)
						reg_v.uart.mcr.reg(SEL_MCR_FLWCTRL):='0'; --this is not supported so auto clear
					when "111" => -- +7
						reg_v.uart.scr.reg:=vci_in.lpc_data_o;
					when others =>
						null;
				end case;
				--we must ack the write always
				reg_v.vci_write_pending:= false;
				reg_v.vci.lpc_ack:='1'; --ack all writes to non writable addresses for VCI to work
			end if;
 
			--Readable conf registers
			if reg_v.vci_read_pending then --write decode			
				case vci_in.lpc_addr(2 downto 0) is
					when "000" =>
						--select DLAB or not
						if reg_v.uart.lcr.reg(SEL_LCR_DLAB)='0' then --Line Control Register (LCR) SEL_LCR_DLAB   
							reg_v.vci.lpc_data_i:=reg_v.uart.rxbuff.reg; --RX read data
							reg_v.uart.lsr.reg(SEL_LSR_DATARDY):='0'; --data has been read
							clr_uart_rx_int(reg_v.uart);
						else
							reg_v.vci.lpc_data_i:=reg_v.uart.div_low.reg;
						end if;	
					when "001" =>
						if reg_v.uart.lcr.reg(SEL_LCR_DLAB)='0' then --Interrupt Enable Register (IER) SEL_LCR_DLAB  
							reg_v.vci.lpc_data_i:=reg_v.uart.ier.reg;
						else --Divisor Latch High Byte
							reg_v.vci.lpc_data_i:=reg_v.uart.div_high.reg;
						end if;
					when "010" =>
							reg_v.vci.lpc_data_i:=reg_v.uart.iir.reg; -- Interrupt Identification Register(IIR)
							clr_uart_tx_int(reg_v.uart); --clear tx on iir read
					when "011" =>
							reg_v.vci.lpc_data_i:=reg_v.uart.lcr.reg;		
					when "100" =>
							reg_v.vci.lpc_data_i:=reg_v.uart.mcr.reg;		
					when "101" =>
							reg_v.vci.lpc_data_i:=reg_v.uart.lsr.reg;		
					when "110" =>
							reg_v.vci.lpc_data_i:=reg_v.uart.msr.reg;
					when "111" =>
							reg_v.vci.lpc_data_i:=reg_v.uart.scr.reg;																		
					when others => 
						reg_v.vci.lpc_data_i:=(others=>'0'); -- return 0
				end case;
				--we must ack the read always
				reg_v.vci_read_pending:= false;
				reg_v.vci.lpc_ack:='1'; --ack all reads to non readable addresses for VCI to work					 							
			end if;			
 
			--UART Register state change handling
			--TX haldler
			if reg_v.fifo.rx_oe_n='1' and reg_v.ftdi_precharge="000" and reg_v.fifo_sync.tx_empty_n='0' and reg_v.tx_timer="000" and reg_v.uart.lsr.reg(SEL_LSR_EMPTY_TXH)='0' then --No ongoing read and can and has something to TX
				reg_v.fifo.txdata:=reg_v.uart.txhold.reg;
				reg_v.fifo.tx_wr:='1';
				reg_v.tx_timer:="011"; --FDTI fifo timing 40 ns needed for write pulse high
			end if;
			if reg_v.tx_timer>"000" then -- TX cycle timer
				reg_v.tx_timer:=reg_v.tx_timer-1;
				if reg_v.tx_timer="000" then
					reg_v.fifo.tx_wr:='0'; -- write happens on falling edge '''\,,,
					reg_v.ftdi_precharge:="011"; --start cycle cap
					reg_v.uart.lsr.reg(SEL_LSR_EMPTY_TXH):='1'; -- all sent
					reg_v.uart.lsr.reg(SEL_LSR_EMPTY_DH):='1'; -- ready for new data
					set_uart_tx_int(reg_v.uart);
				end if;
			end if;
			--RX Handler
 
 
			if (not reg_v.pc_loop) or reg_v.uart.lsr.reg(SEL_LSR_EMPTY_TXH)='1' then	
				if reg_v.fifo.tx_wr='0'and reg_v.ftdi_precharge="000" and reg_v.fifo_sync.rx_full_n='0' and reg_v.rx_timer="000" and reg_v.uart.lsr.reg(SEL_LSR_DATARDY)='0' then -- no ongoing TX and data in FTDI fifo and read buffer has been read
					reg_v.fifo.rx_oe_n:='0'; -- output enable
					reg_v.rx_timer:="100";
				end if;
				if reg_v.rx_timer>"000" then --RX cycle timer
					reg_v.rx_timer:=reg_v.rx_timer-1;
					if reg_v.rx_timer="000" then
						reg_v.fifo.rx_oe_n:='1'; -- read happens on rising front  ,,,,/'''' of oe_n
						reg_v.ftdi_precharge:="101"; --start cycle cap
						reg_v.uart.rxbuff.reg:=reg_v.fifo_sync.rxdata;
						if reg_v.pc_loop then --pc test loop
							reg_v.uart.txhold.reg:=reg_v.fifo_sync.rxdata;
							reg_v.uart.lsr.reg(SEL_LSR_EMPTY_TXH):='0'; --do transmit
						else
							reg_v.uart.lsr.reg(SEL_LSR_DATARDY):='1'; --set data ready in register
							set_uart_rx_int(reg_v.uart);
						end if;
					end if;
				end if;
			end if;
 
			--UART Interrupt
			if reg_v.uart.iir.reg(SEL_IIR_PENDING_N)='0' then
				reg_v.vci.lpc_irq:='1'; --set up int signal
			else
				reg_v.vci.lpc_irq:='0';
			end if;
			--End UART
 
			--VCI request end, clear ack when val drops			
			if vci_in.lpc_val='0' and reg_v.vci.lpc_ack='1'  then
				reg_v.vci.lpc_ack:='0';
			end if;			
 
 
			-- Design pattern 
			-- drive register input signals
			reg_in<=reg_v;
			-- drive module outputs signals
			--port_comb_out<= reg_v.port_comb;  --combinatorial output
			--port_reg_out<= reg.port_reg; --registered output
			vci_out<=reg.vci;
			fifo_out<= reg.fifo;			
		end process;
 
	-- Pattern process 2, Registers
	regs : process (clock,reset_n)
		begin
			if reset_n='0' then
				reg.pc_loop<=false;
				reg.rx_timer<=(others=>'0');
				reg.tx_timer<=(others=>'0');
				reg.ftdi_precharge<=(others=>'0');
				reg.vci_read_pending<=false;
				reg.vci_write_pending<=false;				
				uart_reset(reg.uart);
				fifo_reset(reg.fifo);
				vci_slave_reset(reg.vci);
			elsif rising_edge(clock) then
				reg<=reg_in;
				reg.fifo_sync<=fifo_in;
			end if;
		end process;
 
 
end rtl;
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.