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

Subversion Repositories opb_usblite

[/] [opb_usblite/] [trunk/] [pcores/] [opb_usblite_v1_00_a/] [hdl/] [vhdl/] [usb_serial.vhdl] - Rev 2

Compare with Previous | Blame | View Log

--
--  USB 2.0 Serial data transfer entity
--
--  This entity implements a USB 2.0 device that carries a bidirectional
--  byte stream over the bus. It communicates with the host according to
--  the USB Communication Device Class, specifically the ACM (Abstract
--  Control Model) variant.
--
--  The low-level interface signals are labeled PHY_xxx and can be connected
--  to an UTMI-compliant PHY component. The PHY should be configured in 8-bit
--  mode.
--
--  The application interface supports simple byte-at-a-time sending and
--  receiving. Three block RAMs are used to implement a receive buffer,
--  a transmission buffer and descriptor ROM.
--
--  The CLK input must be the 60 MHz clock generated by the UTMI transceiver.
--  All application interface signals and PHY interface signals are
--  synchronized to the rising edge of CLK, except for SUSPEND which has
--  an asynchronous reset.
--
--  Transmission:
--    * The entity asserts TXRDY when it is ready to send data.
--    * The application puts data on TXDAT and asserts TXVAL when it is
--      ready to send data.
--    * In each clock cycle in which TXRDY and TXVAL are both asserted,
--      the entity takes a byte from TXDAT and queues it for transmission.
--
--  Receiving:
--    * The application asserts RXRDY when it is ready to receive data.
--    * The entity puts data on RXDAT and asserts RXVAL when it has
--      data available. It will only do this in response to RXRDY.
--    * When RXVAL is high, the application must either accept a byte
--      from RXDAT and be ready for the next byte in the following cycle,
--      or it must deassert RXRDY to pause the receive queue.
--
--  At power on, and after RESET, the device waits for 16 ms before
--  attaching to the USB bus. A high signal on ONLINE indicates that
--  the device has been fully configured by the host.
--
--  Bugs and limitations:
--    * The TEST_MODE feature (mandatory for high speed devices) is
--      not implemented and returns an error condition to the host.
--    * The SEND_ENCAPSULATED_COMMAND and GET_ENCAPSULATED_RESPONSE commands
--      (mandatory CDC-ACM requests) are not supported but will return a
--      success condition to the host.
--    * The default control pipe does not verify requests from the host
--      as strictly as required by the standard. As a result, invalid
--      requests from the host may sometimes appear to succeed when
--      they should have returned an error condition.
--
--  Implementation note:
--  At some point it may become useful to implement separate clock domains
--  for the application resp. PHY side of this entity, using the FIFO buffers
--  for clock domain crossing. As a first step, a distinction has been made
--  between application-side signals (prefixed with q_) and PHY-side signals
--  (prefixed with s_). Currently the corresponding signals from both sides
--  are simply wired together with asynchronous assignments. By replacing
--  these hardwired connections with carefully designed synchronization logic,
--  a separation of clock domains could be realized.
--
 
library ieee;
use ieee.std_logic_1164.all, ieee.numeric_std.all;
use work.usb_pkg.all;
 
entity usb_serial is
 
    generic (
 
        -- Vendor ID to report in device descriptor.
        VENDORID :      std_logic_vector(15 downto 0);
 
        -- Product ID to report in device descriptor.
        PRODUCTID :     std_logic_vector(15 downto 0);
 
        -- Product version to report in device descriptor.
        VERSIONBCD :    std_logic_vector(15 downto 0);
 
        -- Support high speed mode.
        HSSUPPORT :     boolean := false;
 
        -- Set to true if the device never draws power from the USB bus.
        SELFPOWERED :   boolean := false;
 
        -- Size of receive buffer as 2-logarithm of the number of bytes.
        -- Must be at least 10 (1024 bytes) for high speed support.
        RXBUFSIZE_BITS: integer range 7 to 12 := 11;
 
        -- Size of transmit buffer as 2-logarithm of the number of bytes.
        TXBUFSIZE_BITS: integer range 7 to 12 := 10 );
 
    port (
 
        -- 60 MHz UTMI clock.
        CLK :           in  std_logic;
 
        -- Synchronous reset; clear buffers and re-attach to the bus.
        RESET :         in  std_logic;
 
        -- High for one clock when a reset signal is detected on the USB bus.
        -- Note: do NOT wire this signal to RESET externally.
        USBRST :        out std_logic;
 
        -- High when the device is operating (or suspended) in high speed mode.
        HIGHSPEED :     out std_logic;
 
        -- High while the device is suspended.
        -- Note: This signal is not synchronized to CLK.
        -- It may be used to asynchronously drive the UTMI SuspendM pin.
        SUSPEND :       out std_logic;
 
        -- High when the device is in the Configured state.
        ONLINE :        out std_logic;
 
        -- High if a received byte is available on RXDAT.
        RXVAL :         out std_logic;
 
        -- Received data byte, valid if RXVAL is high.
        RXDAT :         out std_logic_vector(7 downto 0);
 
        -- High if the application is ready to receive the next byte.
        RXRDY :         in  std_logic;
 
        -- Number of bytes currently available in receive buffer.
        RXLEN :         out std_logic_vector((RXBUFSIZE_BITS-1) downto 0);
 
        -- High if the application has data to send.
        TXVAL :         in  std_logic;
 
        -- Data byte to send, must be valid if TXVAL is high.
        TXDAT :         in  std_logic_vector(7 downto 0);
 
        -- High if the entity is ready to accept the next byte.
        TXRDY :         out std_logic;
 
        -- Number of free byte positions currently available in transmit buffer.
        TXROOM :        out std_logic_vector((TXBUFSIZE_BITS-1) downto 0);
 
        -- Temporarily suppress transmissions at the outgoing endpoint.
        -- This gives the application an oppertunity to fill the transmit
        -- buffer in order to blast data efficiently in big chunks.
        TXCORK :        in  std_logic;
 
        PHY_DATAIN :    in  std_logic_vector(7 downto 0);
	PHY_DATAOUT :   out std_logic_vector(7 downto 0);
	PHY_TXVALID :   out std_logic;
	PHY_TXREADY :   in  std_logic;
	PHY_RXACTIVE :  in  std_logic;
	PHY_RXVALID :   in  std_logic;
	PHY_RXERROR :   in  std_logic;
	PHY_LINESTATE : in  std_logic_vector(1 downto 0);
	PHY_OPMODE :    out std_logic_vector(1 downto 0);
        PHY_XCVRSELECT: out std_logic;
        PHY_TERMSELECT: out std_logic;
	PHY_RESET :     out std_logic );
 
end entity usb_serial;
 
architecture usb_serial_arch of usb_serial is
 
    -- Byte array type
    type t_byte_array is array(natural range <>) of std_logic_vector(7 downto 0);
 
    -- Conditional expression.
    function choose_int(z: boolean; a, b: integer)
        return integer is
    begin
        if z then return a; else return b; end if;
    end function;
 
    -- Conditional expression.
    function choose_byte(z: boolean; a, b: std_logic_vector)
        return std_logic_vector is
    begin
        if z then return a; else return b; end if;
    end function;
 
    -- Maximum packet size according to protocol.
    constant MAX_FSPACKET_SIZE: integer := 64;
    constant MAX_HSPACKET_SIZE: integer := 512;
 
    -- Width required for a pointer that can cover either RX or TX buffer.
    constant BUFPTR_SIZE :  integer := choose_int(RXBUFSIZE_BITS > TXBUFSIZE_BITS, RXBUFSIZE_BITS, TXBUFSIZE_BITS);
 
    -- Data endpoint number.
    constant data_endpt :   std_logic_vector(3 downto 0) := "0001";
    constant notify_endpt : std_logic_vector(3 downto 0) := "0010";
 
    -- Descriptor ROM
    --   addr   0 ..  17 : device descriptor
    --   addr  20 ..  29 : device qualifier
    --   addr  32 ..  98 : full speed configuration descriptor 
    --   addr 112 .. 178 : high speed configuration descriptor
    --   addr 179 :        other_speed_configuration hack
    constant DESC_DEV_ADDR :        integer := 0;
    constant DESC_DEV_LEN  :        integer := 18;
    constant DESC_QUAL_ADDR :       integer := 20;
    constant DESC_QUAL_LEN :        integer := 10;
    constant DESC_FSCFG_ADDR :      integer := 32;
    constant DESC_FSCFG_LEN :       integer := 67;
    constant DESC_HSCFG_ADDR :      integer := 112;
    constant DESC_HSCFG_LEN :       integer := 67;
    constant DESC_OTHERSPEED_ADDR : integer := 179;
 
    constant descrom_pre: t_byte_array(0 to 191) :=
        -- 18 bytes device descriptor
      ( X"12",                  -- bLength = 18 bytes
        X"01",                  -- bDescriptorType = device descriptor
        choose_byte(HSSUPPORT, X"00", X"10"),   -- bcdUSB = 1.10 or 2.00
        choose_byte(HSSUPPORT, X"02", X"01"),
        X"02",                  -- bDeviceClass = Communication Device Class
        X"00",                  -- bDeviceSubClass = none
        X"00",                  -- bDeviceProtocol = none
        X"40",                  -- bMaxPacketSize0 = 64 bytes
        VENDORID(7 downto 0),   -- idVendor
        VENDORID(15 downto 8),
        PRODUCTID(7 downto 0),  -- idProduct
        PRODUCTID(15 downto 8),
        VERSIONBCD(7 downto 0), -- bcdDevice
        VERSIONBCD(15 downto 8),
        X"00",                  -- iManufacturer
        X"00",                  -- iProduct
        X"00",                  -- iSerialNumber
        X"01",                  -- bNumConfigurations = 1
        -- 2 bytes padding
        X"00", X"00",
        -- 10 bytes device qualifier
        X"0a",                  -- bLength = 10 bytes
        X"06",                  -- bDescriptorType = device qualifier
        X"00", X"02",           -- bcdUSB = 2.0
        X"02",                  -- bDeviceClass = Communication Device Class
        X"00",                  -- bDeviceSubClass = none
        X"00",                  -- bDeviceProtocol = none
        X"40",                  -- bMaxPacketSize0 = 64 bytes
        X"01",                  -- bNumConfigurations = 1
        X"00",                  -- bReserved
        -- 2 bytes padding
        X"00", X"00",
        -- 67 bytes full-speed configuration descriptor
        -- 9 bytes configuration header
        X"09",                  -- bLength = 9 bytes
        X"02",                  -- bDescriptorType = configuration descriptor
        X"43", X"00",           -- wTotalLength = 67 bytes
        X"02",                  -- bNumInterfaces = 2
        X"01",                  -- bConfigurationValue = 1
        X"00",                  -- iConfiguration = none
        choose_byte(SELFPOWERED, X"c0", X"80"), -- bmAttributes
        X"fa",                  -- bMaxPower = 500 mA
        -- 9 bytes interface descriptor (communication control class)
        X"09",                  -- bLength = 9 bytes
        X"04",                  -- bDescriptorType = interface descriptor
        X"00",                  -- bInterfaceNumber = 0
        X"00",                  -- bAlternateSetting = 0
        X"01",                  -- bNumEndpoints = 1
        X"02",                  -- bInterfaceClass = Communication Interface
        X"02",                  -- bInterfaceSubClass = Abstract Control Model
        X"01",                  -- bInterfaceProtocol = V.25ter (required for Linux CDC-ACM driver)
        X"00",                  -- iInterface = none
        -- 5 bytes functional descriptor (header)
        X"05",                  -- bLength = 5 bytes
        X"24",                  -- bDescriptorType = CS_INTERFACE
        X"00",                  -- bDescriptorSubtype = header
        X"10", X"01",           -- bcdCDC = 1.10
        -- 4 bytes functional descriptor (abstract control management)
        X"04",                  -- bLength = 4 bytes
        X"24",                  -- bDescriptorType = CS_INTERFACE
        X"02",                  -- bDescriptorSubtype = Abstract Control Mgmnt
        X"00",                  -- bmCapabilities = none
        -- 5 bytes functional descriptor (union)
        X"05",                  -- bLength = 5 bytes
        X"24",                  -- bDescriptorType = CS_INTERFACE
        X"06",                  -- bDescriptorSubtype = union
        X"00",                  -- bMasterInterface = 0
        X"01",                  -- bSlaveInterface0 = 1
        -- 5 bytes functional descriptor (call management)
        X"05",                  -- bLength = 5 bytes
        X"24",                  -- bDescriptorType = CS_INTERFACE
        X"01",                  -- bDescriptorSubType = Call Management
        X"00",                  -- bmCapabilities = no call mgmnt
        X"01",                  -- bDataInterface = 1
        -- 7 bytes endpoint descriptor (notify IN)
        X"07",                  -- bLength = 7 bytes
        X"05",                  -- bDescriptorType = endpoint descriptor
        X"82",                  -- bEndpointAddress = IN 2
        X"03",                  -- bmAttributes = interrupt data
        X"08", X"00",           -- wMaxPacketSize = 8 bytes
        X"ff",                  -- bInterval = 255 frames
        -- 9 bytes interface descriptor (data class)
        X"09",                  -- bLength = 9 bytes
        X"04",                  -- bDescriptorType = interface descriptor
        X"01",                  -- bInterfaceNumber = 1
        X"00",                  -- bAlternateSetting = 0
        X"02",                  -- bNumEndpoints = 2
        X"0a",                  -- bInterfaceClass = Data Interface
        X"00",                  -- bInterfaceSubClass = none
        X"00",                  -- bInterafceProtocol = none
        X"00",                  -- iInterface = none
	-- 7 bytes endpoint descriptor (data IN)
        X"07",                  -- bLength = 7 bytes
        X"05",                  -- bDescriptorType = endpoint descriptor
        X"81",                  -- bEndpointAddress = IN 1
        X"02",                  -- bmAttributes = bulk data
        X"40", X"00",           -- wMaxPacketSize = 64 bytes
        X"00",                  -- bInterval
        -- 7 bytes endpoint descriptor (data OUT)
        X"07",                  -- bLength = 7 bytes
        X"05",                  -- bDescriptorType = endpoint descriptor
        X"01",                  -- bEndpointAddress = OUT 1
        X"02",                  -- bmAttributes = bulk data
        X"40", X"00",           -- wMaxPacketSize = 64 bytes
        X"00",                  -- bInterval
        -- 13 bytes padding
        X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00",
        X"00", X"00", X"00", X"00", X"00",
        -- 67 bytes high-speed configuration descriptor
        -- 9 bytes configuration header
        X"09",                  -- bLength = 9 bytes
        X"02",                  -- bDescriptorType = configuration descriptor
        X"43", X"00",           -- wTotalLength = 67 bytes
        X"02",                  -- bNumInterfaces = 2
        X"01",                  -- bConfigurationValue = 1
        X"00",                  -- iConfiguration = none
        choose_byte(SELFPOWERED, X"c0", X"80" ), -- bmAttributes = self-powered
        X"fa",                  -- bMaxPower = 500 mA
        -- 9 bytes interface descriptor (communication control class)
        X"09",                  -- bLength = 9 bytes
        X"04",                  -- bDescriptorType = interface descriptor
        X"00",                  -- bInterfaceNumber = 0
        X"00",                  -- bAlternateSetting = 0
        X"01",                  -- bNumEndpoints = 1
        X"02",                  -- bInterfaceClass = Communication Interface
        X"02",                  -- bInterfaceSubClass = Abstract Control Model
        X"01",                  -- bInterfaceProtocol = V.25ter (required for Linux CDC-ACM driver)
        X"00",                  -- iInterface = none
        -- 5 bytes functional descriptor (header)
        X"05",                  -- bLength = 5 bytes
        X"24",                  -- bDescriptorType = CS_INTERFACE
        X"00",                  -- bDescriptorSubtype = header
        X"10", X"01",           -- bcdCDC = 1.10
        -- 4 bytes functional descriptor (abstract control management)
        X"04",                  -- bLength = 4 bytes
        X"24",                  -- bDescriptorType = CS_INTERFACE
        X"02",                  -- bDescriptorSubtype = Abstract Control Mgmnt
        X"00",                  -- bmCapabilities = none
        -- 5 bytes functional descriptor (union)
        X"05",                  -- bLength = 5 bytes
        X"24",                  -- bDescriptorType = CS_INTERFACE
        X"06",                  -- bDescriptorSubtype = union
        X"00",                  -- bMasterInterface = 0
        X"01",                  -- bSlaveInterface0 = 1
        -- 5 bytes functional descriptor (call management)
        X"05",                  -- bLength = 5 bytes
        X"24",                  -- bDescriptorType = CS_INTERFACE
        X"01",                  -- bDescriptorSubType = Call Management
        X"00",                  -- bmCapabilities = no call mgmnt
        X"01",                  -- bDataInterface = 1
        -- 7 bytes endpoint descriptor (notify IN)
        X"07",                  -- bLength = 7 bytes
        X"05",                  -- bDescriptorType = endpoint descriptor
        X"82",                  -- bEndpointAddress = IN 2
        X"03",                  -- bmAttributes = interrupt data
        X"08", X"00",           -- wMaxPacketSize = 8 bytes
        X"0f",                  -- bInterval = 2**14 frames
        -- 9 bytes interface descriptor (data class)
        X"09",                  -- bLength = 9 bytes
        X"04",                  -- bDescriptorType = interface descriptor
        X"01",                  -- bInterfaceNumber = 1
        X"00",                  -- bAlternateSetting = 0
        X"02",                  -- bNumEndpoints = 2
        X"0a",                  -- bInterfaceClass = Data Interface
        X"00",                  -- bInterfaceSubClass = none
        X"00",                  -- bInterafceProtocol = none
        X"00",                  -- iInterface = none
	-- 7 bytes endpoint descriptor (data IN)
        X"07",                  -- bLength = 7 bytes
        X"05",                  -- bDescriptorType = endpoint descriptor
        X"81",                  -- bEndpointAddress = IN 1
        X"02",                  -- bmAttributes = bulk data
        X"00", X"02",           -- wMaxPacketSize = 512 bytes
        X"00",                  -- bInterval
        -- 7 bytes endpoint descriptor (data OUT)
        X"07",                  -- bLength = 7 bytes
        X"05",                  -- bDescriptorType = endpoint descriptor
        X"01",                  -- bEndpointAddress = OUT 1
        X"02",                  -- bmAttributes = bulk data
        X"00", X"02",           -- wMaxPacketSize = 512 bytes
        X"00",                  -- bInterval = never NAK
        -- other_speed_configuration hack
        X"07",
        -- 12 bytes padding
        X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00",
        X"00", X"00", X"00", X"00" );
 
    constant descrom: t_byte_array(0 to (choose_int(HSSUPPORT, 191, 111))) :=
        descrom_pre(0 to choose_int(HSSUPPORT, 191, 111));
    signal descrom_start:   unsigned(choose_int(HSSUPPORT, 7, 6) downto 0);
    signal descrom_raddr:   unsigned(choose_int(HSSUPPORT, 7, 6) downto 0);
    signal descrom_rdat:    std_logic_vector(7 downto 0);
 
    -- RX buffer
    signal rxbuf:           t_byte_array(0 to (2**RXBUFSIZE_BITS-1));
    signal rxbuf_rdat:      std_logic_vector(7 downto 0);
 
    -- TX buffer
    signal txbuf:           t_byte_array(0 to (2**TXBUFSIZE_BITS-1));
    signal txbuf_rdat:      std_logic_vector(7 downto 0);
 
    -- Interface to usb_init
    signal usbi_usbrst :    std_logic;
    signal usbi_highspeed : std_logic;
    signal usbi_suspend :   std_logic;
 
    -- Interface to usb_packet
    signal usbp_chirpk :    std_logic;
    signal usbp_rxact :     std_logic;
    signal usbp_rxrdy :     std_logic;
    signal usbp_rxfin :     std_logic;
    signal usbp_rxdat :     std_logic_vector(7 downto 0);
    signal usbp_txact :     std_logic;
    signal usbp_txrdy :     std_logic;
    signal usbp_txdat :     std_logic_vector(7 downto 0);
 
    -- Interface to usb_transact
    signal usbt_in :        std_logic;
    signal usbt_out :       std_logic;
    signal usbt_setup :     std_logic;
    signal usbt_ping :      std_logic;
    signal usbt_fin :       std_logic;
    signal usbt_endpt :     std_logic_vector(3 downto 0);
    signal usbt_nak :       std_logic;
    signal usbt_stall :     std_logic;
    signal usbt_nyet :      std_logic;
    signal usbt_send :      std_logic;
    signal usbt_isync :     std_logic;
    signal usbt_osync :     std_logic;
    signal usbt_rxrdy :     std_logic;
    signal usbt_rxdat :     std_logic_vector(7 downto 0);
    signal usbt_txrdy :     std_logic;
    signal usbt_txdat :     std_logic_vector(7 downto 0);
 
    -- Interface to usb_control
    signal usbc_addr :      std_logic_vector(6 downto 0);
    signal usbc_confd :     std_logic;
    signal usbc_clr_in :    std_logic_vector(1 to 2);
    signal usbc_clr_out :   std_logic_vector(1 to 2);
    signal usbc_sethlt_in : std_logic_vector(1 to 2);
    signal usbc_sethlt_out: std_logic_vector(1 to 2);
    signal usbc_dscbusy :   std_logic;
    signal usbc_dscrd :     std_logic;
    signal usbc_dsctyp :    std_logic_vector(2 downto 0);
    signal usbc_dscinx :    std_logic_vector(7 downto 0);
    signal usbc_dscoff :    std_logic_vector(7 downto 0);
    signal usbc_dsclen :    std_logic_vector(7 downto 0);
    signal usbc_selfpowered : std_logic;
    signal usbc_in :        std_logic;
    signal usbc_out :       std_logic;
    signal usbc_setup :     std_logic;
    signal usbc_ping :      std_logic;
    signal usbc_nak :       std_logic;
    signal usbc_stall :     std_logic;
    signal usbc_nyet :      std_logic;
    signal usbc_send :      std_logic;
    signal usbc_isync :     std_logic;
    signal usbc_txdat :     std_logic_vector(7 downto 0);
 
    -- State machine
    type t_state is (
      ST_IDLE, ST_STALL, ST_NAK,
      ST_INSTART, ST_INSEND, ST_INDONE, ST_OUTRECV, ST_OUTNAK );
    signal s_state : t_state := ST_IDLE;
 
    -- Endpoint administration (PHY side).
    signal s_rxbuf_head :   unsigned(RXBUFSIZE_BITS-1 downto 0) := to_unsigned(0, RXBUFSIZE_BITS);
    signal s_rxbuf_tail :   unsigned(RXBUFSIZE_BITS-1 downto 0);
    signal s_txbuf_head :   unsigned(TXBUFSIZE_BITS-1 downto 0);
    signal s_txbuf_tail :   unsigned(TXBUFSIZE_BITS-1 downto 0) := to_unsigned(0, TXBUFSIZE_BITS);
    signal s_txbuf_stop :   unsigned(TXBUFSIZE_BITS-1 downto 0);
    signal s_bufptr :       unsigned(BUFPTR_SIZE-1 downto 0);
    signal s_txprev_full :  std_logic := '0';       -- Last transmitted packet was full-size
    signal s_txprev_acked : std_logic := '1';       -- Last trantsmitted packet was ack-ed.
    signal s_isync :        std_logic := '0';
    signal s_osync :        std_logic := '0';
    signal s_halt_in :      std_logic_vector(1 to 2) := "00";
    signal s_halt_out :     std_logic_vector(1 to 2) := "00";
    signal s_nyet :         std_logic := '0';
 
    -- Buffer state (application side).
    signal q_rxbuf_head :   unsigned(RXBUFSIZE_BITS-1 downto 0);
    signal q_rxbuf_tail :   unsigned(RXBUFSIZE_BITS-1 downto 0) := to_unsigned(0, RXBUFSIZE_BITS);
    signal q_txbuf_head :   unsigned(TXBUFSIZE_BITS-1 downto 0) := to_unsigned(0, TXBUFSIZE_BITS);
    signal q_txbuf_tail :   unsigned(TXBUFSIZE_BITS-1 downto 0);
 
    -- Control signals (PHY side).
    signal s_reset :        std_logic;
    signal s_txcork :       std_logic;
 
    -- Status signals (application side).
    signal q_usbrst :       std_logic;
    signal q_online :       std_logic;
    signal q_highspeed :    std_logic;
 
    -- Receive buffer logic (application side).
    signal q_rxval :        std_logic := '0';
    signal q_rxbuf_read :   std_logic;
    signal q_txbuf_rdy :    std_logic;
 
begin
 
    -- Check buffer size.
    assert ((not HSSUPPORT) or (RXBUFSIZE_BITS >= 10))
        report "High-speed device needs at least 1024 bytes RX buffer";
 
    -- Bus reset logic
    usb_init_inst : usb_init
        generic map (
            HSSUPPORT       => HSSUPPORT )
        port map (
            CLK             => CLK,
            RESET           => s_reset,
            I_USBRST        => usbi_usbrst,
            I_HIGHSPEED     => usbi_highspeed,
            I_SUSPEND       => usbi_suspend,
            P_CHIRPK        => usbp_chirpk,
            PHY_RESET       => PHY_RESET,
            PHY_LINESTATE   => PHY_LINESTATE,
            PHY_OPMODE      => PHY_OPMODE,
            PHY_XCVRSELECT  => PHY_XCVRSELECT,
            PHY_TERMSELECT  => PHY_TERMSELECT );
 
    -- Packet level logic
    usb_packet_inst : usb_packet
        port map (
            CLK             => CLK,
            RESET           => usbi_usbrst,
            P_CHIRPK        => usbp_chirpk,
            P_RXACT         => usbp_rxact,
            P_RXRDY         => usbp_rxrdy,
            P_RXFIN         => usbp_rxfin,
            P_RXDAT         => usbp_rxdat,
            P_TXACT         => usbp_txact,
            P_TXRDY         => usbp_txrdy,
            P_TXDAT         => usbp_txdat,
            PHY_DATAIN      => PHY_DATAIN,
            PHY_DATAOUT     => PHY_DATAOUT,
            PHY_TXVALID     => PHY_TXVALID,
            PHY_TXREADY     => PHY_TXREADY,
            PHY_RXACTIVE    => PHY_RXACTIVE,
            PHY_RXVALID     => PHY_RXVALID,
            PHY_RXERROR     => PHY_RXERROR );
 
    -- Transaction level logic
    usb_transact_inst : usb_transact
        generic map (
            HSSUPPORT       => HSSUPPORT )
        port map (
            CLK             => CLK,
            RESET           => usbi_usbrst,
            T_IN            => usbt_in,
            T_OUT           => usbt_out,
            T_SETUP         => usbt_setup,
            T_PING          => usbt_ping,
            T_FIN           => usbt_fin,
            T_ADDR          => usbc_addr,
            T_ENDPT         => usbt_endpt,
            T_NAK           => usbt_nak,
            T_STALL         => usbt_stall,
            T_NYET          => usbt_nyet,
            T_SEND          => usbt_send,
            T_ISYNC         => usbt_isync,
            T_OSYNC         => usbt_osync,
            T_RXRDY         => usbt_rxrdy,
            T_RXDAT         => usbt_rxdat,
            T_TXRDY         => usbt_txrdy,
            T_TXDAT         => usbt_txdat,
            I_HIGHSPEED     => usbi_highspeed,
            P_RXACT         => usbp_rxact,
            P_RXRDY         => usbp_rxrdy,
            P_RXFIN         => usbp_rxfin,
            P_RXDAT         => usbp_rxdat,
            P_TXACT         => usbp_txact,
            P_TXRDY         => usbp_txrdy,
            P_TXDAT         => usbp_txdat );
 
    -- Default control endpoint
    usb_control_inst : usb_control
        generic map (
	    NENDPT          => 2 )
        port map (
            CLK             => CLK,
            RESET           => usbi_usbrst,
            C_ADDR          => usbc_addr,
            C_CONFD         => usbc_confd,
            C_CLRIN         => usbc_clr_in,
            C_CLROUT        => usbc_clr_out,
            C_HLTIN         => s_halt_in,
            C_HLTOUT        => s_halt_out,
            C_SHLTIN        => usbc_sethlt_in,
            C_SHLTOUT       => usbc_sethlt_out,
            C_DSCBUSY       => usbc_dscbusy,
            C_DSCRD         => usbc_dscrd,
            C_DSCTYP        => usbc_dsctyp,
            C_DSCINX        => usbc_dscinx,
            C_DSCOFF        => usbc_dscoff,
            C_DSCLEN        => usbc_dsclen,
            C_SELFPOWERED   => usbc_selfpowered,
            T_IN            => usbc_in,
            T_OUT           => usbc_out,
            T_SETUP         => usbc_setup,
            T_PING          => usbc_ping,
            T_FIN           => usbt_fin,
            T_NAK           => usbc_nak,
            T_STALL         => usbc_stall,
            T_NYET          => usbc_nyet,
            T_SEND          => usbc_send,
            T_ISYNC         => usbc_isync,
            T_OSYNC         => usbt_osync,
            T_RXRDY         => usbt_rxrdy,
            T_RXDAT         => usbt_rxdat,
            T_TXRDY         => usbt_txrdy,
            T_TXDAT         => usbc_txdat );
 
    -- Assign usb_serial output signals.
    USBRST      <= q_usbrst;
    HIGHSPEED   <= q_highspeed;
    SUSPEND     <= usbi_suspend;
    ONLINE      <= q_online;
    RXVAL       <= q_rxval;
    RXDAT       <= rxbuf_rdat;
    RXLEN       <= std_logic_vector(q_rxbuf_head - q_rxbuf_tail);
    TXRDY       <= q_txbuf_rdy;
    TXROOM      <= std_logic_vector(q_txbuf_tail - q_txbuf_head - 1);
 
    -- Assign usb_control input signals
    usbc_in     <= usbt_in    when (usbt_endpt = "0000") else '0';
    usbc_out    <= usbt_out   when (usbt_endpt = "0000") else '0';
    usbc_setup  <= usbt_setup when (usbt_endpt = "0000") else '0';
    usbc_ping   <= usbt_ping  when (usbt_endpt = "0000") else '0';
    usbc_selfpowered <= '1'   when SELFPOWERED else '0';
 
    -- Assign usb_transact input lines
    usbt_nak    <= usbc_nak   when (usbt_endpt = "0000") else
                   '1'        when (s_state = ST_NAK) else
                   '0';
    usbt_stall  <= usbc_stall when (usbt_endpt = "0000") else
                   '1'        when (s_state = ST_STALL) else
                   '0';
    usbt_nyet   <= usbc_nyet  when (usbt_endpt = "0000") else
                   s_nyet;
    usbt_send   <= usbc_send  when (usbt_endpt = "0000") else
                   '1'        when (s_state = ST_INSEND) else
		   '0';
    usbt_isync  <= usbc_isync when (usbt_endpt = "0000") else
                   s_isync;
    usbt_txdat  <= usbc_txdat when (usbt_endpt = "0000" and usbc_dscbusy = '0') else
                   descrom_rdat when (usbt_endpt = "0000") else
                   txbuf_rdat;
 
    -- Buffer logic.
    q_rxbuf_read <= (RXRDY or (not q_rxval)) when (q_rxbuf_tail /= q_rxbuf_head) else '0';
    q_txbuf_rdy <= '1' when (q_txbuf_head + 1 /= q_txbuf_tail) else '0';
 
    -- Connection between PHY-side and application-side signals.
    -- This could be a good place to insert clock domain crossing.
    q_rxbuf_head <= s_rxbuf_head;
    s_rxbuf_tail <= q_rxbuf_tail;
    s_txbuf_head <= q_txbuf_head;
    q_txbuf_tail <= s_txbuf_tail;
    s_txcork    <= TXCORK;
    s_reset     <= RESET;
    q_online    <= usbc_confd;
    q_usbrst    <= usbi_usbrst;
    q_highspeed <= usbi_highspeed;
 
    -- Lookup address/length of the selected descriptor (combinatorial).
    process (usbc_dsctyp, usbc_dscinx, usbi_highspeed)
        constant slen: integer := descrom_start'length;
        constant nlen: integer := USBC_DSCLEN'length;
        variable s: unsigned((slen-1) downto 0);
        variable n: unsigned((nlen-1) downto 0);
    begin
        s := to_unsigned(0, slen);
        n := to_unsigned(0, nlen);
        case usbc_dsctyp is
            when "001" =>   -- device descriptor
                s := to_unsigned(DESC_DEV_ADDR, slen);
                n := to_unsigned(DESC_DEV_LEN, nlen);
            when "010" =>   -- configuration descriptor
                if usbc_dscinx = X"00" then
                    if HSSUPPORT and (usbi_highspeed = '1') then
                        s := to_unsigned(DESC_HSCFG_ADDR, slen);
                        n := to_unsigned(DESC_HSCFG_LEN, nlen);
                    else
                        s := to_unsigned(DESC_FSCFG_ADDR, slen);
                        n := to_unsigned(DESC_FSCFG_LEN, nlen);
                    end if;
                end if;
            when "110" =>   -- device qualifier
                if HSSUPPORT then
                    s := to_unsigned(DESC_QUAL_ADDR, slen);
                    n := to_unsigned(DESC_QUAL_LEN, nlen);
                end if;
            when "111" =>   -- other speed configuration
                if HSSUPPORT and (usbc_dscinx = X"00") then
                    if usbi_highspeed = '1' then
                        s := to_unsigned(DESC_FSCFG_ADDR, slen);
                        n := to_unsigned(DESC_FSCFG_LEN, nlen);
                    else
                        s := to_unsigned(DESC_HSCFG_ADDR, slen);
                        n := to_unsigned(DESC_HSCFG_LEN, nlen);
                    end if;
                end if;
            when others =>
                -- unsupported descriptor type
        end case;
        descrom_start <= s;
        usbc_dsclen   <= std_logic_vector(n);
    end process;
 
    -- Main application-side synchronous process.
    process is
    begin
        wait until rising_edge(CLK);
 
        if RESET = '1' then
 
            -- Reset this entity.
            q_rxbuf_tail <= to_unsigned(0, RXBUFSIZE_BITS);
            q_txbuf_head <= to_unsigned(0, TXBUFSIZE_BITS);
            q_rxval      <= '0'; 
 
        else
 
            -- Read data from the RX buffer.
            if q_rxbuf_read = '1' then
                -- The RAM buffer reads a byte in this cycle.
                q_rxbuf_tail    <= q_rxbuf_tail + 1;
                q_rxval         <= '1';
            elsif RXRDY = '1' then
                -- Byte consumed by application; no new data yet.
                q_rxval         <= '0';
            end if;
 
            -- Write data to the TX buffer.
            if (TXVAL = '1') and (q_txbuf_rdy = '1') then
                -- The RAM buffer writes a byte in this cycle.
                q_txbuf_head    <= q_txbuf_head + 1;
            end if;
 
        end if;
 
    end process;
 
    -- Main PHY-side synchronous process.
    process is
        variable v_max_txsize :     unsigned(TXBUFSIZE_BITS-1 downto 0);
        variable v_rxbuf_len_lim :  unsigned(RXBUFSIZE_BITS-1 downto 0);
        variable v_rxbuf_tmp_head : unsigned(RXBUFSIZE_BITS-1 downto 0);
        variable v_rxbuf_pktroom :  std_logic;
    begin
        wait until rising_edge(CLK);
 
        -- Determine the maximum packet size we can transmit.
        if HSSUPPORT and usbi_highspeed = '1' then
            v_max_txsize := to_unsigned(MAX_HSPACKET_SIZE, TXBUFSIZE_BITS);
        else
            v_max_txsize := to_unsigned(MAX_FSPACKET_SIZE, TXBUFSIZE_BITS);
        end if;
 
        -- Determine if there is room for another packet in the RX buffer.
        -- We need room for the largest possible incoming packet, plus
        -- two CRC bytes.
        if HSSUPPORT then
            v_rxbuf_len_lim := to_unsigned(2**RXBUFSIZE_BITS - MAX_HSPACKET_SIZE - 2, RXBUFSIZE_BITS);
        else
            v_rxbuf_len_lim := to_unsigned(2**RXBUFSIZE_BITS - MAX_FSPACKET_SIZE - 2, RXBUFSIZE_BITS);
        end if;
        if HSSUPPORT and s_state = ST_OUTRECV then
            -- Currently receiving a packet; compare against the temporary
            -- tail pointer to decide NYET vs ACK.
            v_rxbuf_tmp_head := resize(s_bufptr, RXBUFSIZE_BITS);
        else
            -- Not receiving a packet (or NYET not supported);
            -- compare against the tail pointer to decide NAK vs ACK.
            v_rxbuf_tmp_head := s_rxbuf_head;
        end if;
        if v_rxbuf_tmp_head - s_rxbuf_tail < v_rxbuf_len_lim then
            v_rxbuf_pktroom := '1';
        else
            v_rxbuf_pktroom := '0';
        end if;
 
        -- State machine
        if s_reset = '1' then
 
            -- Reset this entity.
            s_state         <= ST_IDLE;
            s_rxbuf_head    <= to_unsigned(0, RXBUFSIZE_BITS);
            s_txbuf_tail    <= to_unsigned(0, TXBUFSIZE_BITS);
            s_txprev_full   <= '0';
            s_txprev_acked  <= '1';
            s_isync         <= '0';
            s_osync         <= '0';
            s_halt_in       <= "00";
            s_halt_out      <= "00";
 
        elsif usbi_usbrst = '1' then
 
            -- Reset protocol state.
            s_state         <= ST_IDLE;
            s_txprev_full   <= '0';
            s_txprev_acked  <= '1';
            s_isync         <= '0';
            s_osync         <= '0';
            s_halt_in       <= "00";
            s_halt_out      <= "00";
 
        else
 
            case s_state is
 
                when ST_IDLE =>
                    -- Idle; wait for a transaction
                    s_nyet <= '0';
                    if (usbt_endpt = data_endpt) and (usbt_in = '1') then
                        -- Start of IN transaction
                        if s_halt_in(1) = '1' then
                            -- Endpoint halted
                            s_state  <= ST_STALL;
                        elsif (s_txbuf_tail /= s_txbuf_head and s_txcork = '0') or s_txprev_full = '1' then
                            -- Prepare to send data
                            s_bufptr <= resize(s_txbuf_tail, s_bufptr'length);
                            s_state  <= ST_INSTART;
                        else
                            -- We have no data to send
                            s_state  <= ST_NAK;
                        end if;
                    elsif (usbt_endpt = data_endpt) and (usbt_out = '1') then
                        -- Start of OUT transaction
                        if s_halt_out(1) = '1' then
                            -- Endpoint halted
                            s_state  <= ST_STALL;
                        elsif v_rxbuf_pktroom = '1' then
                            -- Prepare to receive data
                            s_bufptr <= resize(s_rxbuf_head, s_bufptr'length);
                            s_state  <= ST_OUTRECV; 
                        else
                            -- We have no room to store a new packet
                            s_state  <= ST_OUTNAK;
                        end if;
                    elsif HSSUPPORT and (usbt_endpt = data_endpt) and (usbt_ping = '1') then
                         -- Start of PING transaction
                        if v_rxbuf_pktroom = '1' then
                            -- There is room in the RX buffer for another packet; do nothing (ACK).
                            s_state  <= ST_IDLE;
                        else
                            -- There is no room in the RX buffer; respond with NAK.
                            s_state  <= ST_NAK;
                        end if;
                    elsif (usbt_endpt = notify_endpt) and (usbt_in = '1') then
                        -- The notify endpoint simply NAK's all IN transactions
                        if s_halt_in(2) = '1' then
                            -- Endpoint halted
                            s_state <= ST_STALL;
                        else
                            s_state <= ST_NAK;
                        end if;
                    end if;
 
                    -- Reset sync bits when the control endpoint tells us.
                    s_isync <= s_isync and (not usbc_clr_in(1));
                    s_osync <= s_osync and (not usbc_clr_out(1));
 
                    -- Set/reset halt bits when the control endpoint tells us.
                    s_halt_in(1)  <= (s_halt_in(1) or usbc_sethlt_in(1)) and (not usbc_clr_in(1));
                    s_halt_in(2)  <= (s_halt_in(2) or usbc_sethlt_in(2)) and (not usbc_clr_in(2));
                    s_halt_out(1) <= (s_halt_out(1) or usbc_sethlt_out(1)) and (not usbc_clr_out(1));
 
                when ST_STALL =>
                    -- Wait for end of transaction
                    if (usbt_in = '0') and (usbt_out = '0') and (usbt_ping = '0') then
                        s_state <= ST_IDLE;
                    end if;
 
                when ST_NAK =>
                    -- Wait for end of transaction
                    if (usbt_in = '0') and (usbt_out = '0') and (usbt_ping = '0') then
                        s_state <= ST_IDLE;
                    end if;
 
                when ST_INSTART =>
                    -- Prepare to send data; read first byte from memory.
                    if usbt_in = '0' then
                        -- Transaction canceled.
                        s_state <= ST_IDLE;
                    elsif (s_txbuf_tail = s_txbuf_head) or
                          (s_txprev_acked = '0' and resize(s_bufptr, TXBUFSIZE_BITS) = s_txbuf_stop) or
                          (s_txprev_acked = '1' and s_txcork = '1') then
                        -- The TX buffer is empty, or a previous empty packet
                        -- is unacknowledged, or the TX buffer is corked;
                        -- must send an empty packet.
                        s_state <= ST_INDONE;
                    else
                        -- Send a non-empty packet.
                        if s_txprev_acked = '1' then
                            -- Set up a size limit for this packet.
                            s_txbuf_stop <= s_txbuf_tail + v_max_txsize;
                        end if;
			s_bufptr <= s_bufptr + 1;
                        s_state <= ST_INSEND;
                    end if;
 
                when ST_INSEND =>
                    -- Sending data
                    if usbt_in = '0' then
                        -- Transaction canceled.
                        s_state <= ST_IDLE;
                    elsif usbt_txrdy = '1' then
                        -- Need to provide the next data byte;
                        -- stop when we reach the end of the TX buffer;
                        -- stop when we reach the packet size limit.
                        if (resize(s_bufptr, TXBUFSIZE_BITS) = s_txbuf_head) or
                           (resize(s_bufptr, TXBUFSIZE_BITS) = s_txbuf_stop) then
                            -- No more bytes
                            s_state <= ST_INDONE;
                        else
                            s_bufptr <= s_bufptr + 1;
                        end if;
                    end if;
 
                when ST_INDONE =>
                    -- Done sending packet; wait for ACK.
                    if usbt_in = '0' then
                        -- No acknowledgement
                        s_txprev_acked <= '0';
                        -- Set limit for next packet to the same point
			s_txbuf_stop <= resize(s_bufptr, TXBUFSIZE_BITS);
                        -- Done
                        s_state <= ST_IDLE;
                    elsif usbt_fin = '1' then
                        -- Got acknowledgement
                        s_txprev_acked <= '1';
                        -- Update buffer tail
                        s_txbuf_tail <= resize(s_bufptr, TXBUFSIZE_BITS);
                        -- Flip sync bit
                        s_isync <= not s_isync;
                        -- Remember if this was a full-sized packet.
                        if s_txbuf_tail + v_max_txsize = resize(s_bufptr, TXBUFSIZE_BITS) then
                            s_txprev_full <= '1';
                        else
                            s_txprev_full <= '0';
                        end if;
                        -- Done
                        s_state <= ST_IDLE;
                    end if;
 
                when ST_OUTRECV =>
                    -- Receiving data
                    if usbt_out = '0' then
                        -- Transaction ended.
                        -- If the transaction was succesful, usbt_fin has been
                        -- asserted in the previous cycle and has triggered
                        -- an update of s_rxbuf_head.
                        s_state <= ST_IDLE;
                    elsif (usbt_fin = '1') and (usbt_osync = s_osync) then
                        -- Good packet received; discard CRC bytes
                        s_rxbuf_head <= resize(s_bufptr, RXBUFSIZE_BITS) - 2;
                        s_osync <= not s_osync;
                    elsif usbt_rxrdy = '1' then
                        -- Got data byte
                        s_bufptr <= s_bufptr + 1;
                        if HSSUPPORT then
                            -- Set NYET if there is no room to receive
                            -- another packet after this one.
                            s_nyet <= not v_rxbuf_pktroom;
                        end if;
                    end if;
 
                when ST_OUTNAK =>
                    -- Receiving data while we don't have room to store it
                    if usbt_out = '0' then
                        -- End of transaction
                        s_state <= ST_IDLE;
                    elsif (usbt_rxrdy = '1') and (usbt_osync = s_osync) then
                        -- This is a new (non-duplicate) packet, but we can
                        -- not store it; so respond with NAK.
                        s_state <= ST_NAK;
                    end if;
 
            end case;
 
        end if;
    end process;
 
    -- It is always a fight to get the synthesizer to infer block RAM.
    -- The problem is we need dual port RAM with read-enable signals.
    -- The recommended coding style, with registered read addresses,
    -- does not work in this case.
    -- The code below generates three RAM blocks on the Xilinx Spartan-3,
    -- but it is doubtful whether it will work on other FPGA families.
 
    -- Write to RX buffer.
    process (CLK) is
    begin
        if rising_edge(CLK) then
            if s_state = ST_OUTRECV and usbt_rxrdy = '1' then
                rxbuf(to_integer(resize(s_bufptr, RXBUFSIZE_BITS))) <= usbt_rxdat;
            end if;
        end if;
    end process;
 
    -- Read from RX buffer.
    process (CLK) is
    begin
        if rising_edge(CLK) then
            if q_rxbuf_read = '1' then
                rxbuf_rdat <= rxbuf(to_integer(q_rxbuf_tail));
            end if;
        end if;
    end process;
 
    -- Write to TX buffer.
    process (CLK) is
    begin
        if rising_edge(CLK) then
            if TXVAL = '1' then
                txbuf(to_integer(q_txbuf_head)) <= TXDAT;
            end if;
        end if;
    end process;
 
    -- Read from TX buffer.
    process (CLK) is
    begin
        if rising_edge(CLK) then
            if (usbt_txrdy = '1') or (s_state = ST_INSTART) then
                txbuf_rdat <= txbuf(to_integer(resize(s_bufptr, TXBUFSIZE_BITS)));
            end if;
        end if;
    end process;
 
    -- Read from descriptor memory.
    process (CLK) is
    begin
        if rising_edge(CLK) then
            if usbc_dscrd = '1' then
                if HSSUPPORT and unsigned(usbc_dscoff) = 1 and usbc_dsctyp = "111" then
                    -- Disguise the configuration descriptor as an
                    -- other_speed_configuration descriptor.
                    descrom_raddr <= to_unsigned(DESC_OTHERSPEED_ADDR, descrom_raddr'length);
                else
                    descrom_raddr <= descrom_start + resize(unsigned(usbc_dscoff), descrom_raddr'length);
                end if;
            end if;
        end if;
    end process;
    assert to_integer(descrom_raddr) < descrom_rdat'length;
    descrom_rdat <= descrom(to_integer(descrom_raddr));
 
end architecture usb_serial_arch;
 
 

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.