URL
https://opencores.org/ocsvn/opb_usblite/opb_usblite/trunk
Subversion Repositories opb_usblite
Compare Revisions
- This comparison shows the changes necessary to convert path
/
- from Rev 6 to Rev 7
- ↔ Reverse comparison
Rev 6 → Rev 7
/opb_usblite/tags/R1/doc/readme.txt
0,0 → 1,27
-- |
-- opb_usblite - opb_uartlite replacement |
-- |
-- opb_usblite - opb_uartlite replacement for Xilinx Microblaze processor written |
-- in VHDL and Verilog. The opb_usblite is compatible with the USB CDC profile and |
-- works with microsoft usbser virtual comport driver (VCD). |
-- |
-- opb_usblite is using components by Rudolf Usselmann see |
-- http://www.opencores.org/cores/usb_phy/ |
-- and Joris van Rantwijk see http://www.xs4all.nl/~rjoris/fpga/usb.html |
-- MAKE SURE TO READ THEIR LICENSE TERMS BEFORE USING THIS IP-CORE |
-- |
-- Copyright (C) 2010 Ake Rehnman |
-- |
-- This program is free software: you can redistribute it and/or modify |
-- it under the terms of the GNU Lesser General Public License as published by |
-- the Free Software Foundation, either version 3 of the License, or |
-- (at your option) any later version. |
-- |
-- This program is distributed in the hope that it will be useful, |
-- but WITHOUT ANY WARRANTY; without even the implied warranty of |
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
-- GNU Lesser General Public License for more details. |
-- |
-- You should have received a copy of the GNU Lesser General Public License |
-- along with this program. If not, see <http://www.gnu.org/licenses/>. |
-- |
/opb_usblite/tags/R1/doc/README2.txt
0,0 → 1,453
----------------------------------------- |
USB 1.1 / 2.0 serial data transfer core |
----------------------------------------- |
|
Version: 2009-10-06 |
Author: Joris van Rantwijk |
Language: VHDL |
License: GPL - GNU General Public License |
Website: http://www.xs4all.nl/~rjoris/fpga/usb.html |
|
|
usb_serial is a synthesizable VHDL core, implementing serial data |
transfer over USB. Combined with a UTMI-compatible USB transceiver |
chip, this core acts as a USB device that transfers a byte stream |
in both directions over the bus. |
|
This package is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 2 of the License, or |
(at your option) any later version. |
|
|
----------------------------------------- |
See MANUAL.pdf for detailed information. |
----------------------------------------- |
|
|
Files in this package |
--------------------- |
|
COPYING Text of the GNU General Public License. |
MANUAL.pdf Manual for usb_serial core. |
Makefile Script to synthesizes the VHDL code for Xilinx devices. |
usb_serial.vhdl Main core. |
usb_control.vhdl Sub-entity handling control requests. |
usb_init.vhdl Sub-entity handling device initialization. |
usb_packet.vhdl Sub-entity for sending and receiving packets. |
usb_transact.vhdl Sub-entity for transaction handling. |
usbtest.vhdl Sample top-level design for testing. |
te0146.ucf Constraints file for a TE0146 FPGA module. |
testdev.py Python program running a torture test on usbtest.bit. |
perftest.c C program measuring data transfer performance on Linux. |
crcformula.py Python program for computing CRC update formulas. |
|
---- |
|
The rest of this file contains some unorganized notitions. |
|
|
Changes from version 2007-04-19 to 2009-10-06 |
--------------------------------------------- |
|
* usb_init: |
+ Add generic HSSUPPORT |
+ Rename USBRST to I_USBRST |
+ Add output signal I_HIGHSPEED, active iff attached in high speed mode |
+ Add output signal I_SUSPEND, active iff suspended by host |
+ Add output P_CHIRPK |
+ Add output PHY_XCVRSELECT |
+ Add output PHY_TERMSELECT |
+ Implement HS handshake / FS fallback protocol. |
+ Implement suspend detection. |
|
* usb_packet: |
+ Add input P_CHIRPK. |
+ Send continuous chirp-K when P_CHIRPK asserted. |
+ Use signal s_dataout instead of variable v_dataout as register. |
+ Recognize PING as a valid token packet. |
+ Clear PHY_TXVALID and PHY_DATAOUT in response to RESET. |
+ Pay attention to PHY_RXERROR while receiving handshake packet. |
+ Eliminate ST_RFIN state and release P_RXACT one cycle earlier, |
i.e. at the same time as raising P_RXFIN. (Necessary because PHY_RXACTIVE |
may be low for just a single cycle between packets). |
|
* usb_transact: |
+ Verified that releasing P_RXACT while asserting P_RXFIN is handled fine. |
+ Add generic HSSUPPORT. |
+ Add output signal T_PING. |
+ Add input signal T_NYET; must be valid when SEND goes down. |
+ Eliminate ST_FIN so that we will always be in time to catch the rising |
edge of P_RXACT even in the cycle immediately following P_RXFIN. |
+ Implement PING transaction (same application timing as IN transaction). |
+ Implement NYET handshake. |
+ Reduce guaranteed decision time for application from 10 to 2 cycles. |
+ Separate inter-packet delay and response timeout values for FS and HS; |
increase FS inter-packet delay from 10 to 14 cycles. |
+ Ignore our own transmitted packet while waiting for ACK. |
+ Fail transaction if empty packet received while waiting for ACK or DATA. |
+ Again rejected (after extensive consideration) the idea of using |
PHY_LINESTATE for inter-packet delay, even though this is actually |
required according to the UTMI standard. It is difficult to reliably |
relate PHY_LINESTATE to logical send/receive activity. The best I can come |
up with is to have an inter-packet timer which counts down iff the line |
is idle as indicated by PHY_LINESTATE. But detecting line idle in FS mode |
depends on the SE0-to-J transition, which makes the scheme vulnerable in |
case the SE0 state is missed somehow. |
So we stay with the concept of inter-packet timing based on PHY_RXACTIVE |
plus a much relaxed timeout for host responses. |
Note to self: please don't waste more time on this. |
|
* usb_control: |
+ Add generic HSSUPPORT. |
+ Rename upstream interface signals to C_xxx. |
+ Add input signal T_PING (ignored, therefore always ACK-ed). |
+ Add output signal T_NYET (always driven to zero). |
+ Redesigned descriptor ROM interface. |
+ Implement ENDPOINT_HALT feature. |
+ Implement self-powered bit in status word. |
|
* usb_serial: |
+ Changed interface to sub-entities. |
+ Redesigned descriptor ROM interface. |
+ Implement device_qualifier and other_speed_configuration descriptors. |
+ Split single block RAM into three separate RAMs for RX buffer, |
TX buffer and descriptor ROM. |
+ Streamline state machine. |
+ Implement PING / NYET handshake. |
+ Add RXLEN / TXROOM status signals. |
+ Add TXCORK control signal. |
+ Add HIGHSPEED and SUSPEND signals to application interface. |
+ Prepare for separate clock domains. |
+ Support halting of endpoints. |
|
* usb_serial_wb: |
+ Removed. Wishbone is not intended for this kind of thing. |
|
* usbtest: |
+ Add testing of TXCORK flag. |
+ Add blast mode for test of fast streaming transmission. |
|
* Makefile: |
+ Fix command line options for newer versions of Xilinx tools. |
|
* testdev.py: |
+ Testing of TXCORK feature. |
+ Adapt test parameters for bigger TX/RX buffers in the device. |
+ Test partial read of incoming data. |
|
* perftest.c |
+ Performance measurements. |
|
|
Performance measurements |
------------------------ |
|
Version 20090929: |
|
Performance full speed, RX 128, TX 128, libusb-1.0 async: |
RX 67108864 bytes in 61.673 s = 1088137 bytes/s |
TX 64000000 bytes in 58.816 s = 1088146 bytes/s |
|
Performance high speed, RX 2k, TX 1k, libusb-1.0 async: |
RX 67108864 bytes in 1.490 s = 45049302 bytes/s |
TX 64000000 bytes in 1.953 s = 32766457 bytes/s |
|
|
Intermediate version 20090917: |
( Comparing performance of normal code against error injection. ) |
|
Performance FS, normal: |
RX 67108864 bytes in 61.674 s = 1088118 bytes/s |
TX 64000000 bytes in 58.820 s = 1088073 bytes/s |
|
Performance HS, normal: |
RX 67108864 bytes in 1.535 s = 43727704 bytes/s |
TX 64000000 bytes in 1.961 s = 32635212 bytes/s |
|
Performance FS, error injection: |
RX 67108864 bytes in 82.163 s = 816777 bytes/s |
TX 64000000 bytes in 78.420 s = 816113 bytes/s |
|
Performance HS, error injection: |
RX 67108864 bytes in 1.965 s = 34144882 bytes/s |
TX 64000000 bytes in 3.110 s = 20576099 bytes/s |
|
|
Tested |
------ |
|
+ Suspend/resume with SUSPEND signal used as clock gate. |
+ Verified that none of the following events occur during functional test: |
aborted transaction; duplicate OUT packet; OUT-NAK in high speed mode. |
+ Deliberate error injection: works ok, but reduced performance as expected. |
+ Tested SetFeature(ENDPOINT_HALT) |
+ Functional test and performance test: |
+ full speed, konijn, linux, RX 128, TX 128 |
+ full speed, konijn, linux, RX 128, TX 128, no_fullpacket |
+ full speed, konijn, linux, RX 1k, TX 128 |
+ full speed, konijn, linux, RX 128, TX 1k (one time hang in perftest) |
+ full speed, konijn, linux, RX 2k, TX 1k |
+ high speed, konijn, linux, RX 1k, TX 1k (problems with usbserial, fixed) |
+ high speed, konijn, linux, RX 2k, TX 1k |
+ high speed, konijn, linux, RX 2k, TX 1k, no_fullpacket |
+ high speed, konijn, linux, RX 1k, TX 2k |
+ high speed, konijn, linux, RX 4k, TX 2k |
+ full speed, schildpad, linux, RX 128, TX 128 |
+ fallback to full speed, schildpad, linux, RX 2k, TX 1k |
+ full speed, sron, linux |
+ high speed, sron, linux |
+ Limited functional test: |
+ full speed, schildpad, Win2k, RX 128, TX 128 (fails due to zero length packet) |
+ full speed, schildpad, Win2k, RX 128, TX 128, no_fullpacket |
+ fallback to full speed, schildpad, Win2k, RX 2k, TX 1k, no_fullpacket (failed) |
+ full speed, iBook, RX 128, TX 128 |
+ high speed, iBook, RX 2k, TX 1k |
+ full speed, sron, Windows XP |
+ high speed, sron, Windows XP |
+ Performance: |
+ full speed, konijn, linux, RX 128, TX 128 |
+ high speed, konijn, linux, RX 2k, TX 1k |
+ Verify descriptors, device, config, qualifier, other_speed_config, status: |
+ full speed, konijn, linux |
+ high speed, konijn, linux |
+ Test suspend/resume: |
+ full speed, konijn |
+ full speed, iBook |
+ high speed, konijn |
+ high speed, iBook |
+ Plug-in handling: |
+ high speed, konijn, linux |
+ fallback to full speed, schildpad, linux |
+ high speed, sron, Windows XP |
+ high speed, iBook |
|
|
Misc issues |
----------- |
|
* USB 2.0 high speed requires support of SET_FEATURE(TEST_MODE). |
We will not implement this. |
Reason: overkill, no way to test it properly. |
|
* Suspend detection is implemented. |
The output signal SUSPEND from usb_serial can be used to combinatorially |
drive the suspend pin on the UTMI interface. Reset of the SUSPEND signal |
is asynchronous and can therefore work even when the FPGA has no clock. |
|
* We will not implement detection of SOF packets. |
Reason: usefulness is questionable. |
|
* No separate clock domains. |
Reason: difficult to implement, very hard to validate. |
|
* There is a problem with empty packets under Windows 2000. |
The Windows 2000 version of usbser.dll chokes on unexpected empty packets, |
such as send by the device after a final full-length packet. |
This has been solved in Windows XP. |
|
* A babble error occurs when a device sends more bytes than expected |
by the host, even if this is less than the maximum packet size. |
This may happen if software submits an IN request which is not |
a multiple of the maximum packet size. It may also happen if the host |
sends an invalid standard device request, for example GET_STATUS with |
wLength=0. |
To avoid this, always submit IN requests with the transfer size set to |
a multiple of the maximum packet size. |
Note that babble errors can freeze the host controller; this is a known |
bug of VIA UHCI controllers: |
http://www.mail-archive.com/linux-usb-devel@lists.sourceforge.net/msg17019.html |
|
* After plugging in, the Linux kernel log shows |
"device descriptor read/64, error -62" and |
"Cannot enable port 2. Maybe the USB cable is bad?". |
After the errors, the kernel retries and the second attempt is successful. |
It seems pretty reproducible; occurs in FS and HS mode after plugin, |
but not after soft-reattach of the device. |
It is worse under Win2k; the USB subsystem seems to crash after plugging in. |
Theory: Initialization of the FPGA initialization takes longer than 100 ms, |
causing us to miss the initial port handshake. |
|
* Even 8k TX buffer is not sufficient for loss-free transmission @ 25 MB/s. |
Loss rate becomes much higher under CPU load. |
|
|
FPGA Resources |
-------------- |
|
( From mapper log file; target = XC3S1000 ) |
|
Design: usbtest-20070419 |
Tools: Xilinx Webpack 7.1i |
|
Number of errors: 0 |
Number of warnings: 2 |
Logic Utilization: |
Number of Slice Flip Flops: 301 out of 15,360 1% |
Number of 4 input LUTs: 969 out of 15,360 6% |
Logic Distribution: |
Number of occupied Slices: 573 out of 7,680 7% |
Number of Slices containing only related logic: 573 out of 573 100% |
Number of Slices containing unrelated logic: 0 out of 573 0% |
*See NOTES below for an explanation of the effects of unrelated logic |
Total Number 4 input LUTs: 1,034 out of 15,360 6% |
Number used as logic: 969 |
Number used as a route-thru: 65 |
Number of bonded IOBs: 31 out of 173 17% |
IOB Flip Flops: 27 |
Number of Block RAMs: 2 out of 24 8% |
Number of GCLKs: 1 out of 8 12% |
|
Total equivalent gate count for design: 140,539 |
|
---- |
|
Design: usbtest-20090927, full speed, RX 128, TX 128 |
Tools: Xilinx Webpack 7.1i |
|
Number of errors: 0 |
Number of warnings: 2 |
Logic Utilization: |
Number of Slice Flip Flops: 337 out of 15,360 2% |
Number of 4 input LUTs: 1,151 out of 15,360 7% |
Logic Distribution: |
Number of occupied Slices: 671 out of 7,680 8% |
Number of Slices containing only related logic: 671 out of 671 100% |
Number of Slices containing unrelated logic: 0 out of 671 0% |
*See NOTES below for an explanation of the effects of unrelated logic |
Total Number 4 input LUTs: 1,249 out of 15,360 8% |
Number used as logic: 1,151 |
Number used as a route-thru: 98 |
Number of bonded IOBs: 31 out of 173 17% |
IOB Flip Flops: 31 |
Number of Block RAMs: 4 out of 24 16% |
Number of GCLKs: 1 out of 8 12% |
|
Total equivalent gate count for design: 273,110 |
|
---- |
|
Design: usbtest-20090929, high speed, RX 2k, TX 1k |
Tools: Xilinx Webpack 7.1i |
|
Number of errors: 0 |
Number of warnings: 2 |
Logic Utilization: |
Number of Slice Flip Flops: 380 out of 15,360 2% |
Number of 4 input LUTs: 1,349 out of 15,360 8% |
Logic Distribution: |
Number of occupied Slices: 787 out of 7,680 10% |
Number of Slices containing only related logic: 787 out of 787 100% |
Number of Slices containing unrelated logic: 0 out of 787 0% |
*See NOTES below for an explanation of the effects of unrelated logic |
Total Number 4 input LUTs: 1,465 out of 15,360 9% |
Number used as logic: 1,349 |
Number used as a route-thru: 116 |
Number of bonded IOBs: 31 out of 173 17% |
IOB Flip Flops: 34 |
Number of Block RAMs: 4 out of 24 16% |
Number of GCLKs: 1 out of 8 12% |
|
Total equivalent gate count for design: 274,894 |
|
---- |
|
Design: usb_serial only, 20090929, full speex RX 128, TX 128 |
Tools: Xilinx Webpack 7.1i |
|
Number of errors: 0 |
Number of warnings: 2 |
Logic Utilization: |
Number of Slice Flip Flops: 235 out of 15,360 1% |
Number of 4 input LUTs: 841 out of 15,360 5% |
Logic Distribution: |
Number of occupied Slices: 479 out of 7,680 6% |
Number of Slices containing only related logic: 479 out of 479 100% |
Number of Slices containing unrelated logic: 0 out of 479 0% |
*See NOTES below for an explanation of the effects of unrelated logic |
Total Number 4 input LUTs: 899 out of 15,360 5% |
Number used as logic: 841 |
Number used as a route-thru: 58 |
Number of bonded IOBs: 69 out of 173 39% |
IOB Flip Flops: 33 |
Number of Block RAMs: 3 out of 24 12% |
Number of GCLKs: 1 out of 8 12% |
|
Total equivalent gate count for design: 204,527 |
|
---- |
|
Design: usb_serial only, 20090929, high speed, RX 2k, TX 1k |
Tools: Xilinx Webpack 7.1i |
|
Number of errors: 0 |
Number of warnings: 2 |
Logic Utilization: |
Number of Slice Flip Flops: 285 out of 15,360 1% |
Number of 4 input LUTs: 1,062 out of 15,360 6% |
Logic Distribution: |
Number of occupied Slices: 610 out of 7,680 7% |
Number of Slices containing only related logic: 610 out of 610 100% |
Number of Slices containing unrelated logic: 0 out of 610 0% |
*See NOTES below for an explanation of the effects of unrelated logic |
Total Number 4 input LUTs: 1,139 out of 15,360 7% |
Number used as logic: 1,062 |
Number used as a route-thru: 77 |
Number of bonded IOBs: 76 out of 173 43% |
IOB Flip Flops: 36 |
Number of Block RAMs: 3 out of 24 12% |
Number of GCLKs: 1 out of 8 12% |
|
Total equivalent gate count for design: 206,559 |
|
---- |
|
Design: usb_serial only, 20090929, full speed, RX 128, TX 128 |
Tools: Xilinx ISE 11.2 |
|
Number of errors: 0 |
Number of warnings: 1 |
Logic Utilization: |
Number of Slice Flip Flops: 227 out of 15,360 1% |
Number of 4 input LUTs: 808 out of 15,360 5% |
Logic Distribution: |
Number of occupied Slices: 459 out of 7,680 5% |
Number of Slices containing only related logic: 459 out of 459 100% |
Number of Slices containing unrelated logic: 0 out of 459 0% |
*See NOTES below for an explanation of the effects of unrelated logic. |
Total Number of 4 input LUTs: 835 out of 15,360 5% |
Number used as logic: 808 |
Number used as a route-thru: 27 |
The Slice Logic Distribution report is not meaningful if the design is |
over-mapped for a non-slice resource or if Placement fails. |
Number of bonded IOBs: 69 out of 173 39% |
IOB Flip Flops: 27 |
Number of RAMB16s: 3 out of 24 12% |
Number of BUFGMUXs: 1 out of 8 12% |
|
---- |
|
Design: usb_serial only, 20090929, high speed, RX 2k, TX 1k |
Tools: Xilinx ISE 11.2 |
|
Number of errors: 0 |
Number of warnings: 2 |
Logic Utilization: |
Number of Slice Flip Flops: 265 out of 15,360 1% |
Number of 4 input LUTs: 955 out of 15,360 6% |
Logic Distribution: |
Number of occupied Slices: 555 out of 7,680 7% |
Number of Slices containing only related logic: 555 out of 555 100% |
Number of Slices containing unrelated logic: 0 out of 555 0% |
*See NOTES below for an explanation of the effects of unrelated logic. |
Total Number of 4 input LUTs: 1,010 out of 15,360 6% |
Number used as logic: 955 |
Number used as a route-thru: 55 |
The Slice Logic Distribution report is not meaningful if the design is |
over-mapped for a non-slice resource or if Placement fails. |
Number of bonded IOBs: 76 out of 173 43% |
IOB Flip Flops: 32 |
Number of RAMB16s: 3 out of 24 12% |
Number of BUFGMUXs: 1 out of 8 12% |
|
---- |
/opb_usblite/tags/R1/doc/README3.txt
0,0 → 1,99
|
USB 1.1 PHY |
========== |
|
Status |
------ |
This core is done. It was tested with a USB 1.1 core I have written on |
a XESS XCV800 board with a a Philips PDIUSBP11A transceiver. |
I have NOT yet tested it with my USB 2.0 Function IP core. |
|
Test Bench |
---------- |
There is no test bench, period ! As I said above I have tested this core |
in real hardware and it works just fine. |
|
Documentation |
------------- |
Sorry, there is none. I just don't have the time to write it. I have tried |
to follow the UTMI interface specification from USB 2.0. |
'phy_mode' selects between single ended and differential tx_phy output. See |
Philips ISP 1105 transceiver data sheet for an explanation of it's MODE |
select pin (see Note below). |
Currently this PHY only operates in Full-Speed mode. Required clock frequency |
is 48MHz, from which the 12MHz USB transmit and receive clocks are derived. |
|
RxError reports the following errors: |
- sync errors |
Could not synchronize to incoming bit stream |
- Bit Stuff Error |
Stuff bit had the wrong value (expected '0' got '1') |
- Byte Error |
Got a EOP (se0) before finished assembling a full byteAll of those errors |
are or'ed together and reported via RxError. |
|
Note: |
1) "phy_tx_mode" selects the PHY Transmit Mode: |
When phy_tx_mode is '0' the outputs are encoded as: |
txdn, txdp |
0 0 Differential Logic '0' |
0 1 Differential Logic '1' |
1 0 Single Ended '0' |
1 1 Single Ended '0' |
|
When phy_tx_mode is '1' the outputs are encoded as: |
txdn, txdp |
0 0 Single Ended '0' |
0 1 Differential Logic '1' |
1 0 Differential Logic '0' |
1 1 Illegal State |
|
See PHILIPS Transceiver Data Sheet for: ISP1105, ISP1106 and ISP1107 |
for more details. |
|
2) "usb_rst" Indicates a USB Bus Reset (this output is also or'ed with |
the reset input). |
|
Misc |
---- |
The USB 1.1 Phy Project Page is: |
http://www.opencores.org/cores/usb_phy |
|
To find out more about me (Rudolf Usselmann), please visit: |
http://www.asics.ws |
|
|
Directory Structure |
------------------- |
[core_root] |
| |
+-doc Documentation |
| |
+-bench--+ Test Bench |
| +-verilog Verilog Sources |
| +-vhdl VHDL Sources |
| |
+-rtl----+ Core RTL Sources |
| +-verilog Verilog Sources |
| +-vhdl VHDL Sources |
| |
+-sim----+ |
| +-rtl_sim---+ Functional verification Directory |
| | +-bin Makefiles/Run Scripts |
| | +-run Working Directory |
| | |
| +-gate_sim--+ Functional & Timing Gate Level |
| | Verification Directory |
| +-bin Makefiles/Run Scripts |
| +-run Working Directory |
| |
+-lint--+ Lint Directory Tree |
| +-bin Makefiles/Run Scripts |
| +-run Working Directory |
| +-log Linter log & result files |
| |
+-syn---+ Synthesis Directory Tree |
| +-bin Synthesis Scripts |
| +-run Working Directory |
| +-log Synthesis log files |
| +-out Synthesis Output |
/opb_usblite/tags/R1/pcores/opb_usblite_v1_00_a/hdl/vhdl/opb_usblite_core.vhd
0,0 → 1,525
-- |
-- opb_usblite - opb_uartlite replacement |
-- |
-- opb_usblite is using components from Rudolf Usselmann see |
-- http://www.opencores.org/cores/usb_phy/ |
-- and Joris van Rantwijk see http://www.xs4all.nl/~rjoris/fpga/usb.html |
-- |
-- Copyright (C) 2010 Ake Rehnman |
-- |
-- This program is free software: you can redistribute it and/or modify |
-- it under the terms of the GNU Lesser General Public License as published by |
-- the Free Software Foundation, either version 3 of the License, or |
-- (at your option) any later version. |
-- |
-- This program is distributed in the hope that it will be useful, |
-- but WITHOUT ANY WARRANTY; without even the implied warranty of |
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
-- GNU Lesser General Public License for more details. |
-- |
-- You should have received a copy of the GNU Lesser General Public License |
-- along with this program. If not, see <http://www.gnu.org/licenses/>. |
-- |
library IEEE; |
use IEEE.std_logic_1164.all; |
use IEEE.numeric_std.all; |
|
entity OPB_USBLITE_Core is |
generic ( |
C_PHYMODE : std_logic := '1'; |
C_VENDORID : std_logic_vector(15 downto 0) := X"1234"; |
C_PRODUCTID : std_logic_vector(15 downto 0) := X"5678"; |
C_VERSIONBCD : std_logic_vector(15 downto 0) := X"0200"; |
C_SELFPOWERED : boolean := false; |
C_RXBUFSIZE_BITS: integer range 7 to 12 := 10; |
C_TXBUFSIZE_BITS: integer range 7 to 12 := 10 |
); |
port ( |
Clk : in std_logic; |
Reset : in std_logic; |
Usb_Clk : in std_logic; |
-- OPB signals |
OPB_CS : in std_logic; |
OPB_ABus : in std_logic_vector(0 to 1); |
OPB_RNW : in std_logic; |
OPB_DBus : in std_logic_vector(7 downto 0); |
SIn_xferAck : out std_logic; |
SIn_DBus : out std_logic_vector(7 downto 0); |
Interrupt : out std_logic; |
-- USB signals |
txdp : out std_logic; |
txdn : out std_logic; |
txoe : out std_logic; |
rxd : in std_logic; |
rxdp : in std_logic; |
rxdn : in std_logic |
); |
end entity OPB_USBLITE_Core; |
|
library unisim; |
use unisim.all; |
|
architecture akre of OPB_USBLITE_Core is |
|
component 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 component usb_serial; |
|
component usb_phy is |
port ( |
clk : in std_logic; |
rst : in std_logic; |
phy_tx_mode : in std_logic; |
usb_rst : out std_logic; |
|
-- Transciever Interface |
txdp : out std_logic; |
txdn : out std_logic; |
txoe : out std_logic; |
rxd : in std_logic; |
rxdp : in std_logic; |
rxdn : in std_logic; |
|
-- UTMI Interface |
DataOut_i : in std_logic_vector (7 downto 0); |
TxValid_i : in std_logic; |
TxReady_o : out std_logic; |
RxValid_o : out std_logic; |
RxActive_o : out std_logic; |
RxError_o : out std_logic; |
DataIn_o : out std_logic_vector (7 downto 0); |
LineState_o : out std_logic_vector (1 downto 0) |
); |
end component usb_phy; |
|
constant RX_FIFO_ADR : std_logic_vector(0 to 1) := "00"; |
constant TX_FIFO_ADR : std_logic_vector(0 to 1) := "01"; |
constant STATUS_REG_ADR : std_logic_vector(0 to 1) := "10"; |
constant CTRL_REG_ADR : std_logic_vector(0 to 1) := "11"; |
|
-- ADDRESS MAP |
-- =========== |
-- RX FIFO base + $0 |
-- TX FIFO base + $4 |
-- CONTROL REG base + $8 |
-- STATUS REG base + $C |
|
|
-- Read Only |
signal status_Reg : std_logic_vector(7 downto 0); |
-- bit 0 rx_Data_Present |
-- bit 1 rx_Buffer_Full |
-- bit 2 tx_Buffer_Empty |
-- bit 3 tx_Buffer_Full |
-- bit 4 interrupt flag |
-- bit 5 not used |
-- bit 6 online flag |
-- bit 7 suspend flag |
|
-- Write Only |
-- bit 0 Reset_TX_FIFO -- not used |
-- bit 1 Reset_RX_FIFO -- not used |
-- bit 2-3 Dont'Care |
-- bit 4 enable_rxinterrupts |
-- bit 5 Dont'Care |
-- bit 6 enable_txinterrupts |
-- bit 7 tx_enable -- not used |
|
signal enable_txinterrupts : std_logic; |
signal enable_rxinterrupts : std_logic; |
|
signal read_RX_FIFO : std_logic; |
signal reset_RX_FIFO : std_logic; |
signal TX_EN : std_logic; |
signal write_TX_FIFO : std_logic; |
signal reset_TX_FIFO : std_logic; |
signal tx_BUFFER_FULL : std_logic; |
signal tx_Buffer_Empty : std_logic; |
signal rx_Data_Present : std_logic; |
signal rx_BUFFER_FULL : std_logic; |
|
signal xfer_Ack : std_logic; |
signal xfer_Ack1 : std_logic; |
signal xfer_Ack2 : std_logic; |
signal Interrupt_r : std_logic; |
|
signal read_rx_fifo_r : std_logic; |
signal read_rx_fifo_rr : std_logic; |
signal read_rx_fifo_rrr : std_logic; |
signal write_tx_fifo_r : std_logic; |
signal write_tx_fifo_rr : std_logic; |
signal write_tx_fifo_rrr : std_logic; |
|
signal usbrst : std_logic; |
signal rxval : std_logic; |
|
signal rxdat : std_logic_vector (7 downto 0); |
signal rxrdy : std_logic; |
signal txval : std_logic; |
signal txempty : std_logic; |
signal txfull : std_logic; |
signal rxfull : std_logic; |
signal txdat : std_logic_vector (7 downto 0); |
signal txrdy : std_logic; |
|
signal phy_datain : std_logic_vector (7 downto 0); |
signal phy_dataout : std_logic_vector (7 downto 0); |
signal phy_txvalid : std_logic; |
signal phy_txready : std_logic; |
signal phy_rxactive : std_logic; |
signal phy_rxvalid : std_logic; |
signal phy_rxerror : std_logic; |
signal phy_linestate : std_logic_vector (1 downto 0); |
signal phy_reset : std_logic; |
signal phy_resetn : std_logic; |
signal phy_usb_rst : std_logic; |
|
signal highspeed : std_logic; |
signal suspend : std_logic; |
signal online : std_logic; |
signal rxlen : std_logic_vector((C_RXBUFSIZE_BITS-1) downto 0); |
signal txroom : std_logic_vector((C_TXBUFSIZE_BITS-1) downto 0); |
|
attribute TIG : string; |
attribute TIG of Reset : signal is "yes"; |
attribute TIG of write_TX_FIFO : signal is "yes"; |
attribute TIG of read_RX_FIFO : signal is "yes"; |
attribute TIG of rxdat : signal is "yes"; |
attribute TIG of txdat : signal is "yes"; |
attribute TIG of rxval : signal is "yes"; |
attribute TIG of txrdy : signal is "yes"; |
attribute TIG of txempty : signal is "yes"; |
attribute TIG of txfull : signal is "yes"; |
attribute TIG of rxfull : signal is "yes"; |
|
attribute TIG of online : signal is "yes"; |
attribute TIG of suspend : signal is "yes"; |
|
constant C_TXFULL : std_logic_vector((C_TXBUFSIZE_BITS-1) downto 0) := (others=>'0'); |
constant C_TXEMPTY : std_logic_vector((C_TXBUFSIZE_BITS-1) downto 0) := (others=>'1'); |
constant C_RXFULL : std_logic_vector((C_RXBUFSIZE_BITS-1) downto 0) := (others=>'1'); |
constant C_RXEMPTY : std_logic_vector((C_RXBUFSIZE_BITS-1) downto 0) := (others=>'0'); |
|
begin -- architecture akre |
|
----------------------------------------------------------------------------- |
-- Instanciating Components |
----------------------------------------------------------------------------- |
|
usb_serial_inst : usb_serial |
generic map ( |
VENDORID => C_VENDORID, |
PRODUCTID => C_PRODUCTID, |
VERSIONBCD => C_VERSIONBCD, |
HSSUPPORT => false, |
SELFPOWERED => C_SELFPOWERED, |
RXBUFSIZE_BITS => C_RXBUFSIZE_BITS, |
TXBUFSIZE_BITS => C_TXBUFSIZE_BITS |
) |
port map ( |
CLK => usb_clk, --in |
RESET => reset, --in |
USBRST => usbrst, --out |
HIGHSPEED => highspeed, --out |
SUSPEND => suspend, --out |
ONLINE => online, --out |
RXVAL => rxval, --out |
RXDAT => rxdat, --out |
RXRDY => rxrdy, --in |
RXLEN => rxlen, --out |
TXVAL => txval, --in |
TXDAT => txdat, --in |
TXRDY => txrdy, --out |
TXROOM => txroom, --out |
TXCORK => '0', --in |
PHY_DATAIN => phy_datain, --in |
PHY_DATAOUT => phy_dataout, --out |
PHY_TXVALID => phy_txvalid, --out |
PHY_TXREADY => phy_txready, --in |
PHY_RXACTIVE => phy_rxactive, --in |
PHY_RXVALID => phy_rxvalid, --in |
PHY_RXERROR => phy_rxerror, --in |
PHY_LINESTATE => phy_linestate, --in |
PHY_OPMODE => open, --out |
PHY_XCVRSELECT => open, --out |
PHY_TERMSELECT => open, --out |
PHY_RESET => phy_reset --out |
); |
|
phy_resetn <= not(phy_reset); |
|
usb_phy_inst : usb_phy |
port map( |
clk => Usb_Clk, --in 48MHz |
rst => phy_resetn, --in |
phy_tx_mode => C_PHYMODE, --in |
usb_rst => phy_usb_rst, --out |
txdp => txdp, --out |
txdn => txdn, --out |
txoe => txoe, --out |
rxd => rxd, --in |
rxdp => rxdp, --in |
rxdn => rxdn, --in |
DataOut_i => phy_dataout, --in |
TxValid_i => phy_txvalid, --in |
TxReady_o => phy_txready, --out |
RxValid_o => phy_rxvalid, --out |
RxActive_o => phy_rxactive, --out |
RxError_o => phy_rxerror, --out |
DataIn_o => phy_datain, --out |
LineState_o => phy_linestate --out |
); |
|
----------------------------------------------------------------------------- |
-- Status register / Control register |
----------------------------------------------------------------------------- |
status_Reg(0) <= rx_Data_Present; |
status_Reg(1) <= rx_BUFFER_FULL; |
status_Reg(2) <= tx_Buffer_Empty; |
status_Reg(3) <= tx_BUFFER_FULL; |
status_Reg(4) <= Interrupt_r; |
status_Reg(5) <= '0'; |
status_Reg(6) <= online; |
status_Reg(7) <= suspend; |
|
|
----------------------------------------------------------------------------- |
-- Control / Status Register Handling |
----------------------------------------------------------------------------- |
|
process (clk, reset) is |
begin |
if (reset = '1') then -- asynchronous reset (active high) |
reset_TX_FIFO <= '1'; |
reset_RX_FIFO <= '1'; |
enable_rxinterrupts <= '0'; |
enable_txinterrupts <= '0'; |
TX_EN <= '0'; |
xfer_Ack2 <= '0'; |
elsif (clk'event and clk = '1') then -- rising clock edge |
reset_TX_FIFO <= '0'; |
reset_RX_FIFO <= '0'; |
xfer_Ack2 <= '0'; |
if (OPB_CS = '1') and (OPB_RNW = '0') and (OPB_ABus = CTRL_REG_ADR) then |
reset_TX_FIFO <= OPB_DBus(0); |
reset_RX_FIFO <= OPB_DBus(1); |
enable_rxinterrupts <= OPB_DBus(4); |
enable_txinterrupts <= OPB_DBus(6); |
TX_EN <= OPB_DBus(7); |
xfer_Ack2 <= '1'; |
end if; |
if (OPB_CS = '1') and (OPB_RNW = '1') and (OPB_ABus = STATUS_REG_ADR) then |
xfer_Ack2 <= '1'; |
end if; |
end if; |
end process; |
|
----------------------------------------------------------------------------- |
-- Interrupt handling |
----------------------------------------------------------------------------- |
|
process (clk, reset) |
begin |
if reset = '1' then -- asynchronous reset (active high) |
Interrupt_r <= '0'; |
elsif clk'event and clk = '1' then -- rising clock edge |
Interrupt_r <= (enable_rxinterrupts and rx_Data_Present) or |
(enable_txinterrupts and tx_Buffer_Empty); |
end if; |
end process; |
|
Interrupt <= Interrupt_r; |
|
----------------------------------------------------------------------------- |
-- Handling the OPB bus interface |
----------------------------------------------------------------------------- |
|
process (clk, OPB_CS) is |
begin |
if (OPB_CS='0') then |
xfer_Ack <= '0'; |
SIn_DBus <= (others => '0'); |
elsif (clk'event and clk='1') then |
xfer_Ack <= xfer_Ack1 or xfer_Ack2; |
SIn_DBus <= (others => '0'); |
if (OPB_RNW='1') then |
if (OPB_ABus = STATUS_REG_ADR) then |
SIn_DBus(7 downto 0) <= status_reg; |
else |
SIn_DBus(7 downto 0) <= rxdat; |
end if; |
end if; |
end if; |
end process; |
|
SIn_xferAck <= xfer_Ack; |
|
----------------------------------------------------------------------------- |
-- Generating read and write pulses to the FIFOs |
----------------------------------------------------------------------------- |
|
process(clk,reset) |
begin |
if (reset='1') then |
read_RX_FIFO <= '0'; |
write_TX_FIFO <= '0'; |
xfer_Ack1 <= '0'; |
elsif (clk'event and clk='1') then |
tx_BUFFER_EMPTY <= txempty; |
tx_BUFFER_FULL <= txfull; |
rx_Data_Present <= rxval; |
rx_Buffer_Full <= rxfull; |
write_TX_FIFO <= '0'; |
read_RX_FIFO <= '0'; |
xfer_Ack1 <= '0'; |
if (OPB_CS='1' and OPB_RNW='0' and OPB_ABus=TX_FIFO_ADR) then |
txdat <= OPB_DBus(7 downto 0); |
write_TX_FIFO <= '1'; |
xfer_Ack1 <= '1'; |
end if; |
if (OPB_CS='1' and OPB_RNW='1' and OPB_ABus=RX_FIFO_ADR) then |
read_RX_FIFO <= '1'; |
xfer_Ack1 <= '1'; |
end if; |
end if; |
end process; |
|
----------------------------------------------------------------------------- |
-- Synchronization logic across clock domains |
----------------------------------------------------------------------------- |
|
process(usb_clk, reset) |
begin |
if (reset='1') then |
read_RX_FIFO_r <= '0'; |
read_RX_FIFO_rr <= '0'; |
read_RX_FIFO_rrr <= '0'; |
write_TX_FIFO_r <= '0'; |
write_TX_FIFO_rr <= '0'; |
write_TX_FIFO_rrr <= '0'; |
elsif (usb_clk'event and usb_clk='1') then |
rxrdy <= '0'; |
txval <= '0'; |
txfull <= '0'; |
rxfull <= '0'; |
txfull <= '0'; |
txempty <= '0'; |
if (rxlen = C_RXFULL) then |
rxfull <= '1'; |
end if; |
if (txroom = C_TXFULL) then |
-- txfull <= '1'; |
txfull <= online and not(suspend); |
end if; |
if (txroom = C_TXEMPTY) then |
txempty <= '1'; |
end if; |
write_TX_FIFO_r <= write_TX_FIFO; |
write_TX_FIFO_rr <= write_TX_FIFO_r; |
write_TX_FIFO_rrr <= write_TX_FIFO_rr; |
read_RX_FIFO_r <= read_RX_FIFO; |
read_RX_FIFO_rr <= read_RX_FIFO_r; |
read_RX_FIFO_rrr <= read_RX_FIFO_rr; |
if (read_RX_FIFO_rrr='1' and read_RX_FIFO_rr='0') then |
rxrdy <= '1'; |
end if; |
if (write_TX_FIFO_rrr='1' and write_TX_FIFO_rr='0') then |
txval <= '1'; |
end if; |
end if; |
end process; |
|
end architecture akre; |
|
|
|
/opb_usblite/tags/R1/pcores/opb_usblite_v1_00_a/hdl/vhdl/tb_USBLITE_Core.vhd
0,0 → 1,948
-- |
-- opb_usblite - opb_uartlite replacement |
-- |
-- opb_usblite is using components from Rudolf Usselmann see |
-- http://www.opencores.org/cores/usb_phy/ |
-- and Joris van Rantwijk see http://www.xs4all.nl/~rjoris/fpga/usb.html |
-- |
-- Copyright (C) 2010 Ake Rehnman |
-- |
-- This program is free software: you can redistribute it and/or modify |
-- it under the terms of the GNU Lesser General Public License as published by |
-- the Free Software Foundation, either version 3 of the License, or |
-- (at your option) any later version. |
-- |
-- This program is distributed in the hope that it will be useful, |
-- but WITHOUT ANY WARRANTY; without even the implied warranty of |
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
-- GNU Lesser General Public License for more details. |
-- |
-- You should have received a copy of the GNU Lesser General Public License |
-- along with this program. If not, see <http://www.gnu.org/licenses/>. |
-- |
|
library IEEE; |
use IEEE.std_logic_1164.all; |
use IEEE.numeric_std.all; |
use STD.TEXTIO.all; |
use IEEE.STD_LOGIC_TEXTIO.all; |
|
|
entity tb_USBLITE_Core is |
end entity tb_USBLITE_Core; |
|
library unisim; |
use unisim.all; |
|
architecture akre of tb_USBLITE_Core is |
|
component usb_phy is |
port ( |
clk : in std_logic; |
rst : in std_logic; |
phy_tx_mode : in std_logic; |
usb_rst : out std_logic; |
|
-- Transciever Interface |
txdp : out std_logic; |
txdn : out std_logic; |
txoe : out std_logic; |
rxd : in std_logic; |
rxdp : in std_logic; |
rxdn : in std_logic; |
|
-- UTMI Interface |
DataOut_i : in std_logic_vector (7 downto 0); |
TxValid_i : in std_logic; |
TxReady_o : out std_logic; |
RxValid_o : out std_logic; |
RxActive_o : out std_logic; |
RxError_o : out std_logic; |
DataIn_o : out std_logic_vector (7 downto 0); |
LineState_o : out std_logic_vector (1 downto 0) |
); |
end component usb_phy; |
|
component OPB_USBLITE_Core is |
generic ( |
C_PHYMODE : std_logic := '1'; |
C_VENDORID : std_logic_vector(15 downto 0) := X"1234"; |
C_PRODUCTID : std_logic_vector(15 downto 0) := X"5678"; |
C_VERSIONBCD : std_logic_vector(15 downto 0) := X"0200"; |
C_SELFPOWERED : boolean := false; |
C_RXBUFSIZE_BITS: integer range 7 to 12 := 10; |
C_TXBUFSIZE_BITS: integer range 7 to 12 := 10 |
); |
port ( |
Clk : in std_logic; |
Reset : in std_logic; |
Usb_Clk : in std_logic; |
-- OPB signals |
OPB_CS : in std_logic; |
OPB_ABus : in std_logic_vector(0 to 1); |
OPB_RNW : in std_logic; |
OPB_DBus : in std_logic_vector(7 downto 0); |
SIn_xferAck : out std_logic; |
SIn_DBus : out std_logic_vector(7 downto 0); |
Interrupt : out std_logic; |
-- USB signals |
txdp : out std_logic; |
txdn : out std_logic; |
txoe : out std_logic; |
rxd : in std_logic; |
rxdp : in std_logic; |
rxdn : in std_logic |
); |
end component OPB_USBLITE_Core; |
|
signal clk : std_logic; |
signal usbclk : std_logic; |
signal reset : std_logic; |
signal rxdp : std_logic; |
signal rxdn : std_logic; |
signal rxd : std_logic; |
signal txdp : std_logic; |
signal txdn : std_logic; |
signal txoe : std_logic; |
|
signal usbtxdata : std_logic_vector (7 downto 0); |
signal usbtxvalid : std_logic; |
signal usbtxready : std_logic; |
signal usbrxvalid : std_logic; |
signal usbrxactive : std_logic; |
signal usbrxerror : std_logic; |
signal usbrxdata : std_logic_vector (7 downto 0); |
signal usblinestate : std_logic_vector (1 downto 0); |
|
signal Bus2IP_CS : std_logic := '0'; |
signal Bus2IP_CE : std_logic := '0'; |
signal Bus2IP_Addr : std_logic_vector(0 to 31) := X"00000000"; |
signal Bus2IP_RNW : std_logic := '0'; |
signal Bus2IP_Data : std_logic_vector(0 to 31); |
signal Bus2IP_BE : std_logic_vector(3 downto 0) := "0000"; |
signal IP2Bus_Ack : std_logic := '0'; |
signal IP2Bus_Data : std_logic_vector(0 to 31) := X"00000000"; |
signal Interrupt : std_logic := '0'; |
|
signal resetn : std_logic; |
signal usbrxdata_r : std_logic_vector(7 downto 0); |
|
-- type txmemarray is array (0 to 2048) of std_logic_vector(7 downto 0); |
type txmemarray is array (0 to 255) of std_logic_vector(7 downto 0); |
shared variable txmem : txmemarray; |
|
-- type bufferarray is array (0 to 16384) of std_logic_vector(7 downto 0); |
type bufferarray is array (0 to 255) of std_logic_vector(7 downto 0); |
shared variable buffer1 : bufferarray; |
shared variable buffer0 : bufferarray; |
shared variable buffer1_last : integer; |
shared variable len : integer; |
shared variable setup_pid : std_logic; |
shared variable error_cnt : integer; |
|
constant USBF_T_PID_OUT : std_logic_vector(3 downto 0):="0001"; |
constant USBF_T_PID_IN : std_logic_vector(3 downto 0):="1001"; |
constant USBF_T_PID_SOF : std_logic_vector(3 downto 0):="0101"; |
constant USBF_T_PID_SETUP : std_logic_vector(3 downto 0):="1101"; |
constant USBF_T_PID_DATA0 : std_logic_vector(3 downto 0):="0011"; |
constant USBF_T_PID_DATA1 : std_logic_vector(3 downto 0):="1011"; |
constant USBF_T_PID_DATA2 : std_logic_vector(3 downto 0):="0111"; |
constant USBF_T_PID_MDATA : std_logic_vector(3 downto 0):="1111"; |
constant USBF_T_PID_ACK : std_logic_vector(3 downto 0):="0010"; |
constant USBF_T_PID_NACK : std_logic_vector(3 downto 0):="1010"; |
constant USBF_T_PID_STALL : std_logic_vector(3 downto 0):="1110"; |
constant USBF_T_PID_NYET : std_logic_vector(3 downto 0):="0110"; |
constant USBF_T_PID_PRE : std_logic_vector(3 downto 0):="1100"; |
constant USBF_T_PID_ERR : std_logic_vector(3 downto 0):="1100"; |
constant USBF_T_PID_SPLIT : std_logic_vector(3 downto 0):="1000"; |
constant USBF_T_PID_PING : std_logic_vector(3 downto 0):="0100"; |
constant USBF_T_PID_RES : std_logic_vector(3 downto 0):="0000"; |
|
constant GET_STATUS : std_logic_vector(7 downto 0) := X"00"; |
constant CLEAR_FEATURE : std_logic_vector(7 downto 0) := X"01"; |
constant SET_FEATURE : std_logic_vector(7 downto 0) := X"03"; |
constant SET_ADDRESS : std_logic_vector(7 downto 0) := X"05"; |
constant GET_DESCRIPTOR : std_logic_vector(7 downto 0) := X"06"; |
constant SET_DESCRIPTOR : std_logic_vector(7 downto 0) := X"07"; |
constant GET_CONFIG : std_logic_vector(7 downto 0) := X"08"; |
constant SET_CONFIG : std_logic_vector(7 downto 0) := X"09"; |
constant GET_INTERFACE : std_logic_vector(7 downto 0) := X"0a"; |
constant SET_INTERFACE : std_logic_vector(7 downto 0) := X"0b"; |
constant SYNCH_FRAME : std_logic_vector(7 downto 0) := X"0c"; |
|
procedure utmi_recv_pack (variable size : inout integer) is |
begin |
size := 0; |
while (usbrxactive /= '1') loop |
wait until rising_edge(usbclk); |
end loop; |
while (usbrxactive= '1') loop |
while (usbrxvalid /= '1' and usbrxactive = '1') loop |
wait until rising_edge(usbclk); |
end loop; |
if (usbrxvalid = '1' and usbrxactive = '1') then |
txmem(size) := usbrxdata; |
size := size + 1; |
end if; |
wait until rising_edge(usbclk); |
end loop; |
end procedure utmi_recv_pack; |
|
procedure utmi_send_pack (constant size : integer; signal usbtxdata: out std_logic_vector; signal usbtxvalid: out std_logic) is |
variable n : integer; |
begin |
for n in 0 to size-1 loop |
wait until rising_edge(usbclk); |
usbtxvalid <= '1'; |
usbtxdata <= txmem(n); |
while (usbtxready/='1') loop |
wait until rising_edge(usbclk); |
end loop; |
end loop; |
wait until rising_edge(usbclk); |
usbtxvalid <= '0'; |
end procedure utmi_send_pack; |
|
function crc5 (crc_in:std_logic_vector; din:std_logic_vector) return std_logic_vector is |
variable crc5x : std_logic_vector (4 downto 0); |
begin |
crc5x(0) := din(10) xor din(9) xor din(6) xor din(5) xor din(3) xor din(0) xor crc_in(0) xor crc_in(3) xor crc_in(4); |
crc5x(1) := din(10) xor din(7) xor din(6) xor din(4) xor din(1) xor crc_in(0) xor crc_in(1) xor crc_in(4); |
crc5x(2) := din(10) xor din(9) xor din(8) xor din(7) xor din(6) xor din(3) xor din(2) xor din(0) xor crc_in(0) xor crc_in(1) xor crc_in(2) xor crc_in(3) xor crc_in(4); |
crc5x(3) := din(10) xor din(9) xor din(8) xor din(7) xor din(4) xor din(3) xor din(1) xor crc_in(1) xor crc_in(2) xor crc_in(3) xor crc_in(4); |
crc5x(4) := din(10) xor din(9) xor din(8) xor din(5) xor din(4) xor din(2) xor crc_in(2) xor crc_in(3) xor crc_in(4); |
return crc5x; |
end function crc5; |
|
function crc16 (crc_in: std_logic_vector; din:std_logic_vector) return std_logic_vector is |
variable crc_out : std_logic_vector (15 downto 0); |
begin |
crc_out(0) := din(7) xor din(6) xor din(5) xor din(4) xor din(3) xor |
din(2) xor din(1) xor din(0) xor crc_in(8) xor crc_in(9) xor |
crc_in(10) xor crc_in(11) xor crc_in(12) xor crc_in(13) xor |
crc_in(14) xor crc_in(15); |
crc_out(1) := din(7) xor din(6) xor din(5) xor din(4) xor din(3) xor din(2) xor |
din(1) xor crc_in(9) xor crc_in(10) xor crc_in(11) xor |
crc_in(12) xor crc_in(13) xor crc_in(14) xor crc_in(15); |
crc_out(2) := din(1) xor din(0) xor crc_in(8) xor crc_in(9); |
crc_out(3) := din(2) xor din(1) xor crc_in(9) xor crc_in(10); |
crc_out(4) := din(3) xor din(2) xor crc_in(10) xor crc_in(11); |
crc_out(5) := din(4) xor din(3) xor crc_in(11) xor crc_in(12); |
crc_out(6) := din(5) xor din(4) xor crc_in(12) xor crc_in(13); |
crc_out(7) := din(6) xor din(5) xor crc_in(13) xor crc_in(14); |
crc_out(8) := din(7) xor din(6) xor crc_in(0) xor crc_in(14) xor crc_in(15); |
crc_out(9) := din(7) xor crc_in(1) xor crc_in(15); |
crc_out(10) := crc_in(2); |
crc_out(11) := crc_in(3); |
crc_out(12) := crc_in(4); |
crc_out(13) := crc_in(5); |
crc_out(14) := crc_in(6); |
crc_out(15) := din(7) xor din(6) xor din(5) xor din(4) xor din(3) xor din(2) xor |
din(1) xor din(0) xor crc_in(7) xor crc_in(8) xor crc_in(9) xor |
crc_in(10) xor crc_in(11) xor crc_in(12) xor crc_in(13) xor |
crc_in(14) xor crc_in(15); |
return crc_out; |
end function crc16; |
|
procedure recv_packet(variable pid: inout std_logic_vector(3 downto 0); variable size: inout integer) is |
variable del,n : integer; |
variable crc16r : std_logic_vector(15 downto 0); |
variable x,y : std_logic_vector(7 downto 0); |
variable s : LINE; |
begin |
crc16r := X"ffff"; |
utmi_recv_pack(size); |
for n in 1 to size-3 loop |
y := txmem(n); |
x(7) := y(0); |
x(6) := y(1); |
x(5) := y(2); |
x(4) := y(3); |
x(3) := y(4); |
x(2) := y(5); |
x(1) := y(6); |
x(0) := y(7); |
crc16r := crc16(crc16r, x); |
end loop; |
n := size-2; |
|
y := crc16r(15 downto 8); |
x(7) := y(0); |
x(6) := y(1); |
x(5) := y(2); |
x(4) := y(3); |
x(3) := y(4); |
x(2) := y(5); |
x(1) := y(6); |
x(0) := y(7); |
crc16r(15 downto 8) := not(x); |
|
y := crc16r(7 downto 0); |
x(7) := y(0); |
x(6) := y(1); |
x(5) := y(2); |
x(4) := y(3); |
x(3) := y(4); |
x(2) := y(5); |
x(1) := y(6); |
x(0) := y(7); |
crc16r(7 downto 0) := not(x); |
|
if (crc16r /= txmem(n)&txmem(n+1)) then |
--$display("ERROR: CRC Mismatch: Expected: %h, Got: %h%h (%t)",crc16r, txmem[n], txmem[n+1], $time); |
WRITE(s,string'("ERROR: CRC Mismatch got:")); |
HWRITE(s,crc16r); |
WRITE(s,string'(" expected:")); |
HWRITE(s,txmem(n)&txmem(n+1)); |
report s.all; |
end if; |
|
for n in 0 to size-3 loop |
buffer1(buffer1_last+n) := txmem(n+1); |
end loop; |
n := size-3; |
|
buffer1_last := buffer1_last+n; |
|
-- Check PID |
x := txmem(0); |
|
if (x(7 downto 4) /= not(x(3 downto 0))) then |
--$display("ERROR: Pid Checksum mismatch: Top: %h Bottom: %h (%t)",x[7:4], x[3:0], $time); |
WRITE(s,string'("ERROR: Pid Checksum mismatch: Top: ")); |
HWRITE(s,x(7 downto 4)); |
WRITE(s,string'(" Bottom:")); |
HWRITE(s,x(3 downto 0)); |
report s.all; |
end if; |
|
pid := x(3 downto 0); |
size:= size-3; |
|
end procedure recv_packet; |
|
procedure send_token (constant fa:std_logic_vector(7 downto 0); constant ep:std_logic_vector(3 downto 0); constant pid:std_logic_vector(3 downto 0)) is |
variable tmp_data:std_logic_vector(15 downto 0); |
variable x,y:std_logic_vector(10 downto 0); |
variable len:integer; |
begin |
tmp_data := fa(6 downto 0)&ep&"00000"; |
if (pid=USBF_T_PID_ACK) then |
len := 1; |
else |
len := 3; |
end if; |
y := fa(6 downto 0)&ep; |
x(10) := y(4); |
x(9) := y(5); |
x(8) := y(6); |
x(7) := y(7); |
x(6) := y(8); |
x(5) := y(9); |
x(4) := y(10); |
x(3) := y(0); |
x(2) := y(1); |
x(1) := y(2); |
x(0) := y(3); |
y(4 downto 0) := crc5("11111", x); |
tmp_data(4 downto 0) := not(y(4 downto 0)); |
tmp_data(15 downto 5) := x; |
txmem(0) := (not(pid)&pid); -- PID |
txmem(1) := ( tmp_data(8)&tmp_data(9)&tmp_data(10)&tmp_data(11)&tmp_data(12)&tmp_data(13)&tmp_data(14)&tmp_data(15)); |
txmem(2) := ( tmp_data(0)&tmp_data(1)&tmp_data(2)&tmp_data(3)&tmp_data(4)&tmp_data(5)&tmp_data(6)&tmp_data(7)); |
utmi_send_pack(len,usbtxdata,usbtxvalid); |
end procedure send_token; |
|
procedure send_data (constant pid:std_logic_vector(3 downto 0); constant len:integer; constant mode:integer) is |
variable n : integer; |
variable crc16r : std_logic_vector(15 downto 0); |
variable x,y : std_logic_vector(7 downto 0); |
begin |
txmem(0) := not(pid)&pid; -- PID |
crc16r := X"ffff"; |
for n in 0 to len-1 loop |
if(mode=1) then |
y := buffer1(buffer1_last+n); |
else |
y := std_logic_vector(to_unsigned(n,8)); |
end if; |
|
-- x(7 downto 0) := y(0 to 7); |
x(7) := y(0); |
x(6) := y(1); |
x(5) := y(2); |
x(4) := y(3); |
x(3) := y(4); |
x(2) := y(5); |
x(1) := y(6); |
x(0) := y(7); |
txmem(n+1) := y; |
crc16r := crc16(crc16r, x); |
end loop; |
|
buffer1_last := buffer1_last + len - 1; |
y := crc16r(15 downto 8); |
-- x(7 downto 0) := y(0 to 7); |
x(7) := y(0); |
x(6) := y(1); |
x(5) := y(2); |
x(4) := y(3); |
x(3) := y(4); |
x(2) := y(5); |
x(1) := y(6); |
x(0) := y(7); |
txmem(len+1) := not(x); |
|
y := crc16r(7 downto 0); |
-- x(7 downto 0) := y(0 to 7); |
x(7) := y(0); |
x(6) := y(1); |
x(5) := y(2); |
x(4) := y(3); |
x(3) := y(4); |
x(2) := y(5); |
x(1) := y(6); |
x(0) := y(7); |
txmem(len+2) := not(x); |
|
utmi_send_pack(len+3,usbtxdata,usbtxvalid); |
end procedure send_data; |
|
procedure data_in (constant fa:std_logic_vector(7 downto 0); constant pl_size:integer) is |
variable rlen : integer; |
variable pid : std_logic_vector(3 downto 0); |
variable expected_pid : std_logic_vector(3 downto 0); |
variable s : LINE; |
begin |
buffer1_last := 0; |
send_token( fa, -- Function Address |
X"00", -- Logical Endpoint Number |
USBF_T_PID_IN -- PID |
); |
recv_packet(pid,rlen); |
if (setup_pid='1') then |
expected_pid := X"b"; -- DATA 1 |
else |
expected_pid := X"3"; -- DATA 0 |
end if; |
if (pid /= expected_pid) then |
--$display("ERROR: Data IN PID mismatch. Expected: %h, Got: %h (%t)", expect_pid, pid, $time); |
report "ERROR: Data IN PID mismatch."; |
error_cnt := error_cnt + 1; |
end if; |
|
setup_pid := not(setup_pid); |
if (rlen /= pl_size) then |
report "ERROR: Data IN Size mismatch."; |
--$display("ERROR: Data IN Size mismatch. Expected: %d, Got: %d (%t)", pl_size, rlen, $time); |
error_cnt := error_cnt + 1; |
end if; |
|
DEALLOCATE(s); |
WRITE(s,string'("RCV bytes: ")); |
WRITE(s,rlen); |
report s.all; |
for n in 0 to rlen-1 loop |
-- $display("RCV Data[%0d]: %h",n,buffer1[n]); |
DEALLOCATE(s); |
WRITE(s,string'("RCV Data[")); |
WRITE(s,n); |
WRITE(s,string'("]=")); |
HWRITE(s,buffer1(n)); |
report s.all; |
end loop; |
|
-- repeat(5) @(posedge clk); |
wait for 1 us; |
|
send_token( fa, -- Function Address |
X"00", -- Logical Endpoint Number |
USBF_T_PID_ACK -- PID |
); |
|
-- repeat(5) @(posedge clk); |
wait for 1 us; |
end procedure data_in; |
|
procedure data_out(fa:std_logic_vector(7 downto 0); pl_size:integer) is |
variable len : integer; |
begin |
send_token( fa, -- Function Address |
X"00", -- Logical Endpoint Number |
USBF_T_PID_OUT -- PID |
); |
wait until rising_edge(usbclk); |
|
if (setup_pid='0') then |
send_data(USBF_T_PID_DATA0, pl_size, 1); |
else |
send_data(USBF_T_PID_DATA1, pl_size, 1); |
end if; |
|
setup_pid := not(setup_pid); |
|
-- Wait for ACK |
|
utmi_recv_pack(len); |
|
if(txmem(0) /= X"d2") then |
--$display("ERROR: ACK mismatch. Expected: %h, Got: %h (%t)",8'hd2, txmem[0], $time); |
report "ERROR: SETUP: ACK mismatch"; |
error_cnt := error_cnt + 1; |
end if; |
|
if(len /= 1) then |
--$display("ERROR: SETUP: Length mismatch. Expected: %h, Got: %h (%t)",8'h1, len, $time); |
report "ERROR: SETUP: Length mismatch"; |
error_cnt := error_cnt + 1; |
end if; |
|
-- repeat(5) @(posedge clk); |
wait for 1 us; |
end procedure data_out; |
|
procedure send_setup (constant fa:std_logic_vector(7 downto 0); |
constant req_type:std_logic_vector(7 downto 0); |
constant request:std_logic_vector(7 downto 0); |
constant wValue:std_logic_vector(15 downto 0); |
constant wIndex:std_logic_vector(15 downto 0); |
constant wLength:std_logic_vector(15 downto 0)) is |
begin |
send_token(fa,X"0",USBF_T_PID_SETUP); |
wait for 1 us; |
buffer1(0) := req_type; |
buffer1(1) := request; |
buffer1(3) := wValue(15 downto 8); |
buffer1(2) := wValue(7 downto 0); |
buffer1(5) := wIndex(15 downto 8); |
buffer1(4) := wIndex(7 downto 0); |
buffer1(7) := wLength(15 downto 8); |
buffer1(6) := wLength(7 downto 0); |
buffer1_last := 0; |
send_data(USBF_T_PID_DATA0, 8, 1); |
utmi_recv_pack(len); |
if (txmem(0) /= x"d2") then |
--$display("ERROR: SETUP: ACK mismatch. Expected: %h, Got: %h (%t)", 8'hd2, txmem[0], $time); |
report "ERROR: SETUP: ACK mismatch"; |
error_cnt := error_cnt + 1; |
end if; |
if (len /= 1) then |
--$display("ERROR: SETUP: Length mismatch. Expected: %h, Got: %h (%t)", 8'h1, len, $time); |
report "ERROR: SETUP: Length mismatch. len="&integer'image(len); |
error_cnt := error_cnt + 1; |
end if; |
|
wait until rising_edge(usbclk); |
setup_pid := '1'; |
wait until rising_edge(usbclk); |
|
end procedure send_setup; |
|
procedure send_sof(constant frmn:integer) is |
variable frmnv : std_logic_vector(10 downto 0); |
variable tmp_data : std_logic_vector(15 downto 0); |
variable x,y : std_logic_vector(10 downto 0); |
begin |
frmnv := std_logic_vector(to_unsigned(frmn,11)); |
y := frmnv; |
x(10) := y(0); |
x(9) := y(1); |
x(8) := y(2); |
x(7) := y(3); |
x(6) := y(4); |
x(5) := y(5); |
x(4) := y(6); |
x(3) := y(7); |
x(2) := y(8); |
x(1) := y(9); |
x(0) := y(10); |
|
tmp_data(15 downto 5) := x; |
y(4 downto 0) := crc5( X"1F", x ); |
tmp_data(4 downto 0) := not(y(4 downto 0)); |
txmem(0) := not(USBF_T_PID_SOF)&USBF_T_PID_SOF; -- PID |
txmem(1) := tmp_data(8)&tmp_data(9)&tmp_data(10)&tmp_data(11)& |
tmp_data(12)&tmp_data(13)&tmp_data(14)&tmp_data(15); |
txmem(2) := tmp_data(0)&tmp_data(1)&tmp_data(2)&tmp_data(3)& |
tmp_data(4)&tmp_data(5)&tmp_data(6)&tmp_data(7); |
txmem(1) := frmnv(7 downto 0); |
txmem(2) := tmp_data(0)&tmp_data(1)&tmp_data(2)&tmp_data(3)& |
tmp_data(4)& frmnv(10 downto 8); |
utmi_send_pack(3,usbtxdata,usbtxvalid); |
end procedure send_sof; |
|
|
procedure buswrite(constant adr : in std_logic_vector(31 downto 0); |
constant data : in std_logic_vector(31 downto 0); |
signal Bus2IP_Clk : in std_logic; |
signal Bus2IP_Addr : out std_logic_vector(0 to 31); |
signal Bus2IP_Data : out std_logic_vector(0 to 31); |
signal Bus2IP_BE : out std_logic_vector(0 to 3); |
signal Bus2IP_CS : out std_logic; |
signal Bus2IP_CE : out std_logic; |
signal Bus2IP_RNW : out std_logic; |
signal IP2Bus_Data : in std_logic_vector(0 to 31); |
signal IP2Bus_Ack : in std_logic) is |
begin |
wait until (Bus2IP_Clk='1' and Bus2IP_Clk'event); |
wait for 1 ns; |
Bus2IP_Addr <= adr; |
Bus2IP_Data <= data; |
Bus2IP_RNW <= '0'; |
Bus2IP_CE <= '1'; |
Bus2IP_CS <= '1'; |
Bus2IP_BE <= "1111"; |
wait until (Bus2IP_Clk'event and Bus2IP_Clk='1' and IP2Bus_Ack='1'); |
wait for 1 ns; |
Bus2IP_Addr <= (others=>'0'); |
Bus2IP_Data <= (others=>'0'); |
Bus2IP_RNW <= '0'; |
Bus2IP_CE <= '0'; |
Bus2IP_CS <= '0'; |
Bus2IP_BE <= "0000"; |
end buswrite; |
|
procedure busread (constant adr : in std_logic_vector(31 downto 0); |
variable data : out std_logic_vector(31 downto 0); |
signal Bus2IP_Clk : in std_logic; |
signal Bus2IP_Addr : out std_logic_vector(0 to 31); |
signal Bus2IP_Data : out std_logic_vector(0 to 31); |
signal Bus2IP_BE : out std_logic_vector(0 to 3); |
signal Bus2IP_CS : out std_logic; |
signal Bus2IP_CE : out std_logic; |
signal Bus2IP_RNW : out std_logic; |
signal IP2Bus_Data : in std_logic_vector(0 to 31); |
signal IP2Bus_Ack : in std_logic) is |
begin |
wait until (Bus2IP_Clk='1' and Bus2IP_Clk'event); |
wait for 1 ns; |
Bus2IP_Addr <= adr; |
Bus2IP_Data <= (others=>'0'); |
Bus2IP_RNW <= '1'; |
Bus2IP_CS <= '1'; |
Bus2IP_CE <= '1'; |
Bus2IP_BE <= "1111"; |
wait until (Bus2IP_Clk'event and Bus2IP_Clk='1' and IP2Bus_Ack='1'); |
data := IP2Bus_Data; |
wait for 1 ns; |
Bus2IP_Addr <= (others=>'0'); |
Bus2IP_Data <= (others=>'0'); |
Bus2IP_RNW <= '0'; |
Bus2IP_CS <= '0'; |
Bus2IP_CE <= '0'; |
Bus2IP_BE <= "0000"; |
end busread; |
|
procedure uartread (variable d : out std_logic_vector (7 downto 0)) is |
variable tmp : std_logic_vector(31 downto 0); |
-- variable ss : LINE; |
begin |
loop |
busread(X"00000002", tmp, clk, Bus2IP_Addr, Bus2IP_Data, Bus2IP_BE, Bus2IP_CS, Bus2IP_CE, Bus2IP_RNW, IP2Bus_Data, IP2Bus_Ack); |
exit when ((tmp and X"00000001") /= X"00000000"); |
end loop; |
-- DEALLOCATE(ss); |
-- WRITE(ss,string'("uartstatus=")); |
-- HWRITE(ss,tmp); |
-- report ss.all; |
busread(X"00000000", tmp, clk, Bus2IP_Addr, Bus2IP_Data, Bus2IP_BE, Bus2IP_CS, Bus2IP_CE, Bus2IP_RNW, IP2Bus_Data, IP2Bus_Ack); |
d := tmp(7 downto 0); |
end procedure uartread; |
|
procedure uartwrite (variable d : std_logic_vector (7 downto 0)) is |
variable tmp : std_logic_vector(31 downto 0); |
begin |
loop |
busread(X"00000002", tmp, clk, Bus2IP_Addr, Bus2IP_Data, Bus2IP_BE, Bus2IP_CS, Bus2IP_CE, Bus2IP_RNW, IP2Bus_Data, IP2Bus_Ack); |
exit when ((tmp and X"00000004") /= X"00000000"); |
end loop; |
tmp := X"00000000"; |
tmp(7 downto 0) := d; |
buswrite(X"00000001", tmp, clk, Bus2IP_Addr, Bus2IP_Data, Bus2IP_BE, Bus2IP_CS, Bus2IP_CE, Bus2IP_RNW, IP2Bus_Data, IP2Bus_Ack); |
|
end procedure uartwrite; |
|
shared variable nn : integer; |
shared variable pid : std_logic_vector(3 downto 0); |
shared variable ss : LINE; |
shared variable dd : std_logic_vector(7 downto 0); |
shared variable rlen : integer; |
begin |
|
|
resetn <= not(reset); |
rxd <= rxdp; |
|
usb_phy_inst : usb_phy |
port map ( |
clk => usbclk, |
rst => resetn, |
phy_tx_mode => '1', |
usb_rst => open, |
txdp => rxdp, |
txdn => rxdn, |
txoe => open, |
rxd => txdp, |
rxdp => txdp, |
rxdn => txdn, |
|
-- UTMI Interface |
DataOut_i => usbtxdata, |
TxValid_i => usbtxvalid, |
TxReady_o => usbtxready, |
RxValid_o => usbrxvalid, |
RxActive_o => usbrxactive, |
RxError_o => usbrxerror, |
DataIn_o => usbrxdata, |
LineState_o => usblinestate |
); |
|
|
OPB_USBLITE_Core_inst : OPB_USBLITE_Core |
port map ( |
Clk => clk, |
Reset => reset, |
Usb_Clk => usbclk, |
OPB_CS => Bus2IP_CS, |
OPB_ABus => Bus2IP_Addr(30 to 31), |
OPB_RNW => Bus2IP_RNW, |
OPB_DBus => Bus2IP_Data(24 to 31), |
SIn_xferAck => IP2Bus_Ack, |
SIn_DBus => IP2Bus_Data(24 to 31), |
Interrupt => Interrupt, |
txdp => txdp, |
txdn => txdn, |
txoe => txoe, |
rxd => rxd, |
rxdp => rxdp, |
rxdn => rxdn |
); |
|
|
process |
begin |
clk <= '0'; |
wait for 6.66666ns; |
clk <= '1'; |
wait for 6.66666ns; |
end process; |
|
process |
begin |
usbclk <= '0'; |
wait for 10.41666ns; |
usbclk <= '1'; |
wait for 10.41666ns; |
end process; |
|
process(usbclk) |
begin |
if (usbclk'event and usbclk='1') then |
if (usbrxvalid='1') then |
usbrxdata_r <= usbrxdata; |
end if; |
end if; |
end process; |
|
process |
begin |
wait for 100ns; |
reset <= '1'; |
wait for 100ns; |
reset <= '0'; |
wait for 100 us; |
|
report "Setting Address ..."; |
wait for 1 us; |
send_setup( X"00", -- Function Address |
X"00", -- Request Type |
SET_ADDRESS, -- Request |
X"0012", -- wValue |
X"0000", -- wIndex |
X"0000" -- wLength |
); |
|
-- Status OK |
data_in( X"00", -- Function Address |
0 -- Expected payload size |
); |
|
report("Getting DEVICE descriptor ..."); |
send_setup( X"12", -- Function Address |
X"80", -- Request Type |
GET_DESCRIPTOR, -- Request |
X"0100", -- wValue |
X"0000", -- wIndex |
X"0008" -- wLength |
); |
|
data_in( X"12", -- Function Address |
8 -- Expected payload size |
); |
|
-- Status OK |
data_out( X"12", -- Function Address |
0 -- Expected payload size |
); |
|
report("Getting whole DEVICE descriptor ..."); |
send_setup( X"12", -- Function Address |
X"80", -- Request Type |
GET_DESCRIPTOR, -- Request |
X"0100", -- wValue |
X"0000", -- wIndex |
X"0012" -- wLength |
); |
|
data_in( X"12", -- Function Address |
18 -- Expected payload size |
); |
|
-- Status OK |
data_out( X"12", -- Function Address |
0 -- Expected payload size |
); |
|
report "Getting CONFIGURATION descriptor ..."; |
send_setup( X"12", -- Function Address |
X"80", -- Request Type |
GET_DESCRIPTOR, -- Request |
X"0200", -- wValue |
X"0000", -- wIndex |
X"0008" -- wLength |
); |
|
data_in( X"12", -- Function Address |
8 -- Expected payload size |
); |
|
-- Status OK |
data_out( X"12", -- Function Address |
0 -- Expected payload size |
); |
|
report "Getting whole CONFIGURATION descriptor ..."; |
send_setup( X"12", -- Function Address |
X"80", -- Request Type |
GET_DESCRIPTOR, -- Request |
X"0200", -- wValue |
X"0000", -- wIndex |
X"0043" -- wLength |
); |
|
data_in( X"12", -- Function Address |
64 -- Expected payload size |
); |
|
-- Status OK |
data_out( X"12", -- Function Address |
0 -- Expected payload size |
); |
|
data_in( X"12", -- Function Address |
3 -- Expected payload size |
); |
|
-- Status OK |
data_out( X"12", -- Function Address |
0 -- Expected payload size |
); |
|
report "Set configuration 1..."; |
send_setup( X"12", -- Function Address |
X"00", -- Request Type |
SET_CONFIG, -- Request |
X"0001", -- wValue |
X"0000", -- wIndex |
X"0000" -- wLength |
); |
|
data_in( X"12", -- Function Address |
0 -- Expected payload size |
); |
|
wait for 1 us; |
|
report "EP1 OUT..."; |
for nn in 0 to 63 loop |
buffer1(nn) := std_logic_vector(to_unsigned(nn+32,8)); |
end loop; |
buffer1_last := 0; |
pid := "0000"; |
|
send_sof(0); -- Send SOF |
wait until rising_edge(usbclk); |
|
send_token( X"12", -- Function Address |
X"1", -- Logical Endpoint Number |
USBF_T_PID_OUT -- PID |
); |
|
wait until rising_edge(usbclk); |
|
if (pid="0000") then |
send_data(USBF_T_PID_DATA0, 64, 1); |
else |
send_data(USBF_T_PID_DATA1, 64, 1); |
end if; |
|
pid := not(pid); |
|
-- Wait for ACK |
utmi_recv_pack(len); |
|
for nn in 0 to 63 loop |
uartread(dd); |
DEALLOCATE(ss); |
WRITE(ss,string'("uartread=")); |
HWRITE(ss,dd); |
report ss.all; |
end loop; |
|
wait for 1 us; |
|
report "EP1 IN..."; |
|
for nn in 0 to 63 loop |
dd := std_logic_vector(to_unsigned(nn,8)); |
DEALLOCATE(ss); |
WRITE(ss,string'("uartwrite=")); |
HWRITE(ss,dd); |
report ss.all; |
uartwrite(dd); |
end loop; |
|
|
-- Send Data |
send_sof(1); -- Send SOF |
send_token( X"12", -- Function Address |
X"1", -- Logical Endpoint Number |
USBF_T_PID_IN -- PID |
); |
|
recv_packet(pid,rlen); |
|
for nn in 0 to 63 loop |
dd := txmem(nn+1); |
DEALLOCATE(ss); |
WRITE(ss,string'("usb recv=")); |
HWRITE(ss,dd); |
report ss.all; |
end loop; |
|
send_token( X"12", -- Function Address |
X"1", -- Logical Endpoint Number |
USBF_T_PID_ACK -- PID |
); |
|
wait for 10us; |
|
reset <= '1'; |
wait for 1us; |
reset <= '0'; |
|
wait; |
end process; |
|
|
end architecture akre; |
/opb_usblite/tags/R1/pcores/opb_usblite_v1_00_a/hdl/vhdl/opb_usblite.vhd
0,0 → 1,204
-- |
-- opb_usblite - opb_uartlite replacement |
-- |
-- opb_usblite is using components from Rudolf Usselmann see |
-- http://www.opencores.org/cores/usb_phy/ |
-- and Joris van Rantwijk see http://www.xs4all.nl/~rjoris/fpga/usb.html |
-- |
-- Copyright (C) 2010 Ake Rehnman |
-- |
-- This program is free software: you can redistribute it and/or modify |
-- it under the terms of the GNU Lesser General Public License as published by |
-- the Free Software Foundation, either version 3 of the License, or |
-- (at your option) any later version. |
-- |
-- This program is distributed in the hope that it will be useful, |
-- but WITHOUT ANY WARRANTY; without even the implied warranty of |
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
-- GNU Lesser General Public License for more details. |
-- |
-- You should have received a copy of the GNU Lesser General Public License |
-- along with this program. If not, see <http://www.gnu.org/licenses/>. |
-- |
library IEEE; |
use IEEE.std_logic_1164.all; |
|
entity OPB_USBLITE is |
generic ( |
C_OPB_AWIDTH : integer := 32; |
C_OPB_DWIDTH : integer := 32; |
C_BASEADDR : std_logic_vector(0 to 31) := X"FFFF_0000"; |
C_HIGHADDR : std_logic_vector := X"FFFF_00FF"; |
C_SYSRST : std_logic := '1'; -- enable external reset |
C_PHYMODE : std_logic := '1'; -- phy mode |
C_VENDORID : std_logic_vector(15 downto 0) := X"1234"; -- VID |
C_PRODUCTID : std_logic_vector(15 downto 0) := X"5678"; -- PID |
C_VERSIONBCD : std_logic_vector(15 downto 0) := X"0200"; -- device version |
C_SELFPOWERED : boolean := false; -- self or bus powered |
C_RXBUFSIZE_BITS: integer range 7 to 12 := 10; -- size of rx buf (2^10 = 1024 bytes) |
C_TXBUFSIZE_BITS: integer range 7 to 12 := 10 -- size of tx buf (2^10 = 1024 bytes) |
); |
port ( |
-- Global signals |
OPB_Clk : in std_logic; |
OPB_Rst : in std_logic; |
SYS_Rst : in std_logic; |
USB_Clk : in std_logic; |
-- OPB signals |
OPB_ABus : in std_logic_vector(0 to 31); |
OPB_BE : in std_logic_vector(0 to 3); |
OPB_RNW : in std_logic; |
OPB_select : in std_logic; |
OPB_seqAddr : in std_logic; |
OPB_DBus : in std_logic_vector(0 to 31); |
Sl_DBus : out std_logic_vector(0 to 31); |
Sl_errAck : out std_logic; |
Sl_retry : out std_logic; |
Sl_toutSup : out std_logic; |
Sl_xferAck : out std_logic; |
|
-- Interrupt |
Interrupt : out std_logic; |
|
-- USB signals |
txdp : out std_logic; -- connect to VPO |
txdn : out std_logic; -- connect to VMO/FSEO |
txoe : out std_logic; -- connect to OE |
rxd : in std_logic; -- connect to RCV |
rxdp : in std_logic; -- connect to VP |
rxdn : in std_logic -- connect to VM |
); |
|
end entity OPB_USBLITE; |
|
library Common_v1_00_a; |
use Common_v1_00_a.pselect; |
|
library unisim; |
use unisim.all; |
|
library opb_usblite_v1_00_a; |
use opb_usblite_v1_00_a.opb_usblite_core; |
|
architecture akre of OPB_USBLITE is |
|
component pselect is |
generic ( |
C_AB : integer; |
C_AW : integer; |
C_BAR : std_logic_vector); |
port ( |
A : in std_logic_vector(0 to C_AW-1); |
AValid : in std_logic; |
ps : out std_logic); |
end component pselect; |
|
component OPB_USBLITE_Core is |
generic ( |
C_PHYMODE : std_logic := '1'; |
C_VENDORID : std_logic_vector(15 downto 0) := X"1234"; |
C_PRODUCTID : std_logic_vector(15 downto 0) := X"5678"; |
C_VERSIONBCD : std_logic_vector(15 downto 0) := X"0200"; |
C_SELFPOWERED : boolean := false; |
C_RXBUFSIZE_BITS: integer range 7 to 12 := 10; |
C_TXBUFSIZE_BITS: integer range 7 to 12 := 10 |
); |
port ( |
Clk : in std_logic; |
Reset : in std_logic; |
Usb_Clk : in std_logic; |
-- OPB signals |
OPB_CS : in std_logic; |
OPB_ABus : in std_logic_vector(0 to 1); |
OPB_RNW : in std_logic; |
OPB_DBus : in std_logic_vector(7 downto 0); |
SIn_xferAck : out std_logic; |
SIn_DBus : out std_logic_vector(7 downto 0); |
Interrupt : out std_logic; |
-- USB signals |
txdp : out std_logic; |
txdn : out std_logic; |
txoe : out std_logic; |
rxd : in std_logic; |
rxdp : in std_logic; |
rxdn : in std_logic |
); |
end component OPB_USBLITE_Core; |
|
function nbits (x, y : std_logic_vector(0 to C_OPB_AWIDTH-1)) return integer is |
begin |
for i in 0 to C_OPB_AWIDTH-1 loop |
if x(i) /= y(i) then |
return i; |
end if; |
end loop; |
return(C_OPB_AWIDTH); |
end function nbits; |
|
constant C_NBITS : integer := nbits(C_HIGHADDR, C_BASEADDR); |
|
signal OPB_CS : std_logic; |
signal core_rst : std_logic; |
|
begin -- architecture akre |
|
|
----------------------------------------------------------------------------- |
-- OPB bus interface |
----------------------------------------------------------------------------- |
|
-- Do the OPB address decoding |
pselect_I : pselect |
generic map ( |
C_AB => C_NBITS, |
C_AW => C_OPB_AWIDTH, |
C_BAR => C_BASEADDR) |
port map ( |
A => OPB_ABus, |
AValid => OPB_select, |
ps => OPB_CS); |
|
|
Sl_errAck <= '0'; |
Sl_retry <= '0'; |
Sl_toutSup <= '0'; |
Sl_DBus(0 to 23) <= (others=>'0'); |
|
----------------------------------------------------------------------------- |
-- Instanciating the USB core |
----------------------------------------------------------------------------- |
|
core_rst <= SYS_Rst when C_SYSRST='1' else OPB_Rst; |
|
OPB_USBLITE_Core_inst : OPB_USBLITE_Core |
generic map ( |
C_PHYMODE => C_PHYMODE, |
C_VENDORID => C_VENDORID, |
C_PRODUCTID => C_PRODUCTID, |
C_VERSIONBCD => C_VERSIONBCD, |
C_SELFPOWERED => C_SELFPOWERED, |
C_RXBUFSIZE_BITS => C_RXBUFSIZE_BITS, |
C_TXBUFSIZE_BITS => C_TXBUFSIZE_BITS |
) |
port map ( |
Clk => OPB_Clk, |
Reset => core_rst, |
Usb_Clk => USB_Clk, |
-- OPB signals |
OPB_CS => OPB_CS, |
OPB_ABus => OPB_ABus(28 to 29), |
OPB_RNW => OPB_RNW, |
OPB_DBus => OPB_DBus(24 to 31), |
SIn_xferAck => Sl_xferAck, |
SIn_DBus => Sl_DBus(24 to 31), |
Interrupt => Interrupt, |
-- USB signals |
txdp => txdp, |
txdn => txdn, |
txoe => txoe, |
rxd => rxd, |
rxdp => rxdp, |
rxdn => rxdn |
); |
|
end architecture akre; |
/opb_usblite/tags/R1/pcores/opb_usblite_v1_00_a/hdl/vhdl/usb_serial.vhdl
0,0 → 1,1061
-- |
-- 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; |
|
/opb_usblite/tags/R1/pcores/opb_usblite_v1_00_a/hdl/vhdl/usb_transact.vhdl
0,0 → 1,628
-- |
-- USB 2.0 Transaction-level logic |
-- |
-- This entity deals with transactions. A transaction consists of up to |
-- three packets: token, data, handshake. This component supports four |
-- transaction types: |
-- * IN (device-to-host bulk/interrupt/control transfer) |
-- * OUT (host-to-device bulk/interrupt/control transfer) |
-- * SETUP (host-to-device control operation) |
-- * PING (flow control for host-to-device bulk/control transfer, HS only) |
-- Isochronous transactions are not supported. |
-- |
-- The low-level interface signals are named P_xxx and connect to |
-- the usb_packet component. |
-- |
-- The application interface signals are named T_xxx and operate as |
-- follows: |
-- |
-- * At the start of a transaction, either T_IN, T_OUT, T_SETUP or T_PING |
-- rises to 1, indicating the transaction type. At the same time, |
-- T_ENDPT is set to the endpoint number for this transaction. |
-- These signals are held for the duration of the transaction. |
-- |
-- OUT and SETUP transactions: |
-- * Each incoming byte is put on RXDAT and announced by asserting RXRDY. |
-- These signals are valid for only one clock cycle. |
-- * OSYNC is set to the transmitter's sync bit and held until the end |
-- of the transaction. |
-- * The last two bytes are CRC bytes; these should be ignored. |
-- * Successfull completion is indicated by asserting T_FIN for one cycle. |
-- * Receive errors are indicated by deasserting T_OUT/T_SETUP without |
-- ever asserting T_FIN. In this case, the application must discard any |
-- data already accepted during this transaction. |
-- * It is probably safe to assume that the first assertion of T_RXRDY |
-- does not immediately coincide with the rising T_OUT/T_SETUP signal. |
-- The implementation of usb_control and usb_serial depend on this |
-- assumption. The assumption may be false if PHY_RXACTIVE is low for |
-- only one clock between token and data, and re-assertion of PHY_RXACTIVE |
-- coincides with assertion of PHY_RXVALID. This is not explicitly |
-- prohibited in the UTMI spec, but it just seems extremely unlikely. |
-- |
-- OUT transactions: |
-- * If the application is not ready to accept data, it should assert |
-- either NAK or STALL. These signals must be set up as soon as the last |
-- byte of the packet has been received, and kept stable until the end |
-- of the transaction. |
-- * If the application is ready to accept this OUT packet, but not ready |
-- to accept a subsequent OUT packet, it may assert T_NYET. This signal |
-- must be set up as soon as the last byte of the packet has been received |
-- and kept stable until the end of the transaction. NYET is only valid |
-- in high speed mode; in full speed mode, this entity will ignore the |
-- NYET signal and send ACK instead. |
-- * Note: NAK/STALL/NYET must not be used during SETUP transactions; |
-- the standard specifies that SETUP transactions must always be ACK-ed |
-- and errors reported during the subsequent data transaction. |
-- |
-- IN transactions: |
-- * The application should assert SEND, put the sync bit on ISYNC |
-- and put the first byte on TXDAT. The component will assert TXRDY |
-- to acknowledge each byte; in the following cycle, the application |
-- must either provide the next data byte or release SEND to indicate |
-- the end of the packet. |
-- After T_IN rises, the application must respond within 2 clock cycles. |
-- * The application must not include CRC bytes. |
-- * If the application is not ready to send data, it should assert |
-- either NAK or STALL and keep it asserted until the end of the |
-- transaction. |
-- * An empty packet can be sent by keeping SEND, NAK and STALL |
-- deasserted; the component will interpret this as a zero-length SEND. |
-- * Successfull completion of an IN transaction is indicated by |
-- asserting FIN for one cycle. |
-- * Timeout is indicated by deasserting T_IN without ever asserting FIN. |
-- In this case, the application must assume that the IN transaction |
-- failed. |
-- |
-- PING transactions: |
-- * In high speed mode only, the host may send a PING transaction to which |
-- the application must respond with either ACK or NAK to indicate whether |
-- it is willing to receive a full sized OUT transaction. |
-- * When a PING is received, T_PING is raised and at the same time T_ENDPT |
-- becomes valid. The application must respond within 2 clock cycles. |
-- * If the application is not ready to received data, it should assert T_NAK |
-- and keep it asserted until the end of the transaction. If the application |
-- does not assert either T_NAK or T_STALL, an ACK response will be sent. |
-- |
|
library ieee; |
use ieee.std_logic_1164.all, ieee.numeric_std.all; |
|
entity usb_transact is |
|
generic ( |
|
-- Support high speed mode. |
HSSUPPORT : boolean := false ); |
|
port ( |
|
-- 60 MHz UTMI clock. |
CLK : in std_logic; |
|
-- Synchronous reset of this entity. |
RESET : in std_logic; |
|
-- High during IN transactions. |
T_IN : out std_logic; |
|
-- High during OUT transactions. |
T_OUT : out std_logic; |
|
-- High during SETUP transactions. |
T_SETUP : out std_logic; |
|
-- High during PING transactions. |
T_PING : out std_logic; |
|
-- Indicates successfull completion of a transaction. |
T_FIN : out std_logic; |
|
-- Device address. |
T_ADDR : in std_logic_vector(6 downto 0); |
|
-- Endpoint number for current transaction. |
T_ENDPT : out std_logic_vector(3 downto 0); |
|
-- Triggers a NAK response to IN/OUT/PING. |
T_NAK : in std_logic; |
|
-- Triggers a STALL response to IN/OUT. |
T_STALL : in std_logic; |
|
-- Triggers a NYET response to OUT. |
T_NYET : in std_logic; |
|
-- High while application has data to send (in response to OUT). |
T_SEND : in std_logic; |
|
-- Sync bit to use for IN transactions. |
T_ISYNC : in std_logic; |
|
-- Sync bit used for the current OUT transaction. |
T_OSYNC : out std_logic; |
|
-- Indicates next byte received. |
T_RXRDY : out std_logic; |
|
-- Received data; valid when T_RXRDY = '1'. |
T_RXDAT : out std_logic_vector(7 downto 0); |
|
-- Requests next byte to transmit; application must update T_TXDAT or T_SEND in next cycle. |
T_TXRDY : out std_logic; |
|
-- Data byte to transmit; must be valid when T_SEND = '1'. |
T_TXDAT : in std_logic_vector(7 downto 0); |
|
-- Connect to I_HIGHSPEED from usb_init. |
I_HIGHSPEED : in std_logic; |
|
-- Connect to P_RXACT from usb_packet. |
P_RXACT : in std_logic; |
|
-- Connect to P_RXRDY from usb_packet. |
P_RXRDY : in std_logic; |
|
-- Connect to P_RXFIN from usb_packet. |
P_RXFIN : in std_logic; |
|
-- Connect to P_RXDAT from usb_packet. |
P_RXDAT : in std_logic_vector(7 downto 0); |
|
-- Connect to P_TXACT towards usb_packet. |
P_TXACT : out std_logic; |
|
-- Connect to P_TXRDY from usb_packet. |
P_TXRDY : in std_logic; |
|
-- Connect to P_TXDAT towards usb_packet. |
P_TXDAT : out std_logic_vector(7 downto 0) ); |
|
end entity usb_transact; |
|
architecture usb_transact_arch of usb_transact is |
|
-- PID constants |
constant pid_out : std_logic_vector(3 downto 0) := "0001"; |
constant pid_in : std_logic_vector(3 downto 0) := "1001"; |
constant pid_setup: std_logic_vector(3 downto 0) := "1101"; |
constant pid_ack : std_logic_vector(3 downto 0) := "0010"; |
constant pid_nak : std_logic_vector(3 downto 0) := "1010"; |
constant pid_stall: std_logic_vector(3 downto 0) := "1110"; |
constant pid_nyet : std_logic_vector(3 downto 0) := "0110"; |
constant pid_ping : std_logic_vector(3 downto 0) := "0100"; |
constant pid_data : std_logic_vector(2 downto 0) := "011"; |
|
function pid_mirror(v: std_logic_vector) return std_logic_vector |
is begin |
return (not v) & v; |
end function; |
|
-- State machine |
type t_state is ( |
ST_IDLE, ST_SKIP, |
ST_GETTOKEN1, ST_GETTOKEN2, ST_GETTOKEN3, ST_GOTTOKEN, |
ST_SENDSHAKE, |
ST_GETDATA, ST_GOTDATA, |
ST_SENDDATA, ST_SENDING, |
ST_WAITACK, ST_WAITSKIP, ST_GETACK ); |
signal s_state : t_state := ST_IDLE; |
signal s_active : std_logic; |
|
-- Transaction state |
signal s_in : std_logic := '0'; |
signal s_out : std_logic := '0'; |
signal s_setup : std_logic := '0'; |
signal s_ping : std_logic := '0'; |
signal s_finished : std_logic := '0'; |
|
-- Previous value of P_RXACT; needed to detect bad packet while waiting for host. |
signal s_prevrxact : std_logic; |
|
-- PID byte to use for outgoing packet (ST_SENDSHAKE or ST_SENDDATA) |
signal s_sendpid : std_logic_vector(3 downto 0); |
|
-- Registered output signals |
signal s_endpt : std_logic_vector(3 downto 0) := "0000"; |
signal s_osync : std_logic := '0'; |
|
-- In full speed mode, we must time out an expected host response after |
-- 16 to 18 bit periods. In high speed mode, we must time out after |
-- 736 to 816 bit periods. We can not get accurate timing because we don't |
-- know the delay due to CRC, EOP, SYNC and UTMI pipeline. (We should use |
-- PHY_LINESTATE for timing, but we don't.) So we just use a much longer |
-- timeout; wait_timeout_fs = 511 cycles = 102 bit periods; |
-- wait_timeout_hs = 127 cycles = 1020 bit periods. |
constant wait_timeout_fs : unsigned(8 downto 0) := "111111111"; |
constant wait_timeout_hs : unsigned(8 downto 0) := "001111111"; |
|
-- In full speed mode, we must wait at least 2 and at most 6.5 bit periods |
-- before responding to the host. We have wait_send_fs = 14 cycles from |
-- rising T_IN/OUT/SETUP until valid T_NAK; equals 16 cycles from rising |
-- P_RXFIN until rising P_TXACT; equals 18 cycles from falling PHY_RXACTIVE |
-- until rising PHY_TXVALID. Including pipeline delay in the UTMI, we end |
-- up with 2 to 5 bit periods from SE0-to-J until SYNC. |
constant wait_send_fs : unsigned(8 downto 0) := "000001110"; |
|
-- In high speed mode, we must wait at least 8 and at most 192 bit periods |
-- before responding to the host. We give the application wait_send_hs = 2 |
-- cycles to get its act together; i.e. from rising T_IN/OUT/SETUP/PING |
-- until valid T_NAK/STALL/NYET/SEND. This corresponds to 4 cycles from |
-- P_RXFIN until P_TXACT; equals 6 cycles from falling PHY_RXACTIVE until |
-- rising PHY_TXVALID. Including pipeline delay in the UTMI, we end up |
-- with 78 to 127 bit periods between packets. |
constant wait_send_hs : unsigned(8 downto 0) := "000000010"; |
|
-- Count down timer. |
signal wait_count : unsigned(8 downto 0); |
|
begin |
|
-- Assign control signals |
s_active <= |
'1' when (s_state = ST_IDLE or s_state = ST_GOTTOKEN or |
s_state = ST_SENDSHAKE or |
s_state = ST_GETDATA or s_state = ST_GOTDATA or |
s_state = ST_SENDDATA or s_state = ST_SENDING or |
s_state = ST_WAITACK or s_state = ST_WAITSKIP or s_state = ST_GETACK) |
else '0'; |
T_IN <= s_in and s_active; |
T_OUT <= s_out and s_active; |
T_SETUP <= s_setup and s_active; |
T_PING <= s_ping and s_active; |
T_FIN <= s_finished; -- Note: T_FIN only occurs when s_state = ST_IDLE |
T_ENDPT <= s_endpt; |
T_OSYNC <= s_osync; |
|
-- Received bytes |
T_RXRDY <= P_RXRDY when (s_state = ST_GETDATA) else '0'; |
T_RXDAT <= P_RXDAT; |
|
-- Byte to transmit: handshake PID, data PID or data byte |
T_TXRDY <= P_TXRDY when (s_state = ST_SENDING) else '0'; |
P_TXACT <= '1' when (s_state = ST_SENDSHAKE or s_state = ST_SENDDATA or |
(s_state = ST_SENDING and T_SEND = '1')) |
else '0'; |
P_TXDAT <= pid_mirror(s_sendpid) when (s_state = ST_SENDSHAKE or s_state = ST_SENDDATA) |
else T_TXDAT; |
|
|
-- On every rising clock edge |
process is |
begin |
wait until rising_edge(CLK); |
|
s_prevrxact <= P_RXACT; |
|
if RESET = '1' then |
|
-- Reset this component |
s_state <= ST_IDLE; |
s_in <= '0'; |
s_out <= '0'; |
s_setup <= '0'; |
s_ping <= '0'; |
s_finished <= '0'; |
|
else |
|
case s_state is |
|
when ST_IDLE => |
-- Idle; wait for incoming packet |
s_in <= '0'; |
s_out <= '0'; |
s_setup <= '0'; |
s_ping <= '0'; |
s_finished <= '0'; |
if P_RXRDY = '1' then |
case P_RXDAT(3 downto 0) is |
when pid_out => |
-- OUT token |
s_out <= '1'; |
s_state <= ST_GETTOKEN1; |
when pid_in => |
-- IN token |
s_in <= '1'; |
s_state <= ST_GETTOKEN1; |
when pid_setup => |
-- SETUP token |
s_setup <= '1'; |
s_state <= ST_GETTOKEN1; |
when pid_ping => |
-- PING token |
if HSSUPPORT then |
s_ping <= '1'; |
s_state <= ST_GETTOKEN1; |
else |
-- no PINGing for full speed devices |
s_state <= ST_SKIP; |
end if; |
when others => |
-- unexpected packet |
s_state <= ST_SKIP; |
end case; |
end if; |
|
when ST_SKIP => |
-- Skip incoming packet and go back to IDLE |
if P_RXACT = '0' then |
s_state <= ST_IDLE; |
end if; |
|
when ST_GETTOKEN1 => |
-- Receive and check 2nd byte of a token packet |
if P_RXACT = '0' then |
-- Bad packet |
s_state <= ST_IDLE; |
elsif P_RXRDY = '1' then |
-- Store endpoint number |
s_endpt(0) <= P_RXDAT(7); |
-- Check address |
if P_RXDAT(6 downto 0) = T_ADDR then |
-- Packet is addressed to us |
s_state <= ST_GETTOKEN2; |
else |
-- Packet not addressed to us |
s_state <= ST_SKIP; |
end if; |
end if; |
|
when ST_GETTOKEN2 => |
-- Receive 3rd byte of token packet |
if P_RXACT = '0' then |
-- Bad packet |
s_state <= ST_IDLE; |
elsif P_RXRDY = '1' then |
-- Store endpoint number |
s_endpt(3 downto 1) <= P_RXDAT(2 downto 0); |
s_state <= ST_GETTOKEN3; |
end if; |
|
when ST_GETTOKEN3 => |
-- Wait for end of incoming token packet |
if P_RXFIN = '1' then |
-- Token was ok |
s_state <= ST_GOTTOKEN; |
elsif P_RXACT = '0' then |
-- Token was bad |
s_state <= ST_IDLE; |
end if; |
if (s_in = '1') or (HSSUPPORT and (s_ping = '1')) then |
if HSSUPPORT and (I_HIGHSPEED = '1') then |
wait_count <= wait_send_hs; |
else |
wait_count <= wait_send_fs; |
end if; |
else |
if HSSUPPORT and (I_HIGHSPEED = '1') then |
wait_count <= wait_timeout_hs; |
else |
wait_count <= wait_timeout_fs; |
end if; |
end if; |
|
when ST_GOTTOKEN => |
-- Wait for data packet or wait for our turn to respond |
if P_RXACT = '1' then |
if P_RXRDY = '1' then |
-- Got PID byte |
if ((s_out = '1') or (s_setup = '1')) and |
(P_RXDAT(2 downto 0) = pid_data) then |
-- This is the DATA packet we were waiting for |
s_osync <= P_RXDAT(3); |
s_state <= ST_GETDATA; |
else |
-- Got unexpected packet |
s_in <= '0'; |
s_out <= '0'; |
s_setup <= '0'; |
s_ping <= '0'; |
case P_RXDAT(3 downto 0) is |
when pid_out => |
-- unexpected OUT token |
s_out <= '1'; |
s_state <= ST_GETTOKEN1; |
when pid_in => |
-- unexpected IN token |
s_in <= '1'; |
s_state <= ST_GETTOKEN1; |
when pid_setup => |
-- unexpected SETUP token |
s_setup <= '1'; |
s_state <= ST_GETTOKEN1; |
when pid_ping => |
-- unexpected PING token |
if HSSUPPORT then |
s_ping <= '1'; |
s_state <= ST_GETTOKEN1; |
else |
-- no PINGing for full speed devices |
s_state <= ST_SKIP; |
end if; |
when others => |
-- unexpected packet |
s_state <= ST_SKIP; |
end case; |
end if; |
end if; |
elsif s_prevrxact = '1' then |
-- got bad packet |
s_state <= ST_IDLE; |
elsif wait_count = 0 then |
-- timer reached zero |
if s_in = '1' then |
-- IN transaction: send response |
if T_STALL = '1' then |
s_state <= ST_SENDSHAKE; |
s_sendpid <= pid_stall; |
elsif T_NAK = '1' then |
s_state <= ST_SENDSHAKE; |
s_sendpid <= pid_nak; |
else |
s_state <= ST_SENDDATA; |
s_sendpid <= T_ISYNC & pid_data; |
end if; |
elsif HSSUPPORT and (s_ping = '1') then |
-- PING transaction: send handshake |
s_state <= ST_SENDSHAKE; |
if T_STALL = '1' then |
s_sendpid <= pid_stall; |
elsif T_NAK = '1' then |
s_sendpid <= pid_nak; |
else |
s_sendpid <= pid_ack; |
end if; |
else |
-- OUT/SETUP transaction: |
-- timeout while waiting for DATA packet |
s_state <= ST_IDLE; |
end if; |
end if; |
-- count down timer |
wait_count <= wait_count - 1; |
|
when ST_SENDSHAKE => |
-- Send handshake packet |
if P_TXRDY = '1' then |
-- Handshake done, transaction completed |
s_finished <= '1'; |
s_state <= ST_IDLE; |
end if; |
|
when ST_GETDATA => |
-- Wait for end of incoming data packet |
if P_RXFIN = '1' then |
-- Data packet was good, respond with handshake |
s_state <= ST_GOTDATA; |
elsif P_RXACT = '0' then |
-- Data packet was bad, ignore it |
s_state <= ST_IDLE; |
end if; |
if HSSUPPORT and (I_HIGHSPEED = '1') then |
wait_count <= wait_send_hs; |
else |
wait_count <= wait_send_fs; |
end if; |
|
when ST_GOTDATA => |
-- Wait for inter-packet delay before responding |
if wait_count = 0 then |
-- Move to response state |
s_state <= ST_SENDSHAKE; |
if T_STALL = '1' then |
s_sendpid <= pid_stall; |
elsif T_NAK = '1' then |
s_sendpid <= pid_nak; |
elsif HSSUPPORT and (I_HIGHSPEED = '1') and (T_NYET = '1') then |
s_sendpid <= pid_nyet; |
else |
s_sendpid <= pid_ack; |
end if; |
end if; |
wait_count <= wait_count - 1; |
|
when ST_SENDDATA => |
-- Start sending a data packet |
if P_TXRDY = '1' then |
-- Sent PID byte, need first data byte |
s_state <= ST_SENDING; |
end if; |
|
when ST_SENDING => |
-- Send payload of data packet |
if T_SEND = '0' then |
-- End of data packet |
s_state <= ST_WAITACK; |
end if; |
if HSSUPPORT and (I_HIGHSPEED = '1') then |
wait_count <= wait_timeout_hs; |
else |
wait_count <= wait_timeout_fs; |
end if; |
|
when ST_WAITACK => |
-- Wait for ACK handshake |
if P_RXACT = '1' then |
if P_RXRDY = '1' then |
-- Got PID byte |
case P_RXDAT(3 downto 0) is |
when pid_ack => |
-- ACK handshake |
s_state <= ST_GETACK; |
when pid_out => |
-- unexpected OUT token |
s_in <= '0'; |
s_out <= '1'; |
s_state <= ST_GETTOKEN1; |
when pid_in => |
-- unexpected IN token |
s_in <= '1'; |
s_state <= ST_GETTOKEN1; |
when pid_setup => |
-- unexpected SETUP token |
s_in <= '0'; |
s_setup <= '1'; |
s_state <= ST_GETTOKEN1; |
when pid_ping => |
-- unexpected PING token |
if HSSUPPORT then |
s_in <= '0'; |
s_ping <= '1'; |
s_state <= ST_GETTOKEN1; |
else |
-- no PINGing for full speed devices |
s_state <= ST_SKIP; |
end if; |
when ("0" & pid_data) | ("1" & pid_data) => |
-- unexpected DATA packet |
-- This could be our own transmitted packet |
-- (if it was very short), so skip this. |
s_state <= ST_WAITSKIP; |
when others => |
-- unexpected packet |
s_state <= ST_SKIP; |
end case; |
end if; |
elsif s_prevrxact = '1' then |
-- got bad packet |
s_state <= ST_IDLE; |
elsif wait_count = 0 then |
-- timeout while waiting for ACK |
s_state <= ST_IDLE; |
end if; |
-- count down timer |
wait_count <= wait_count - 1; |
|
when ST_WAITSKIP => |
-- Skip the echo of our own transmitted packet |
if wait_count = 0 then |
-- timeout |
s_state <= ST_SKIP; |
elsif P_RXFIN = '1' then |
-- end of packet |
s_state <= ST_WAITACK; |
elsif P_RXACT = '0' then |
-- bad packet |
s_state <= ST_IDLE; |
end if; |
-- count down timer |
wait_count <= wait_count - 1; |
|
when ST_GETACK => |
-- Wait for end of incoming ACK packet |
if P_RXFIN = '1' then |
-- ACK handshake was good |
s_finished <= '1'; |
s_state <= ST_IDLE; |
elsif P_RXACT = '0' then |
-- ACK handshake was bad |
s_state <= ST_IDLE; |
end if; |
|
end case; |
|
end if; |
|
end process; |
|
end architecture usb_transact_arch; |
/opb_usblite/tags/R1/pcores/opb_usblite_v1_00_a/hdl/vhdl/usb_control.vhdl
0,0 → 1,623
-- |
-- USB 2.0 Default control endpoint |
-- |
-- This entity implements the minimal required functionality of |
-- the default control endpoint. |
-- |
-- The low-level interface signals are named T_xxx and should be conditionally |
-- connected to the usb_transact interface in the following way: |
-- * Always connect output signal C_ADDR to T_ADDR; |
-- * Always connect input signals T_FIN, T_OSYNC, T_RXRDY, T_RXDAT, T_TXRDY; |
-- * If T_ENDPT = 0, connect input signals T_IN, T_OUT, T_SETUP, T_PING; |
-- otherwise pull these inputs to zero. |
-- * If T_ENDPT = 0, connect output signals T_NAK, T_STALL, T_NYET, T_SEND, |
-- T_ISYNC, T_TXDAT; otherwise another endpoint should drive these. |
-- * If T_ENDPT = 0 and C_DSCBUSY = 0, connect output signal T_TXDAT; |
-- otherwise if T_ENDPT = 0 and C_DSCBUSY = 1, drive T_TXDAT |
-- from descriptor memory; |
-- otherwise another endpoint drives T_TXDAT. |
-- |
-- A device descriptor and a configuration descriptor must be provided |
-- in external memory. If high speed mode is supported, an other-speed |
-- device qualifier and other-speed configuration descriptor must also |
-- be provided. In addition, string descriptors may optionally be provided. |
-- Each descriptor may be at most 255 bytes long. |
-- A maximum packet size of 64 bytes is assumed for control transfers. |
-- |
-- This entity uses the following protocol to access descriptor data: |
-- * When C_DSCBUSY is high, the entity is accessing descriptor data. |
-- A descriptor is selected by signals C_DSCTYP and C_DSCINX; |
-- a byte within this descriptor is selected by signal C_DSCOFF. |
-- * Based on C_DSCTYP and C_DSCINX, the application must assign |
-- the length of the selected descriptor to C_DSCLEN. If the selected |
-- descriptor does not exist, the application must set C_DSCLEN to zero. |
-- C_DSCLEN must be valid one clock after rising C_DSCBUSY and must |
-- remain stable as long as C_DSCBUSY, C_DSCTYP and C_DSCINX remain |
-- unchanged. |
-- * When C_DSCRD is asserted, the application must put the selected |
-- byte from the selected descriptor on T_TXDAT towards usb_transact. |
-- The application must respond in the first clock cycle following |
-- assertion of C_DSCRD. |
-- * When C_DSCRD is not asserted, but C_DSCBUSY is still high, |
-- the application must keep T_TXDAT unchanged. Changes to C_DSCOFF |
-- must not affect T_TXDAT while C_DSCRD is low. |
-- |
-- The standard device requests are handled as follows: |
-- |
-- Clear Feature: |
-- When clearing the ENDPOINT_HALT feature, reset the endpoint's |
-- sync bits (as required by spec). Otherwise ignore but report |
-- success status. |
-- BAD: should return STALL when referring to invalid endpoint/interface. |
-- |
-- Get Configuration: |
-- Return 1 if configured, 0 if not configured. |
-- |
-- Get Descriptor: |
-- Handled by application through descriptor data interface as |
-- described above. |
-- |
-- Get Interface: |
-- Always return zero byte. |
-- BAD: should return STALL when referring to invalid endpoint/interface. |
-- |
-- Get Status: |
-- Return device status / endpoint status / zero. |
-- BAD: should return STALL when referring to invalid endpoint/interface. |
-- |
-- Set Address: |
-- Store new address. |
-- |
-- Set Configuration: |
-- Switch between Configured and Address states; clear all endpoint |
-- sync bits (as required by spec). Accepts only configuration values |
-- 0 and 1. |
-- |
-- Set Descriptor: |
-- Not implemented; returns STALL. (Correct; request is optional.) |
-- |
-- Set Feature: |
-- Only ENDPOINT_HALT feature implemented; otherwise returns STALL. |
-- BAD: every high speed device must support TEST_MODE. |
-- |
-- Set Interface: |
-- Not implemented; returns STALL. |
-- (Correct; request is optional if no interfaces have alternate settings.) |
-- |
-- Synch Frame: |
-- Not implemented; returns STALL. |
-- (Correct, assuming no isosynchronous endpoints.) |
-- |
-- Non-standard requests are silently ignored but return success status. |
-- This is incorrect, but necessary to get host software to accept usb_serial |
-- as CDC-ACM device. |
-- |
|
library ieee; |
use ieee.std_logic_1164.all, ieee.numeric_std.all; |
|
entity usb_control is |
|
generic ( |
|
-- Highest endpoint number in use. |
NENDPT : integer range 1 to 15 ); |
|
port ( |
|
-- 60 MHz UTMI clock. |
CLK : in std_logic; |
|
-- Synchronous reset of this entity. |
RESET : in std_logic; |
|
-- Current device address. |
C_ADDR : out std_logic_vector(6 downto 0); |
|
-- High when in Configured state. |
C_CONFD : out std_logic; |
|
-- Trigger clearing of sync/halt bits for IN endpoint. |
C_CLRIN : out std_logic_vector(1 to NENDPT); |
|
-- Trigger clearing of sync/halt bits for OUT endpoint. |
C_CLROUT : out std_logic_vector(1 to NENDPT); |
|
-- Current status of halt bit for IN endpoints. |
C_HLTIN : in std_logic_vector(1 to NENDPT); |
|
-- Current status of halt bit for IN endpoints. |
C_HLTOUT : in std_logic_vector(1 to NENDPT); |
|
-- Trigger setting of halt bit for IN endpoints. |
C_SHLTIN : out std_logic_vector(1 to NENDPT); |
|
-- Trigger setting of halt bit for OUT endpoints. |
C_SHLTOUT : out std_logic_vector(1 to NENDPT); |
|
-- High when accessing descriptor memory. |
-- Note that C_DSCBUSY may go low in between packets of a single descriptor. |
C_DSCBUSY : out std_logic; |
|
-- Descriptor read enable. Asserted to request a descriptor byte; |
-- in the next clock cycle, the application must update T_TXDAT. |
C_DSCRD : out std_logic; |
|
-- LSB bits of the requested descriptor type. Valid when C_DSCBUSY is high. |
C_DSCTYP : out std_logic_vector(2 downto 0); |
|
-- Requested descriptor index. Valid when C_DSCBUSY is high. |
C_DSCINX : out std_logic_vector(7 downto 0); |
|
-- Offset within requested descriptor. Valid when C_DSCBUSY and C_DSCRD are high. |
C_DSCOFF : out std_logic_vector(7 downto 0); |
|
-- Set to length of current descriptor by application. |
C_DSCLEN : in std_logic_vector(7 downto 0); |
|
-- High if the device is not drawing bus power. |
C_SELFPOWERED : in std_logic; |
|
-- Connect to T_IN from usb_transact when T_ENDPT = 0, otherwise pull to 0. |
T_IN : in std_logic; |
|
-- Connect to T_OUT from usb_transact when T_ENDPT = 0, otherwise pull to 0. |
T_OUT : in std_logic; |
|
-- Connect to T_SETUP from usb_transact when T_ENDPT = 0, otherwise pull to 0. |
T_SETUP : in std_logic; |
|
-- Connect to T_PING from usb_transact when T_ENDPT = 0, otherwise pull to 0. |
T_PING : in std_logic; |
|
-- Connect to T_FIN from ubs_transact. |
T_FIN : in std_logic; |
|
-- Connect to T_NAK towards usb_transact when T_ENDPT = 0. |
T_NAK : out std_logic; |
|
-- Connect to T_STALL towards usb_transact when T_ENDPT = 0. |
T_STALL : out std_logic; |
|
-- Connect to T_NYET towards usb_transact when T_ENDPT = 0. |
T_NYET : out std_logic; |
|
-- Connect to T_SEND towards usb_transact when T_ENDPT = 0. |
T_SEND : out std_logic; |
|
-- Connect to T_ISYNC towards usb_transact when T_ENDPT = 0. |
T_ISYNC : out std_logic; |
|
-- Connect to T_OSYNC from usb_transact. |
T_OSYNC : in std_logic; |
|
-- Connect to T_RXRDY from usb_transact. |
T_RXRDY : in std_logic; |
|
-- Connect to T_RXDAT from usb_transact. |
T_RXDAT : in std_logic_vector(7 downto 0); |
|
-- Connect to T_TXRDY from usb_transact. |
T_TXRDY : in std_logic; |
|
-- Connect to T_TXDAT towards usb_transact when T_ENDPT = 0 and C_DSCBUSY = '0'. |
T_TXDAT : out std_logic_vector(7 downto 0) ); |
|
end entity usb_control; |
|
architecture usb_control_arch of usb_control is |
|
-- Constants for control request |
constant req_getstatus : std_logic_vector(3 downto 0) := "0000"; |
constant req_clearfeature : std_logic_vector(3 downto 0) := "0001"; |
constant req_setfeature : std_logic_vector(3 downto 0) := "0011"; |
constant req_setaddress : std_logic_vector(3 downto 0) := "0101"; |
constant req_getdesc : std_logic_vector(3 downto 0) := "0110"; |
constant req_getconf : std_logic_vector(3 downto 0) := "1000"; |
constant req_setconf : std_logic_vector(3 downto 0) := "1001"; |
constant req_getiface : std_logic_vector(3 downto 0) := "1010"; |
|
-- State machine |
type t_state is ( |
ST_IDLE, ST_STALL, |
ST_SETUP, ST_SETUPERR, ST_NONSTANDARD, ST_ENDSETUP, ST_WAITIN, |
ST_SENDRESP, ST_STARTDESC, ST_SENDDESC, ST_DONESEND ); |
signal s_state : t_state := ST_IDLE; |
|
-- Current control request |
signal s_ctlrequest : std_logic_vector(3 downto 0); |
signal s_ctlparam : std_logic_vector(7 downto 0); |
signal s_desctyp : std_logic_vector(2 downto 0); |
signal s_answerlen : unsigned(7 downto 0); |
signal s_sendbyte : std_logic_vector(7 downto 0) := "00000000"; |
|
-- Device state |
signal s_addr : std_logic_vector(6 downto 0) := "0000000"; |
signal s_confd : std_logic := '0'; |
|
-- Counters |
signal s_setupptr : unsigned(2 downto 0); |
signal s_answerptr : unsigned(7 downto 0); |
|
begin |
|
-- Status signals |
C_ADDR <= s_addr; |
C_CONFD <= s_confd; |
|
-- Memory interface |
C_DSCBUSY <= T_IN when (s_state = ST_WAITIN) else |
'1' when (s_state = ST_STARTDESC or s_state = ST_SENDDESC) else |
'0'; |
C_DSCRD <= '1' when (s_state = ST_STARTDESC) else T_TXRDY; |
C_DSCTYP <= s_desctyp; |
C_DSCINX <= s_ctlparam; |
C_DSCOFF <= std_logic_vector(s_answerptr); |
|
-- Transaction interface |
T_NAK <= '0'; |
T_STALL <= '1' when (s_state = ST_STALL) else '0'; |
T_NYET <= '0'; |
T_SEND <= '1' when ((s_state = ST_SENDRESP) or (s_state = ST_SENDDESC)) |
else '0'; |
T_ISYNC <= not std_logic(s_answerptr(6)); |
T_TXDAT <= s_sendbyte; |
|
-- On every rising clock edge |
process is |
begin |
wait until rising_edge(CLK); |
|
-- Set endpoint reset/halt lines to zero by default |
C_CLRIN <= (others => '0'); |
C_CLROUT <= (others => '0'); |
C_SHLTIN <= (others => '0'); |
C_SHLTOUT <= (others => '0'); |
|
-- State machine |
if RESET = '1' then |
|
-- Reset this entity |
s_state <= ST_IDLE; |
s_addr <= "0000000"; |
s_confd <= '0'; |
|
-- Trigger endpoint reset lines |
C_CLRIN <= (others => '1'); |
C_CLROUT <= (others => '1'); |
|
else |
|
case s_state is |
|
when ST_IDLE => |
-- Idle; wait for SETUP transaction; |
-- OUT transactions are ignored but acknowledged; |
-- IN transactions send an empty packet. |
s_answerptr <= to_unsigned(0, s_answerptr'length); |
if T_SETUP = '1' then |
-- Start of SETUP transaction |
s_state <= ST_SETUP; |
s_setupptr <= to_unsigned(0, s_setupptr'length); |
end if; |
|
when ST_STALL => |
-- Stalled; wait for next SETUP transaction; |
-- respond to IN/OUT transactions with a STALL handshake. |
if T_SETUP = '1' then |
-- Start of SETUP transaction |
s_state <= ST_SETUP; |
s_setupptr <= to_unsigned(0, s_setupptr'length); |
end if; |
|
when ST_SETUP => |
-- In SETUP transaction; parse request structure. |
s_answerptr <= to_unsigned(0, s_answerptr'length); |
if T_RXRDY = '1' then |
-- Process next request byte |
case s_setupptr is |
when "000" => |
-- bmRequestType |
s_ctlparam <= T_RXDAT; |
if T_RXDAT(6 downto 5) /= "00" then |
-- non-standard device request |
s_state <= ST_NONSTANDARD; |
end if; |
when "001" => |
-- bRequest |
s_ctlrequest <= T_RXDAT(3 downto 0); |
if T_RXDAT(7 downto 4) /= "0000" then |
-- Unknown request |
s_state <= ST_SETUPERR; |
end if; |
when "010" => |
-- wValue lsb |
if s_ctlrequest /= req_getstatus then |
s_ctlparam <= T_RXDAT; |
end if; |
when "011" => |
-- wValue msb |
if s_ctlrequest = req_getdesc then |
if T_RXDAT(7 downto 3) /= "00000" then |
-- Unsupported descriptor type |
s_state <= ST_SETUPERR; |
end if; |
end if; |
-- Store descriptor type (assuming GET_DESCRIPTOR request) |
s_desctyp <= T_RXDAT(2 downto 0); |
when "100" => |
-- wIndex lsb |
case s_ctlrequest is |
when req_clearfeature => |
if s_ctlparam = "00000000" then |
-- Clear ENDPOINT_HALT feature; |
-- store endpoint selector |
s_ctlparam <= T_RXDAT; |
else |
-- Unknown clear feature request |
s_ctlparam <= "00000000"; |
end if; |
when req_setfeature => |
if s_ctlparam = "00000000" then |
-- Set ENDPOINT_HALT feature; |
-- store endpoint selector |
s_ctlparam <= T_RXDAT; |
else |
-- Unsupported set feature request |
s_state <= ST_SETUPERR; |
end if; |
when req_getstatus => |
if s_ctlparam(1 downto 0) = "00" then |
-- Get device status |
s_sendbyte <= "0000000" & C_SELFPOWERED; |
s_ctlparam <= "00000000"; |
elsif s_ctlparam(1 downto 0) = "10" then |
-- Get endpoint status |
s_sendbyte <= "00000000"; |
s_ctlparam <= T_RXDAT; |
else |
-- Probably get interface status |
s_sendbyte <= "00000000"; |
s_ctlparam <= "00000000"; |
end if; |
when others => |
-- Don't care about index. |
end case; |
when "101" => |
-- wIndex msb; don't care |
when "110" => |
-- wLength lsb |
s_answerlen <= unsigned(T_RXDAT); |
when "111" => |
-- wLength msb |
if T_RXDAT /= "00000000" then |
s_answerlen <= "11111111"; |
end if; |
s_state <= ST_ENDSETUP; |
when others => |
-- Impossible |
end case; |
-- Increment position within SETUP packet |
s_setupptr <= s_setupptr + 1; |
elsif T_FIN = '1' then |
-- Got short SETUP packet; answer with STALL status. |
s_state <= ST_STALL; |
elsif T_SETUP = '0' then |
-- Got corrupt SETUP packet; ignore. |
s_state <= ST_IDLE; |
end if; |
|
when ST_SETUPERR => |
-- In SETUP transaction; got request error |
if T_FIN = '1' then |
-- Got good SETUP packet that causes request error |
s_state <= ST_STALL; |
elsif T_SETUP = '0' then |
-- Got corrupt SETUP packet; ignore |
s_state <= ST_IDLE; |
end if; |
|
when ST_NONSTANDARD => |
-- Ignore non-standard requests |
if T_SETUP = '0' then |
s_state <= ST_IDLE; |
end if; |
|
when ST_ENDSETUP => |
-- Parsed request packet; wait for end of SETUP transaction |
if T_FIN = '1' then |
-- Got complet SETUP packet; handle it |
case s_ctlrequest is |
when req_getstatus => |
-- Prepare status byte and move to data stage |
-- If s_ctlparam = 0, the status byte has already |
-- been prepared in state S_SETUP. |
for i in 1 to NENDPT loop |
if unsigned(s_ctlparam(3 downto 0)) = i then |
if s_ctlparam(7) = '1' then |
s_sendbyte <= "0000000" & C_HLTIN(i); |
else |
s_sendbyte <= "0000000" & C_HLTOUT(i); |
end if; |
end if; |
end loop; |
s_state <= ST_WAITIN; |
when req_clearfeature => |
-- Reset endpoint |
for i in 1 to NENDPT loop |
if unsigned(s_ctlparam(3 downto 0)) = i then |
if s_ctlparam(7) = '1' then |
C_CLRIN(i) <= '1'; |
else |
C_CLROUT(i) <= '1'; |
end if; |
end if; |
end loop; |
s_state <= ST_IDLE; |
when req_setfeature => |
-- Set endpoint HALT |
for i in 1 to NENDPT loop |
if unsigned(s_ctlparam(3 downto 0)) = i then |
if s_ctlparam(7) = '1' then |
C_SHLTIN(i) <= '1'; |
else |
C_SHLTOUT(i) <= '1'; |
end if; |
end if; |
end loop; |
s_state <= ST_IDLE; |
when req_setaddress => |
-- Move to status stage |
s_state <= ST_WAITIN; |
when req_getdesc => |
-- Move to data stage |
s_state <= ST_WAITIN; |
when req_getconf => |
-- Move to data stage |
s_state <= ST_WAITIN; |
when req_setconf => |
-- Set device configuration |
if s_ctlparam(7 downto 1) = "0000000" then |
s_confd <= s_ctlparam(0); |
s_state <= ST_IDLE; |
C_CLRIN <= (others => '1'); |
C_CLROUT <= (others => '1'); |
else |
-- Unknown configuration number |
s_state <= ST_STALL; |
end if; |
when req_getiface => |
-- Move to data stage |
s_state <= ST_WAITIN; |
when others => |
-- Unsupported request |
s_state <= ST_STALL; |
end case; |
elsif T_SETUP = '0' then |
-- Got corrupt SETUP packet; ignore |
s_state <= ST_IDLE; |
end if; |
|
when ST_WAITIN => |
-- Got valid SETUP packet; waiting for IN transaction. |
s_answerptr(5 downto 0) <= "000000"; |
if T_SETUP = '1' then |
-- Start of next SETUP transaction |
s_state <= ST_SETUP; |
s_setupptr <= to_unsigned(0, s_setupptr'length); |
elsif T_IN = '1' then |
-- Start of IN transaction; respond to the request |
case s_ctlrequest is |
when req_getstatus => |
-- Respond with status byte, followed by zero byte. |
s_state <= ST_SENDRESP; |
when req_setaddress => |
-- Effectuate change of device address |
s_addr <= s_ctlparam(6 downto 0); |
s_state <= ST_IDLE; |
when req_getdesc => |
-- Respond with descriptor |
s_state <= ST_STARTDESC; |
when req_getconf => |
-- Respond with current configuration |
s_sendbyte <= "0000000" & s_confd; |
s_state <= ST_SENDRESP; |
when req_getiface => |
-- Respond with zero byte |
s_sendbyte <= "00000000"; |
s_state <= ST_SENDRESP; |
when others => |
-- Impossible |
end case; |
end if; |
|
when ST_SENDRESP => |
-- Respond to IN with a preset byte, |
-- followed by zero or more nul byte(s) |
if T_IN = '0' then |
-- Aborted IN transaction; wait for retry |
s_state <= ST_WAITIN; |
elsif T_TXRDY = '1' then |
-- Need next data byte |
s_sendbyte <= "00000000"; |
if (s_answerptr(0) = '1') or (s_answerlen(0) = '1') then |
-- Reached end of transfer. |
-- Note that we only ever send 1 or 2 byte answers. |
s_state <= ST_DONESEND; |
end if; |
s_answerptr(5 downto 0) <= s_answerptr(5 downto 0) + 1; |
end if; |
|
when ST_STARTDESC => |
-- Fetching first byte of packet. |
if T_IN = '0' then |
-- Aborted IN transaction; wait for retry |
s_state <= ST_WAITIN; |
elsif unsigned(C_DSCLEN) = 0 then |
-- Invalid descriptor. |
s_state <= ST_STALL; |
elsif (s_answerptr = unsigned(C_DSCLEN)) or |
(s_answerptr = s_answerlen) then |
-- Send an empty packet to complete the transfer. |
s_state <= ST_DONESEND; |
else |
-- Send a normal descriptor packet. |
s_state <= ST_SENDDESC; |
end if; |
s_answerptr(5 downto 0) <= s_answerptr(5 downto 0) + 1; |
|
when ST_SENDDESC => |
-- Respond to IN with descriptor |
if T_IN = '0' then |
-- Aborted IN transaction; wait for retry |
s_state <= ST_WAITIN; |
elsif T_TXRDY = '1' then |
-- Need next data byte |
if (s_answerptr(5 downto 0) = 0) or |
(s_answerptr = unsigned(C_DSCLEN)) or |
(s_answerptr = s_answerlen) then |
-- Just sent the last byte of the packet |
s_state <= ST_DONESEND; |
else |
s_answerptr(5 downto 0) <= s_answerptr(5 downto 0) + 1; |
end if; |
end if; |
|
when ST_DONESEND => |
-- Done sending packet; wait until IN transaction completes. |
-- Note: s_answerptr contains the number of bytes sent so-far, |
-- unless this is a multiple of 64, in which case s_answerptr |
-- contains 64 less than the number of bytes sent; and unless |
-- the last packet sent was an empty end-of-transfer packet, |
-- in which case s_answerptr contains 1 more than the number |
-- of bytes sent. |
if T_FIN = '1' then |
-- Host acknowledged transaction. |
if s_answerptr(5 downto 0) = 0 then |
-- The last sent packet was a full sized packet. |
-- If s_answerptr + 64 = s_answerlen, the transfer |
-- is now complete; otherwise the host will expect |
-- more data. In either case, we go back to WAITIN. |
-- This can't go wrong because WAITIN also listens |
-- for the next SETUP and handles it properly. |
s_state <= ST_WAITIN; |
else |
-- The last sent packet was not full sized; |
-- it was either empty or reached the end of |
-- the descriptor. In either case, the transfer |
-- is now complete. |
s_state <= ST_IDLE; |
end if; |
s_answerptr <= s_answerptr + 64; |
elsif T_IN = '0' then |
-- Transaction failed; wait for retry. |
s_state <= ST_WAITIN; |
end if; |
|
end case; |
|
end if; |
|
end process; |
|
end architecture usb_control_arch; |
/opb_usblite/tags/R1/pcores/opb_usblite_v1_00_a/hdl/vhdl/usb_pkg.vhdl
0,0 → 1,163
-- |
-- USB 2.0 VHDL package |
-- |
|
library ieee; |
use ieee.std_logic_1164.all, ieee.numeric_std.all; |
|
package usb_pkg is |
|
-- Initialization, handshake, reset. |
component usb_init is |
generic ( |
HSSUPPORT : boolean := false ); -- Support high speed mode |
port ( |
CLK : in std_logic; -- 60 MHz UTMI clock |
RESET : in std_logic; -- Synchronous reset |
I_USBRST : out std_logic; -- High when bus reset signal detected |
I_HIGHSPEED : out std_logic; -- High when attached at high speed |
I_SUSPEND : out std_logic; -- High when suspended |
P_CHIRPK : out std_logic; |
PHY_RESET : out 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 ); |
end component usb_init; |
|
-- Packet-level logic and CRC handling. |
component usb_packet is |
port ( |
CLK : in std_logic; -- 60 MHz UTMI clock |
RESET : in std_logic; -- Synchronous reset of this entity |
P_CHIRPK : in std_logic; -- High to force chirp K transmission |
P_RXACT : out std_logic; -- High while receiving a packet |
P_RXRDY : out std_logic; -- Indicates arrival of a byte |
P_RXFIN : out std_logic; -- Indicates successfull completion |
P_RXDAT : out std_logic_vector(7 downto 0); -- Received byte value |
P_TXACT : in std_logic; -- High while transmitting a packet |
P_TXRDY : out std_logic; -- Request for next data byte |
P_TXDAT : in std_logic_vector(7 downto 0); -- Data byte to transmit |
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 ); |
end component usb_packet; |
|
-- Transaction-level logic. |
component usb_transact is |
generic ( |
HSSUPPORT : boolean := false ); -- Support high speed mode |
port ( |
CLK : in std_logic; -- 60 MHz UTMI clock |
RESET : in std_logic; -- Synchronous reset of this entity |
T_IN : out std_logic; -- High during IN transactions |
T_OUT : out std_logic; -- High during OUT transactions |
T_SETUP : out std_logic; -- High during SETUP transactions |
T_PING : out std_logic; -- High during PING transactions |
T_FIN : out std_logic; -- Indicates successfull completion |
T_ADDR : in std_logic_vector(6 downto 0); -- Device address |
T_ENDPT : out std_logic_vector(3 downto 0); -- Endpoint number |
T_NAK : in std_logic; -- Triggers a NAK response to IN/OUT |
T_STALL : in std_logic; -- Triggers a STALL response to IN/OUT |
T_NYET : in std_logic; -- Triggers a NYET response to OUT |
T_SEND : in std_logic; -- High while application has data to send |
T_ISYNC : in std_logic; -- Sync bit to use for IN transactions |
T_OSYNC : out std_logic; -- Sync bit used in the OUT transaction |
T_RXRDY : out std_logic; -- Indicates arrival of received byte |
T_RXDAT : out std_logic_vector(7 downto 0); -- Received data |
T_TXRDY : out std_logic; -- Requests next data byte to transmit |
T_TXDAT : in std_logic_vector(7 downto 0); -- Data to transmit |
I_HIGHSPEED : in std_logic; |
P_RXACT : in std_logic; |
P_RXRDY : in std_logic; |
P_RXFIN : in std_logic; |
P_RXDAT : in std_logic_vector(7 downto 0); |
P_TXACT : out std_logic; |
P_TXRDY : in std_logic; |
P_TXDAT : out std_logic_vector(7 downto 0) ); |
end component usb_transact; |
|
-- Default control endpoint. |
component usb_control is |
generic ( |
NENDPT : integer range 1 to 15 ); -- Highest endpoint number in use |
port ( |
CLK : in std_logic; -- 60 MHz UTMI clock |
RESET : in std_logic; -- Synchronous reset of this entity |
C_ADDR : out std_logic_vector(6 downto 0); -- Current device address |
C_CONFD : out std_logic; -- High when in Configured state |
C_CLRIN : out std_logic_vector(1 to NENDPT); -- Trigger clearing of sync bit for IN endpoint |
C_CLROUT : out std_logic_vector(1 to NENDPT); -- Trigger clearing of sync bit for OUT endpoint |
C_HLTIN : in std_logic_vector(1 to NENDPT); -- Current status of halt bit for IN endpoint |
C_HLTOUT : in std_logic_vector(1 to NENDPT); -- Current status of halt bit for OUT endpoint |
C_SHLTIN : out std_logic_vector(1 to NENDPT); -- Trigger setting of halt bit for IN endpoint |
C_SHLTOUT : out std_logic_vector(1 to NENDPT); -- Trigger setting of halt bit for OUT endpoint |
C_DSCBUSY : out std_logic; -- High when accessing descriptor memory |
C_DSCRD : out std_logic; -- Descriptor read enable |
C_DSCTYP : out std_logic_vector(2 downto 0); -- Requested descriptor type |
C_DSCINX : out std_logic_vector(7 downto 0); -- Requested descriptor index |
C_DSCOFF : out std_logic_vector(7 downto 0); -- Offset within requested descriptor |
C_DSCLEN : in std_logic_vector(7 downto 0); -- Length of selected descriptor |
C_SELFPOWERED : in std_logic; -- High if the device is not drawing bus power |
T_IN : in std_logic; |
T_OUT : in std_logic; |
T_SETUP : in std_logic; |
T_PING : in std_logic; |
T_FIN : in std_logic; |
T_NAK : out std_logic; |
T_STALL : out std_logic; |
T_NYET : out std_logic; |
T_SEND : out std_logic; |
T_ISYNC : out std_logic; |
T_OSYNC : in std_logic; |
T_RXRDY : in std_logic; |
T_RXDAT : in std_logic_vector(7 downto 0); |
T_TXRDY : in std_logic; |
T_TXDAT : out std_logic_vector(7 downto 0) ); |
end component usb_control; |
|
-- Serial data transfer core. |
component usb_serial is |
generic ( |
VENDORID : std_logic_vector(15 downto 0); -- Vendor ID |
PRODUCTID : std_logic_vector(15 downto 0); -- Product ID |
VERSIONBCD : std_logic_vector(15 downto 0); -- Product version |
HSSUPPORT : boolean := false; -- Support high speed mode |
SELFPOWERED : boolean := false; -- Device does not use bus power |
RXBUFSIZE_BITS: integer range 7 to 12 := 11; -- Size of receive buffer |
TXBUFSIZE_BITS: integer range 7 to 12 := 10 ); -- Size of transmit buffer |
port ( |
CLK : in std_logic; -- 60 MHz UTMI clock |
RESET : in std_logic; -- Synchronous reset |
USBRST : out std_logic; -- Reset signal detected on bus |
HIGHSPEED : out std_logic; -- Device operating in high speed mode |
SUSPEND : out std_logic; -- Device is suspended |
ONLINE : out std_logic; -- Device is in Configured state |
RXVAL : out std_logic; -- Received byte available on RXDAT |
RXDAT : out std_logic_vector(7 downto 0); |
RXRDY : in std_logic; -- Application ready for next byte |
RXLEN : out std_logic_vector(RXBUFSIZE_BITS-1 downto 0); |
TXVAL : in std_logic; -- Application has data to send |
TXDAT : in std_logic_vector(7 downto 0); |
TXRDY : out std_logic; -- Entity ready to accept next byte |
TXROOM : out std_logic_vector(TXBUFSIZE_BITS-1 downto 0); |
TXCORK : in std_logic; -- Suppress data transmission |
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 component usb_serial; |
|
end package usb_pkg; |
/opb_usblite/tags/R1/pcores/opb_usblite_v1_00_a/hdl/vhdl/usb_init.vhdl
0,0 → 1,386
-- |
-- USB 2.0 Initialization, handshake and reset detection. |
-- |
-- This entity provides the following functions: |
-- |
-- * USB bus attachment: At powerup and after a RESET signal, switch to |
-- non-driving mode, wait for 17 ms, then attach to the USB bus. This |
-- should ensure that the host notices our reattachment and initiates |
-- a reset procedure. |
-- |
-- * High speed handshake (if HSSUPPORT enabled): attempt to enter |
-- high speed mode after a bus reset. |
-- |
-- * Monitor the linestate for reset and/or suspend signalling. |
-- |
-- The low-level interface connects to an UTMI compliant USB PHY such as |
-- the SMSC GT3200. The UTMI interface must be configured for 60 MHz operation |
-- with an 8-bit data bus. |
-- |
|
library ieee; |
use ieee.std_logic_1164.all, ieee.numeric_std.all; |
|
entity usb_init is |
|
generic ( |
|
-- Support high speed mode. |
HSSUPPORT : boolean := false ); |
|
port ( |
|
-- 60 MHz UTMI clock. |
CLK : in std_logic; |
|
-- Synchronous reset; triggers detach and reattach to the USB bus. |
RESET : in std_logic; |
|
-- High for one clock if a reset signal is detected on the USB bus. |
I_USBRST : out std_logic; |
|
-- High when attached to the host in high speed mode. |
I_HIGHSPEED : out std_logic; |
|
-- High when suspended. |
-- Reset of this signal is asynchronous. |
-- This signal may be used to drive (inverted) the UTMI SuspendM pin. |
I_SUSPEND : out std_logic; |
|
-- High to tell usb_packet that it must drive a continuous K state. |
P_CHIRPK : out std_logic; |
|
-- Connect to the UTMI Reset signal. |
PHY_RESET : out std_logic; |
|
-- Connect to the UTMI LineState signal. |
PHY_LINESTATE : in std_logic_vector(1 downto 0); |
|
-- Cconnect to the UTMI OpMode signal. |
PHY_OPMODE : out std_logic_vector(1 downto 0); |
|
-- Connect to the UTMI XcvrSelect signal (0 = high speed, 1 = full speed). |
PHY_XCVRSELECT : out std_logic; |
|
-- Connect to the UTMI TermSelect signal (0 = high speed, 1 = full speed). |
PHY_TERMSELECT : out std_logic ); |
|
end entity usb_init; |
|
architecture usb_init_arch of usb_init is |
|
-- Time from bus idle until device suspend (3 ms). |
constant TIME_SUSPEND : unsigned(19 downto 0) := to_unsigned(180000, 20); |
|
-- Time from start of SE0 until detection of reset signal (2.5 us + 10%). |
constant TIME_RESET : unsigned(7 downto 0) := to_unsigned(165, 8); |
|
-- Time to wait for good SE0 when waking up from suspend (6 ms). |
constant TIME_SUSPRST: unsigned(19 downto 0) := to_unsigned(360000, 20); |
|
-- Duration of chirp K from device during high speed detection (1 ms + 10%). |
constant TIME_CHIRPK : unsigned(19 downto 0) := to_unsigned(66000, 20); |
|
-- Minimum duration of chirp J/K during high speed detection (2.5 us + 10%). |
constant TIME_FILT : unsigned(7 downto 0) := to_unsigned(165, 8); |
|
-- Time to wait for chirp until giving up (1.1 ms). |
constant TIME_WTFS : unsigned(19 downto 0) := to_unsigned(66000, 20); |
|
-- Time to wait after reverting to full-speed before sampling the bus (100 us). |
constant TIME_WTRSTHS : unsigned(19 downto 0) := to_unsigned(6000, 20); |
|
-- State machine |
type t_state is ( |
ST_INIT, ST_FSRESET, ST_FULLSPEED, ST_SUSPEND, ST_SUSPRESET, |
ST_SENDCHIRP, ST_RECVCHIRP, ST_HIGHSPEED, ST_HSREVERT ); |
signal s_state : t_state := ST_INIT; |
|
-- Timers. |
signal s_timer1 : unsigned(7 downto 0); |
signal s_timer2 : unsigned(19 downto 0) := to_unsigned(0, 20); |
|
-- Count J/K chirps. |
signal s_chirpcnt : unsigned(2 downto 0); |
|
-- High if the device is operating in high speed (or suspended from high speed). |
signal s_highspeed : std_logic := '0'; |
|
-- High if the device is currently suspended. |
-- Reset of this signal is asynchronous. |
signal s_suspend : std_logic := '0'; |
|
-- Input registers. |
signal s_linestate : std_logic_vector(1 downto 0); |
|
-- Output registers. |
signal s_reset : std_logic := '1'; |
signal s_opmode : std_logic_vector(1 downto 0) := "01"; |
signal s_xcvrselect : std_logic := '1'; |
signal s_termselect : std_logic := '1'; |
signal s_chirpk : std_logic := '0'; |
|
begin |
|
I_USBRST <= s_reset; |
I_HIGHSPEED <= s_highspeed; |
I_SUSPEND <= s_suspend; |
P_CHIRPK <= s_chirpk; |
PHY_RESET <= s_reset; |
PHY_OPMODE <= s_opmode; |
PHY_XCVRSELECT <= s_xcvrselect; |
PHY_TERMSELECT <= s_termselect; |
|
-- Synchronous process. |
process is |
variable v_clrtimer1 : std_logic; |
variable v_clrtimer2 : std_logic; |
begin |
wait until rising_edge(CLK); |
|
-- By default, do not clear the timers. |
v_clrtimer1 := '0'; |
v_clrtimer2 := '0'; |
|
-- Register linestate input. |
s_linestate <= PHY_LINESTATE; |
|
-- Default assignments to registers. |
s_reset <= '0'; |
s_chirpk <= '0'; |
|
if RESET = '1' then |
|
-- Reset PHY. |
s_reset <= '1'; |
s_opmode <= "01"; |
s_xcvrselect <= '1'; |
s_termselect <= '1'; |
|
-- Go to ST_INIT state and wait until bus attachment. |
v_clrtimer1 := '1'; |
v_clrtimer2 := '1'; |
s_highspeed <= '0'; |
s_state <= ST_INIT; |
|
else |
|
case s_state is |
|
when ST_INIT => |
-- Wait before attaching to bus. |
s_opmode <= "01"; -- non-driving |
s_xcvrselect <= '1'; -- full speed |
s_termselect <= '1'; -- full speed |
v_clrtimer1 := '1'; |
if s_timer2 = to_unsigned(0, s_timer2'length) - 1 then |
-- Timer2 overflows after ~ 17 ms; attach to bus. |
v_clrtimer2 := '1'; |
s_state <= ST_FULLSPEED; |
end if; |
|
when ST_FSRESET => |
-- Waiting for end of reset before full speed operation. |
s_highspeed <= '0'; |
s_opmode <= "00"; -- normal |
s_xcvrselect <= '1'; -- full speed |
s_termselect <= '1'; -- full speed |
v_clrtimer1 := '1'; |
v_clrtimer2 := '1'; |
if s_linestate /= "00" then |
-- Reset signal ended. |
s_state <= ST_FULLSPEED; |
end if; |
|
when ST_FULLSPEED => |
-- Operating in full speed. |
s_highspeed <= '0'; |
s_opmode <= "00"; -- normal |
s_xcvrselect <= '1'; -- full speed |
s_termselect <= '1'; -- full speed |
if s_linestate /= "00" then |
-- Bus not in SE0 state; clear reset timer. |
v_clrtimer1 := '1'; |
end if; |
if s_linestate /= "01" then |
-- Bus not in J state; clear suspend timer. |
v_clrtimer2 := '1'; |
end if; |
if s_timer1 = TIME_RESET then |
-- Bus has been in SE0 state for TIME_RESET; |
-- this is a reset signal. |
s_reset <= '1'; |
if HSSUPPORT then |
s_state <= ST_SENDCHIRP; |
else |
s_state <= ST_FSRESET; |
end if; |
elsif s_timer2 = TIME_SUSPEND then |
-- Bus has been idle for TIME_SUSPEND; |
-- go to suspend state. |
s_state <= ST_SUSPEND; |
end if; |
|
when ST_SUSPEND => |
-- Suspended; waiting for resume signal. |
-- Possibly our clock will be disabled; wake up |
-- is initiated by the asynchronous reset of s_suspend. |
s_opmode <= "00"; -- normal |
s_xcvrselect <= '1'; -- full speed |
s_termselect <= '1'; -- full speed |
v_clrtimer1 := '1'; |
v_clrtimer2 := '1'; |
if s_linestate /= "01" then |
-- Bus not in J state; resume. |
if HSSUPPORT and s_highspeed = '1' then |
-- High speed resume protocol. |
if s_linestate = "10" then |
-- Bus in K state; resume to high speed. |
s_state <= ST_HIGHSPEED; |
elsif s_linestate = "00" then |
-- Bus in SE0 state; start reset detection. |
s_state <= ST_SUSPRESET; |
end if; |
else |
-- Resume to full speed. |
s_state <= ST_FULLSPEED; |
end if; |
end if; |
|
when ST_SUSPRESET => |
-- Wake up in SE0 state; wait for proper reset signal. |
s_opmode <= "00"; -- normal |
s_xcvrselect <= '1'; -- full speed |
s_termselect <= '1'; -- full speed |
if s_linestate /= "00" then |
-- Bus not in SE0 state; clear reset timer. |
v_clrtimer1 := '1'; |
end if; |
if s_timer1 = TIME_RESET then |
-- Bus has been in SE0 state for TIME_RESET; |
-- this is a reset signal. |
s_reset <= '1'; |
v_clrtimer2 := '1'; |
s_state <= ST_SENDCHIRP; |
end if; |
if s_timer2 = TIME_SUSPRST then |
-- Still no proper reset signal; go back to sleep. |
s_state <= ST_SUSPEND; |
end if; |
|
when ST_SENDCHIRP => |
-- Sending chirp K for a duration of TIME_CHIRPK. |
s_highspeed <= '0'; |
s_opmode <= "10"; -- disable bit stuffing |
s_xcvrselect <= '0'; -- high speed |
s_termselect <= '1'; -- full speed |
s_chirpk <= '1'; -- send chirp K |
v_clrtimer1 := '1'; |
if s_timer2 = TIME_CHIRPK then |
-- end of chirp K |
v_clrtimer2 := '1'; |
s_chirpcnt <= "000"; |
s_state <= ST_RECVCHIRP; |
end if; |
|
when ST_RECVCHIRP => |
-- Waiting for K-J-K-J-K-J chirps. |
-- Note: DO NOT switch Opmode to normal yet; there |
-- may be pending bits in the transmission buffer. |
s_opmode <= "10"; -- disable bit stuffing |
s_xcvrselect <= '0'; -- high speed |
s_termselect <= '1'; -- full speed |
if ( s_chirpcnt(0) = '0' and s_linestate /= "10" ) or |
( s_chirpcnt(0) = '1' and s_linestate /= "01" ) then |
-- Not the linestate we want. |
v_clrtimer1 := '1'; |
end if; |
if s_timer2 = TIME_WTFS then |
-- High speed detection failed; go to full speed. |
v_clrtimer1 := '1'; |
v_clrtimer2 := '1'; |
s_state <= ST_FSRESET; |
elsif s_timer1 = TIME_FILT then |
-- We got the chirp we wanted. |
if s_chirpcnt = 5 then |
-- This was the last chirp; |
-- we got a successful high speed handshake. |
v_clrtimer2 := '1'; |
s_state <= ST_HIGHSPEED; |
end if; |
s_chirpcnt <= s_chirpcnt + 1; |
v_clrtimer1 := '1'; |
end if; |
|
when ST_HIGHSPEED => |
-- Operating in high speed. |
s_highspeed <= '1'; |
s_opmode <= "00"; -- normal |
s_xcvrselect <= '0'; -- high speed |
s_termselect <= '0'; -- high speed |
if s_linestate /= "00" then |
-- Bus not idle; clear revert timer. |
v_clrtimer2 := '1'; |
end if; |
if s_timer2 = TIME_SUSPEND then |
-- Bus has been idle for TIME_SUSPEND; |
-- revert to full speed. |
v_clrtimer2 := '1'; |
s_state <= ST_HSREVERT; |
end if; |
|
when ST_HSREVERT => |
-- Revert to full speed and wait for 100 us. |
s_opmode <= "00"; -- normal |
s_xcvrselect <= '1'; -- full speed |
s_termselect <= '1'; -- full speed |
if s_timer2 = TIME_WTRSTHS then |
v_clrtimer2 := '1'; |
if s_linestate = "00" then |
-- Reset from high speed. |
s_reset <= '1'; |
s_state <= ST_SENDCHIRP; |
else |
-- Suspend from high speed. |
s_state <= ST_SUSPEND; |
end if; |
end if; |
|
end case; |
|
end if; |
|
-- Increment or clear timer1. |
if v_clrtimer1 = '1' then |
s_timer1 <= to_unsigned(0, s_timer1'length); |
else |
s_timer1 <= s_timer1 + 1; |
end if; |
|
-- Increment or clear timer2. |
if v_clrtimer2 = '1' then |
s_timer2 <= to_unsigned(0, s_timer2'length); |
else |
s_timer2 <= s_timer2 + 1; |
end if; |
|
end process; |
|
-- Drive the s_suspend flipflop (synchronous set, asynchronous reset). |
process (CLK, PHY_LINESTATE) is |
begin |
if PHY_LINESTATE /= "01" then |
-- The bus is not in full speed idle state; |
-- reset the s_suspend flipflop. |
s_suspend <= '0'; |
elsif rising_edge(CLK) then |
if s_state = ST_SUSPEND then |
-- Bus is idle and FSM is in suspend state; |
-- enable the s_suspend flipflop. |
s_suspend <= '1'; |
end if; |
end if; |
end process; |
|
end architecture usb_init_arch; |
|
/opb_usblite/tags/R1/pcores/opb_usblite_v1_00_a/hdl/vhdl/usb_packet.vhdl
0,0 → 1,460
-- |
-- USB 2.0 Packet-level logic. |
-- |
-- This entity hides the details of the UTMI interface and handles |
-- computation and verificaton of CRCs. |
-- |
-- The low-level interface signals are named PHY_xxx and may be |
-- connected to an UTMI compliant USB PHY, such as the SMSC GT3200. |
-- |
-- The application interface signals are named P_xxx. |
-- The receiving side of the interface operates as follows: |
-- * At the start of an incoming packet, RXACT is set high. |
-- * When a new byte arrives, RXRDY is asserted and the byte is put |
-- on RXDAT. These signals are valid for only one clock cycle; the |
-- application must accept them immediately. |
-- * The first byte of a packet is the PID. Subsequent bytes contain |
-- data and CRC. This entity verifies the CRC, but does not |
-- discard it from the data stream. |
-- * Some time after correctly receiving the last byte of a packet, |
-- RXACT is deasserted; at the same time RXFIN is asserted for one cycle |
-- to confirm the packet. |
-- * If a corrupt packet is received, RXACT is deasserted without |
-- asserting RXFIN. |
-- |
-- The transmission side of the interface operates as follows: |
-- * The application starts transmission by setting TXACT to 1 and setting |
-- TXDAT to the PID value (with correctly mirrored high order bits). |
-- * The entity asserts TXRDY when it needs the next payload byte. |
-- On the following clock cycle, the application must then provide the |
-- next payload byte on TXDAT, or deassert TXACT to indicate the end of |
-- the packet. The signal on TXDAT must be held stable until the next |
-- assertion of TXRDY. |
-- * CRC bytes should not be included in the payload; the entity will |
-- add them automatically. |
-- * As part of the high speed handshake, the application may request |
-- transmission of a continuous chirp K state by asserting CHIRPK. |
-- |
-- Implementation note: |
-- Transmission timing is a bit tricky due to the following issues: |
-- * After the PHY asserts PHY_TXREADY, we must immediately provide |
-- new data or deassert PHY_TXVALID on the next clock cycle. |
-- * The PHY may assert PHY_TXREADY during subsequent clock cycles, |
-- even though the average byte period is more than 40 cycles. |
-- * We want to register PHY inputs and outputs to ensure valid timing. |
-- |
-- To satisfy these requirements, we make the application run one byte |
-- ahead. While keeping the current byte in the output register PHY_DATAOUT, |
-- the application already provides the following data byte. That way, we |
-- can respond to PHY_TXREADY immediately in the next cycle, with the |
-- application following up in the clock cycle after that. |
-- |
|
library ieee; |
use ieee.std_logic_1164.all, ieee.numeric_std.all; |
|
entity usb_packet is |
|
port ( |
|
-- 60 MHz UTMI clock. |
CLK : in std_logic; |
|
-- Synchronous reset of this entity. |
RESET : in std_logic; |
|
-- High to force chirp K transmission. |
P_CHIRPK : in std_logic; |
|
-- High while receiving a packet. |
P_RXACT : out std_logic; |
|
-- Indicates next byte received; data must be read from RXDAT immediately. |
P_RXRDY : out std_logic; |
|
-- High for one cycle to indicate successful completion of packet. |
P_RXFIN : out std_logic; |
|
-- Received byte value. Valid if RXRDY is high. |
P_RXDAT : out std_logic_vector(7 downto 0); |
|
-- High while transmitting a packet. |
P_TXACT : in std_logic; |
|
-- Request for next data byte; application must change TXDAT on the next clock cycle. |
P_TXRDY : out std_logic; |
|
-- Data byte to transmit. Hold stable until next assertion of TXRDY. |
P_TXDAT : in std_logic_vector(7 downto 0); |
|
-- Connect to UTMI DataIn signal. |
PHY_DATAIN : in std_logic_vector(7 downto 0); |
|
-- Connect to UTMI DataOut signal. |
PHY_DATAOUT : out std_logic_vector(7 downto 0); |
|
-- Connect to UTMI TxValid signal. |
PHY_TXVALID : out std_logic; |
|
-- Connect to UTMI TxReady signal. |
PHY_TXREADY : in std_logic; |
|
-- Connect to UTMI RxActive signal. |
PHY_RXACTIVE : in std_logic; |
|
-- Connect to UTMI RxValid signal. |
PHY_RXVALID : in std_logic; |
|
-- Connect to UTMI RxError signal. |
PHY_RXERROR : in std_logic ); |
|
end entity usb_packet; |
|
architecture usb_packet_arch of usb_packet is |
|
-- State machine |
type t_state is ( |
ST_NONE, ST_CHIRPK, |
ST_RWAIT, ST_RTOKEN, ST_RDATA, ST_RSHAKE, |
ST_TSTART, ST_TDATA, ST_TCRC1, ST_TCRC2 ); |
signal s_state : t_state := ST_NONE; |
signal s_txfirst : std_logic := '0'; |
|
-- Registered inputs |
signal s_rxactive : std_logic; |
signal s_rxvalid : std_logic; |
signal s_rxerror : std_logic; |
signal s_datain : std_logic_vector(7 downto 0); |
signal s_txready : std_logic; |
|
-- Byte pending for transmission |
signal s_dataout : std_logic_vector(7 downto 0); |
|
-- True if an incoming packet would be valid if it ended now. |
signal s_rxgoodpacket : std_logic; |
|
-- CRC computation |
constant crc5_gen : std_logic_vector(4 downto 0) := "00101"; |
constant crc5_res : std_logic_vector(4 downto 0) := "01100"; |
constant crc16_gen : std_logic_vector(15 downto 0) := "1000000000000101"; |
constant crc16_res : std_logic_vector(15 downto 0) := "1000000000001101"; |
signal crc5_buf : std_logic_vector(4 downto 0); |
signal crc16_buf : std_logic_vector(15 downto 0); |
|
-- Update CRC 5 to account for a new byte |
function crc5_upd( |
c : in std_logic_vector(4 downto 0); |
b : in std_logic_vector(7 downto 0) ) |
return std_logic_vector |
is |
variable t : std_logic_vector(4 downto 0); |
variable y : std_logic_vector(4 downto 0); |
begin |
t := ( |
b(0) xor c(4), |
b(1) xor c(3), |
b(2) xor c(2), |
b(3) xor c(1), |
b(4) xor c(0) ); |
y := ( |
b(5) xor t(1) xor t(2), |
b(6) xor t(0) xor t(1) xor t(4), |
b(5) xor b(7) xor t(0) xor t(3) xor t(4), |
b(6) xor t(1) xor t(3) xor t(4), |
b(7) xor t(0) xor t(2) xor t(3) ); |
return y; |
end function; |
|
-- Update CRC-16 to account for new byte |
function crc16_upd( |
c : in std_logic_vector(15 downto 0); |
b : in std_logic_vector(7 downto 0) ) |
return std_logic_vector |
is |
variable t : std_logic_vector(7 downto 0); |
variable y : std_logic_vector(15 downto 0); |
begin |
t := ( |
b(0) xor c(15), |
b(1) xor c(14), |
b(2) xor c(13), |
b(3) xor c(12), |
b(4) xor c(11), |
b(5) xor c(10), |
b(6) xor c(9), |
b(7) xor c(8) ); |
y := ( |
c(7) xor t(0) xor t(1) xor t(2) xor t(3) xor t(4) xor t(5) xor t(6) xor t(7), |
c(6), c(5), c(4), c(3), c(2), |
c(1) xor t(7), |
c(0) xor t(6) xor t(7), |
t(5) xor t(6), |
t(4) xor t(5), |
t(3) xor t(4), |
t(2) xor t(3), |
t(1) xor t(2), |
t(0) xor t(1), |
t(1) xor t(2) xor t(3) xor t(4) xor t(5) xor t(6) xor t(7), |
t(0) xor t(1) xor t(2) xor t(3) xor t(4) xor t(5) xor t(6) xor t(7) ); |
return y; |
end function; |
|
begin |
|
-- Assign output signals |
P_RXACT <= s_rxactive; |
P_RXFIN <= (not s_rxactive) and (not s_rxerror) and s_rxgoodpacket; |
P_RXRDY <= s_rxactive and s_rxvalid; |
P_RXDAT <= s_datain; |
|
-- Assert P_TXRDY during ST_TSTART to acknowledge the PID byte, |
-- during the first cycle of ST_TDATA to acknowledge the first |
-- data byte, and whenever we need a new data byte during ST_TDATA. |
P_TXRDY <= '1' when (s_state = ST_TSTART) |
else (s_txfirst or s_txready) when (s_state = ST_TDATA) |
else '0'; |
|
-- On every rising clock edge |
process is |
variable v_dataout : std_logic_vector(7 downto 0); |
variable v_txvalid : std_logic; |
variable v_crc_upd : std_logic; |
variable v_crc_data : std_logic_vector(7 downto 0); |
variable v_crc5_new : std_logic_vector(4 downto 0); |
variable v_crc16_new : std_logic_vector(15 downto 0); |
begin |
wait until rising_edge(CLK); |
|
-- Default assignment to temporary variables |
v_dataout := s_dataout; |
v_txvalid := '0'; |
v_crc_upd := '0'; |
v_crc_data := "00000000"; |
v_crc5_new := "00000"; |
v_crc16_new := "0000000000000000"; |
|
-- Default assignment to s_txfirst |
s_txfirst <= '0'; |
|
-- Register inputs |
s_rxactive <= PHY_RXACTIVE; |
s_rxvalid <= PHY_RXVALID; |
s_rxerror <= PHY_RXERROR; |
s_datain <= PHY_DATAIN; |
s_txready <= PHY_TXREADY; |
|
-- State machine |
if RESET = '1' then |
|
-- Reset entity |
s_state <= ST_NONE; |
s_rxgoodpacket <= '0'; |
|
else |
|
case s_state is |
when ST_NONE => |
-- Waiting for incoming or outgoing packet |
|
-- Initialize CRC buffers |
crc5_buf <= "11111"; |
crc16_buf <= "1111111111111111"; |
s_rxgoodpacket <= '0'; |
|
if P_CHIRPK = '1' then |
-- Send continuous chirp K. |
s_state <= ST_CHIRPK; |
|
elsif s_rxactive = '1' then |
-- Receiver starting |
|
if s_rxerror = '1' then |
-- Receive error at PHY level |
s_state <= ST_RWAIT; |
elsif s_rxvalid = '1' then |
-- Got PID byte |
if s_datain(3 downto 0) = not s_datain(7 downto 4) then |
case s_datain(1 downto 0) is |
when "01" => -- token packet |
s_state <= ST_RTOKEN; |
when "11" => -- data packet |
s_state <= ST_RDATA; |
when "10" => -- handshake packet |
s_state <= ST_RSHAKE; |
s_rxgoodpacket <= '1'; |
when others => -- PING token or special packet |
-- If this is a PING token, it will work out fine; |
-- otherwise it will be flagged as a bad packet |
-- either here or in usb_transact. |
s_state <= ST_RTOKEN; |
end case; |
else |
-- Corrupt PID byte |
s_state <= ST_RWAIT; |
end if; |
end if; |
|
elsif P_TXACT = '1' then |
-- Transmission starting; put data in output buffer |
v_txvalid := '1'; |
v_dataout := P_TXDAT; |
s_state <= ST_TSTART; |
end if; |
|
when ST_CHIRPK => |
-- Sending continuous chirp K. |
if P_CHIRPK = '0' then |
s_state <= ST_NONE; |
end if; |
|
when ST_RTOKEN => |
-- Receiving a token packet |
if s_rxactive = '0' then |
-- End of packet |
s_rxgoodpacket <= '0'; |
s_state <= ST_NONE; |
elsif s_rxerror = '1' then |
-- Error at PHY level |
s_rxgoodpacket <= '0'; |
s_state <= ST_RWAIT; |
elsif s_rxvalid = '1' then |
-- Just received a byte; update CRC |
v_crc5_new := crc5_upd(crc5_buf, s_datain); |
crc5_buf <= v_crc5_new; |
if v_crc5_new = crc5_res then |
s_rxgoodpacket <= '1'; |
else |
s_rxgoodpacket <= '0'; |
end if; |
end if; |
|
when ST_RDATA => |
-- Receiving a data packet |
if s_rxactive = '0' then |
-- End of packet |
s_rxgoodpacket <= '0'; |
s_state <= ST_NONE; |
elsif s_rxerror = '1' then |
-- Error at PHY level |
s_rxgoodpacket <= '0'; |
s_state <= ST_RWAIT; |
elsif s_rxvalid = '1' then |
-- Just received a byte; update CRC |
v_crc_upd := '1'; |
v_crc_data := s_datain; |
end if; |
|
when ST_RWAIT => |
-- Wait until the end of the current packet |
if s_rxactive = '0' then |
s_state <= ST_NONE; |
end if; |
|
when ST_RSHAKE => |
-- Receiving a handshake packet |
if s_rxactive = '0' then |
-- Got good handshake |
s_rxgoodpacket <= '0'; |
s_state <= ST_NONE; |
elsif s_rxerror = '1' or s_rxvalid = '1' then |
-- Error or unexpected data byte in handshake packet |
s_rxgoodpacket <= '0'; |
s_state <= ST_RWAIT; |
end if; |
|
when ST_TSTART => |
-- Transmission starting; |
-- PHY module sees our PHY_TXVALID signal; |
-- PHY_TXREADY is undefined; |
-- we assert P_TXRDY to acknowledge the PID byte |
v_txvalid := '1'; |
-- Check packet type |
case P_TXDAT(1 downto 0) is |
when "11" => -- data packet |
s_state <= ST_TDATA; |
s_txfirst <= '1'; |
when "10" => -- handshake packet |
s_state <= ST_RWAIT; |
when others => -- should not happen |
end case; |
|
when ST_TDATA => |
-- Sending a data packet |
v_txvalid := '1'; |
if (s_txready = '1') or (s_txfirst = '1') then |
-- Need next byte |
if P_TXACT = '0' then |
-- No more data; send first CRC byte |
for i in 0 to 7 loop |
v_dataout(i) := not crc16_buf(15-i); |
end loop; |
s_state <= ST_TCRC1; |
else |
-- Put next byte in output buffer |
v_dataout := P_TXDAT; |
-- And update the CRC |
v_crc_upd := '1'; |
v_crc_data := P_TXDAT; |
end if; |
end if; |
|
when ST_TCRC1 => |
-- Sending the first CRC byte of a data packet |
v_txvalid := '1'; |
if s_txready = '1' then |
-- Just queued the first CRC byte; move to 2nd byte |
for i in 0 to 7 loop |
v_dataout(i) := not crc16_buf(7-i); |
end loop; |
s_state <= ST_TCRC2; |
end if; |
|
when ST_TCRC2 => |
-- Sending the second CRC byte of a data packet |
if s_txready = '1' then |
-- Just sent the 2nd CRC byte; end packet |
s_state <= ST_RWAIT; |
else |
-- Last byte is still pending |
v_txvalid := '1'; |
end if; |
|
end case; |
|
end if; |
|
-- CRC-16 update |
if v_crc_upd = '1' then |
v_crc16_new := crc16_upd(crc16_buf, v_crc_data); |
crc16_buf <= v_crc16_new; |
if s_state = ST_RDATA and v_crc16_new = crc16_res then |
-- If this is the last byte of the packet, it is a valid packet. |
s_rxgoodpacket <= '1'; |
else |
s_rxgoodpacket <= '0'; |
end if; |
end if; |
|
-- Drive data output to PHY |
if RESET = '1' then |
-- Reset. |
PHY_TXVALID <= '0'; |
PHY_DATAOUT <= "00000000"; |
elsif s_state = ST_CHIRPK then |
-- Continuous chirp-K. |
PHY_TXVALID <= P_CHIRPK; |
PHY_DATAOUT <= "00000000"; |
elsif (PHY_TXREADY = '1') or (s_state = ST_NONE and P_TXACT = '1') then |
-- Move a data byte from the buffer to the output lines when the PHY |
-- accepts the previous byte, and also at the start of a new packet. |
PHY_TXVALID <= v_txvalid; |
PHY_DATAOUT <= v_dataout; |
end if; |
|
-- Keep pending output byte in register. |
s_dataout <= v_dataout; |
|
end process; |
|
end architecture usb_packet_arch; |
|
/opb_usblite/tags/R1/pcores/opb_usblite_v1_00_a/hdl/verilog/usb_rx_phy.v
0,0 → 1,452
///////////////////////////////////////////////////////////////////// |
//// //// |
//// USB 1.1 PHY //// |
//// RX & DPLL //// |
//// //// |
//// //// |
//// Author: Rudolf Usselmann //// |
//// rudi@asics.ws //// |
//// //// |
//// //// |
//// Downloaded from: http://www.opencores.org/cores/usb_phy/ //// |
//// //// |
///////////////////////////////////////////////////////////////////// |
//// //// |
//// Copyright (C) 2000-2002 Rudolf Usselmann //// |
//// www.asics.ws //// |
//// rudi@asics.ws //// |
//// //// |
//// This source file may be used and distributed without //// |
//// restriction provided that this copyright statement is not //// |
//// removed from the file and that any derivative work contains //// |
//// the original copyright notice and the associated disclaimer.//// |
//// //// |
//// THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY //// |
//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED //// |
//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS //// |
//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR //// |
//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, //// |
//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES //// |
//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE //// |
//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR //// |
//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF //// |
//// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT //// |
//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT //// |
//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE //// |
//// POSSIBILITY OF SUCH DAMAGE. //// |
//// //// |
///////////////////////////////////////////////////////////////////// |
|
// CVS Log |
// |
// $Id: usb_rx_phy.v,v 1.5 2004/10/19 09:29:07 rudi Exp $ |
// |
// $Date: 2004/10/19 09:29:07 $ |
// $Revision: 1.5 $ |
// $Author: rudi $ |
// $Locker: $ |
// $State: Exp $ |
// |
// Change History: |
// $Log: usb_rx_phy.v,v $ |
// Revision 1.5 2004/10/19 09:29:07 rudi |
// Fixed DPLL alignment in the rx_phy and bit stuffing errors in the tx_phy (if last bit bit was a stuff bit in a packet it was omitted). |
// |
// Revision 1.4 2003/12/02 04:56:00 rudi |
// Fixed a bug reported by Karl C. Posch from Graz University of Technology. Thanks Karl ! |
// |
// Revision 1.3 2003/10/19 18:07:45 rudi |
// - Fixed Sync Error to be only checked/generated during the sync phase |
// |
// Revision 1.2 2003/10/19 17:40:13 rudi |
// - Made core more robust against line noise |
// - Added Error Checking and Reporting |
// (See README.txt for more info) |
// |
// Revision 1.1.1.1 2002/09/16 14:27:01 rudi |
// Created Directory Structure |
// |
// |
// |
// |
// |
// |
// |
// |
|
`include "timescale.v" |
|
module usb_rx_phy( clk, rst, fs_ce, |
|
// Transciever Interface |
rxd, rxdp, rxdn, |
|
// UTMI Interface |
RxValid_o, RxActive_o, RxError_o, DataIn_o, |
RxEn_i, LineState); |
|
input clk; |
input rst; |
output fs_ce; |
input rxd, rxdp, rxdn; |
output [7:0] DataIn_o; |
output RxValid_o; |
output RxActive_o; |
output RxError_o; |
input RxEn_i; |
output [1:0] LineState; |
|
/////////////////////////////////////////////////////////////////// |
// |
// Local Wires and Registers |
// |
|
reg rxd_s0, rxd_s1, rxd_s; |
reg rxdp_s0, rxdp_s1, rxdp_s, rxdp_s_r; |
reg rxdn_s0, rxdn_s1, rxdn_s, rxdn_s_r; |
reg synced_d; |
wire k, j, se0; |
reg rxd_r; |
reg rx_en; |
reg rx_active; |
reg [2:0] bit_cnt; |
reg rx_valid1, rx_valid; |
reg shift_en; |
reg sd_r; |
reg sd_nrzi; |
reg [7:0] hold_reg; |
wire drop_bit; // Indicates a stuffed bit |
reg [2:0] one_cnt; |
|
reg [1:0] dpll_state, dpll_next_state; |
reg fs_ce_d; |
reg fs_ce; |
wire change; |
wire lock_en; |
reg [2:0] fs_state, fs_next_state; |
reg rx_valid_r; |
reg sync_err_d, sync_err; |
reg bit_stuff_err; |
reg se0_r, byte_err; |
reg se0_s; |
|
/////////////////////////////////////////////////////////////////// |
// |
// Misc Logic |
// |
|
assign RxActive_o = rx_active; |
assign RxValid_o = rx_valid; |
assign RxError_o = sync_err | bit_stuff_err | byte_err; |
assign DataIn_o = hold_reg; |
assign LineState = {rxdn_s1, rxdp_s1}; |
|
always @(posedge clk) rx_en <= RxEn_i; |
always @(posedge clk) sync_err <= !rx_active & sync_err_d; |
|
/////////////////////////////////////////////////////////////////// |
// |
// Synchronize Inputs |
// |
|
// First synchronize to the local system clock to |
// avoid metastability outside the sync block (*_s0). |
// Then make sure we see the signal for at least two |
// clock cycles stable to avoid glitches and noise |
|
always @(posedge clk) rxd_s0 <= rxd; |
always @(posedge clk) rxd_s1 <= rxd_s0; |
always @(posedge clk) // Avoid detecting Line Glitches and noise |
if(rxd_s0 && rxd_s1) rxd_s <= 1'b1; |
else |
if(!rxd_s0 && !rxd_s1) rxd_s <= 1'b0; |
|
always @(posedge clk) rxdp_s0 <= rxdp; |
always @(posedge clk) rxdp_s1 <= rxdp_s0; |
always @(posedge clk) rxdp_s_r <= rxdp_s0 & rxdp_s1; |
always @(posedge clk) rxdp_s <= (rxdp_s0 & rxdp_s1) | rxdp_s_r; // Avoid detecting Line Glitches and noise |
|
always @(posedge clk) rxdn_s0 <= rxdn; |
always @(posedge clk) rxdn_s1 <= rxdn_s0; |
always @(posedge clk) rxdn_s_r <= rxdn_s0 & rxdn_s1; |
always @(posedge clk) rxdn_s <= (rxdn_s0 & rxdn_s1) | rxdn_s_r; // Avoid detecting Line Glitches and noise |
|
assign k = !rxdp_s & rxdn_s; |
assign j = rxdp_s & !rxdn_s; |
assign se0 = !rxdp_s & !rxdn_s; |
|
always @(posedge clk) if(fs_ce) se0_s <= se0; |
|
/////////////////////////////////////////////////////////////////// |
// |
// DPLL |
// |
|
// This design uses a clock enable to do 12Mhz timing and not a |
// real 12Mhz clock. Everything always runs at 48Mhz. We want to |
// make sure however, that the clock enable is always exactly in |
// the middle between two virtual 12Mhz rising edges. |
// We monitor rxdp and rxdn for any changes and do the appropiate |
// adjustments. |
// In addition to the locking done in the dpll FSM, we adjust the |
// final latch enable to compensate for various sync registers ... |
|
// Allow lockinf only when we are receiving |
assign lock_en = rx_en; |
|
always @(posedge clk) rxd_r <= rxd_s; |
|
// Edge detector |
assign change = rxd_r != rxd_s; |
|
// DPLL FSM |
`ifdef USB_ASYNC_REST |
always @(posedge clk or negedge rst) |
`else |
always @(posedge clk) |
`endif |
if(!rst) dpll_state <= 2'h1; |
else dpll_state <= dpll_next_state; |
|
always @(dpll_state or lock_en or change) |
begin |
fs_ce_d = 1'b0; |
case(dpll_state) // synopsys full_case parallel_case |
2'h0: |
if(lock_en && change) dpll_next_state = 2'h0; |
else dpll_next_state = 2'h1; |
2'h1:begin |
fs_ce_d = 1'b1; |
if(lock_en && change) dpll_next_state = 2'h3; |
else dpll_next_state = 2'h2; |
end |
2'h2: |
if(lock_en && change) dpll_next_state = 2'h0; |
else dpll_next_state = 2'h3; |
2'h3: |
if(lock_en && change) dpll_next_state = 2'h0; |
else dpll_next_state = 2'h0; |
endcase |
end |
|
// Compensate for sync registers at the input - allign full speed |
// clock enable to be in the middle between two bit changes ... |
reg fs_ce_r1, fs_ce_r2; |
|
always @(posedge clk) fs_ce_r1 <= fs_ce_d; |
always @(posedge clk) fs_ce_r2 <= fs_ce_r1; |
always @(posedge clk) fs_ce <= fs_ce_r2; |
|
|
/////////////////////////////////////////////////////////////////// |
// |
// Find Sync Pattern FSM |
// |
|
parameter FS_IDLE = 3'h0, |
K1 = 3'h1, |
J1 = 3'h2, |
K2 = 3'h3, |
J2 = 3'h4, |
K3 = 3'h5, |
J3 = 3'h6, |
K4 = 3'h7; |
|
`ifdef USB_ASYNC_REST |
always @(posedge clk or negedge rst) |
`else |
always @(posedge clk) |
`endif |
if(!rst) fs_state <= FS_IDLE; |
else fs_state <= fs_next_state; |
|
always @(fs_state or fs_ce or k or j or rx_en or rx_active or se0 or se0_s) |
begin |
synced_d = 1'b0; |
sync_err_d = 1'b0; |
fs_next_state = fs_state; |
if(fs_ce && !rx_active && !se0 && !se0_s) |
case(fs_state) // synopsys full_case parallel_case |
FS_IDLE: |
begin |
if(k && rx_en) fs_next_state = K1; |
end |
K1: |
begin |
if(j && rx_en) fs_next_state = J1; |
else |
begin |
sync_err_d = 1'b1; |
fs_next_state = FS_IDLE; |
end |
end |
J1: |
begin |
if(k && rx_en) fs_next_state = K2; |
else |
begin |
sync_err_d = 1'b1; |
fs_next_state = FS_IDLE; |
end |
end |
K2: |
begin |
if(j && rx_en) fs_next_state = J2; |
else |
begin |
sync_err_d = 1'b1; |
fs_next_state = FS_IDLE; |
end |
end |
J2: |
begin |
if(k && rx_en) fs_next_state = K3; |
else |
begin |
sync_err_d = 1'b1; |
fs_next_state = FS_IDLE; |
end |
end |
K3: |
begin |
if(j && rx_en) fs_next_state = J3; |
else |
if(k && rx_en) |
begin |
fs_next_state = FS_IDLE; // Allow missing first K-J |
synced_d = 1'b1; |
end |
else |
begin |
sync_err_d = 1'b1; |
fs_next_state = FS_IDLE; |
end |
end |
J3: |
begin |
if(k && rx_en) fs_next_state = K4; |
else |
begin |
sync_err_d = 1'b1; |
fs_next_state = FS_IDLE; |
end |
end |
K4: |
begin |
if(k) synced_d = 1'b1; |
fs_next_state = FS_IDLE; |
end |
endcase |
end |
|
/////////////////////////////////////////////////////////////////// |
// |
// Generate RxActive |
// |
|
`ifdef USB_ASYNC_REST |
always @(posedge clk or negedge rst) |
`else |
always @(posedge clk) |
`endif |
if(!rst) rx_active <= 1'b0; |
else |
if(synced_d && rx_en) rx_active <= 1'b1; |
else |
if(se0 && rx_valid_r) rx_active <= 1'b0; |
|
always @(posedge clk) |
if(rx_valid) rx_valid_r <= 1'b1; |
else |
if(fs_ce) rx_valid_r <= 1'b0; |
|
/////////////////////////////////////////////////////////////////// |
// |
// NRZI Decoder |
// |
|
always @(posedge clk) |
if(fs_ce) sd_r <= rxd_s; |
|
`ifdef USB_ASYNC_REST |
always @(posedge clk or negedge rst) |
`else |
always @(posedge clk) |
`endif |
if(!rst) sd_nrzi <= 1'b0; |
else |
if(!rx_active) sd_nrzi <= 1'b1; |
else |
if(rx_active && fs_ce) sd_nrzi <= !(rxd_s ^ sd_r); |
|
/////////////////////////////////////////////////////////////////// |
// |
// Bit Stuff Detect |
// |
|
`ifdef USB_ASYNC_REST |
always @(posedge clk or negedge rst) |
`else |
always @(posedge clk) |
`endif |
if(!rst) one_cnt <= 3'h0; |
else |
if(!shift_en) one_cnt <= 3'h0; |
else |
if(fs_ce) |
begin |
if(!sd_nrzi || drop_bit) one_cnt <= 3'h0; |
else one_cnt <= one_cnt + 3'h1; |
end |
|
assign drop_bit = (one_cnt==3'h6); |
|
always @(posedge clk) bit_stuff_err <= drop_bit & sd_nrzi & fs_ce & !se0 & rx_active; // Bit Stuff Error |
|
/////////////////////////////////////////////////////////////////// |
// |
// Serial => Parallel converter |
// |
|
always @(posedge clk) |
if(fs_ce) shift_en <= synced_d | rx_active; |
|
always @(posedge clk) |
if(fs_ce && shift_en && !drop_bit) |
hold_reg <= {sd_nrzi, hold_reg[7:1]}; |
|
/////////////////////////////////////////////////////////////////// |
// |
// Generate RxValid |
// |
|
`ifdef USB_ASYNC_REST |
always @(posedge clk or negedge rst) |
`else |
always @(posedge clk) |
`endif |
if(!rst) bit_cnt <= 3'b0; |
else |
if(!shift_en) bit_cnt <= 3'h0; |
else |
if(fs_ce && !drop_bit) bit_cnt <= bit_cnt + 3'h1; |
|
`ifdef USB_ASYNC_REST |
always @(posedge clk or negedge rst) |
`else |
always @(posedge clk) |
`endif |
if(!rst) rx_valid1 <= 1'b0; |
else |
if(fs_ce && !drop_bit && (bit_cnt==3'h7)) rx_valid1 <= 1'b1; |
else |
if(rx_valid1 && fs_ce && !drop_bit) rx_valid1 <= 1'b0; |
|
always @(posedge clk) rx_valid <= !drop_bit & rx_valid1 & fs_ce; |
|
always @(posedge clk) se0_r <= se0; |
|
always @(posedge clk) byte_err <= se0 & !se0_r & (|bit_cnt[2:1]) & rx_active; |
|
endmodule |
|
/opb_usblite/tags/R1/pcores/opb_usblite_v1_00_a/hdl/verilog/usb_tx_phy.v
0,0 → 1,465
///////////////////////////////////////////////////////////////////// |
//// //// |
//// USB 1.1 PHY //// |
//// TX //// |
//// //// |
//// //// |
//// Author: Rudolf Usselmann //// |
//// rudi@asics.ws //// |
//// //// |
//// //// |
//// Downloaded from: http://www.opencores.org/cores/usb_phy/ //// |
//// //// |
///////////////////////////////////////////////////////////////////// |
//// //// |
//// Copyright (C) 2000-2002 Rudolf Usselmann //// |
//// www.asics.ws //// |
//// rudi@asics.ws //// |
//// //// |
//// This source file may be used and distributed without //// |
//// restriction provided that this copyright statement is not //// |
//// removed from the file and that any derivative work contains //// |
//// the original copyright notice and the associated disclaimer.//// |
//// //// |
//// THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY //// |
//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED //// |
//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS //// |
//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR //// |
//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, //// |
//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES //// |
//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE //// |
//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR //// |
//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF //// |
//// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT //// |
//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT //// |
//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE //// |
//// POSSIBILITY OF SUCH DAMAGE. //// |
//// //// |
///////////////////////////////////////////////////////////////////// |
|
// CVS Log |
// |
// $Id: usb_tx_phy.v,v 1.4 2004/10/19 09:29:07 rudi Exp $ |
// |
// $Date: 2004/10/19 09:29:07 $ |
// $Revision: 1.4 $ |
// $Author: rudi $ |
// $Locker: $ |
// $State: Exp $ |
// |
// Change History: |
// $Log: usb_tx_phy.v,v $ |
// Revision 1.4 2004/10/19 09:29:07 rudi |
// Fixed DPLL alignment in the rx_phy and bit stuffing errors in the tx_phy (if last bit bit was a stuff bit in a packet it was omitted). |
// |
// Revision 1.3 2003/10/21 05:58:41 rudi |
// usb_rst is no longer or'ed with the incomming reset internally. |
// Now usb_rst is simply an output, the application can decide how |
// to utilize it. |
// |
// Revision 1.2 2003/10/19 17:40:13 rudi |
// - Made core more robust against line noise |
// - Added Error Checking and Reporting |
// (See README.txt for more info) |
// |
// Revision 1.1.1.1 2002/09/16 14:27:02 rudi |
// Created Directory Structure |
// |
// |
// |
// |
// |
// |
// |
|
`include "timescale.v" |
|
module usb_tx_phy( |
clk, rst, fs_ce, phy_mode, |
|
// Transciever Interface |
txdp, txdn, txoe, |
|
// UTMI Interface |
DataOut_i, TxValid_i, TxReady_o |
); |
|
input clk; |
input rst; |
input fs_ce; |
input phy_mode; |
output txdp, txdn, txoe; |
input [7:0] DataOut_i; |
input TxValid_i; |
output TxReady_o; |
|
/////////////////////////////////////////////////////////////////// |
// |
// Local Wires and Registers |
// |
|
parameter IDLE = 3'd0, |
SOP = 3'h1, |
DATA = 3'h2, |
EOP1 = 3'h3, |
EOP2 = 3'h4, |
WAIT = 3'h5; |
|
reg TxReady_o; |
reg [2:0] state, next_state; |
reg tx_ready_d; |
reg ld_sop_d; |
reg ld_data_d; |
reg ld_eop_d; |
reg tx_ip; |
reg tx_ip_sync; |
reg [2:0] bit_cnt; |
reg [7:0] hold_reg; |
reg [7:0] hold_reg_d; |
|
reg sd_raw_o; |
wire hold; |
reg data_done; |
reg sft_done; |
reg sft_done_r; |
wire sft_done_e; |
reg ld_data; |
wire eop_done; |
reg [2:0] one_cnt; |
wire stuff; |
reg sd_bs_o; |
reg sd_nrzi_o; |
reg append_eop; |
reg append_eop_sync1; |
reg append_eop_sync2; |
reg append_eop_sync3; |
reg append_eop_sync4; |
reg txdp, txdn; |
reg txoe_r1, txoe_r2; |
reg txoe; |
|
/////////////////////////////////////////////////////////////////// |
// |
// Misc Logic |
// |
|
`ifdef USB_ASYNC_REST |
always @(posedge clk or negedge rst) |
`else |
always @(posedge clk) |
`endif |
if(!rst) TxReady_o <= 1'b0; |
else TxReady_o <= tx_ready_d & TxValid_i; |
|
always @(posedge clk) ld_data <= ld_data_d; |
|
/////////////////////////////////////////////////////////////////// |
// |
// Transmit in progress indicator |
// |
|
`ifdef USB_ASYNC_REST |
always @(posedge clk or negedge rst) |
`else |
always @(posedge clk) |
`endif |
if(!rst) tx_ip <= 1'b0; |
else |
if(ld_sop_d) tx_ip <= 1'b1; |
else |
if(eop_done) tx_ip <= 1'b0; |
|
`ifdef USB_ASYNC_REST |
always @(posedge clk or negedge rst) |
`else |
always @(posedge clk) |
`endif |
if(!rst) tx_ip_sync <= 1'b0; |
else |
if(fs_ce) tx_ip_sync <= tx_ip; |
|
// data_done helps us to catch cases where TxValid drops due to |
// packet end and then gets re-asserted as a new packet starts. |
// We might not see this because we are still transmitting. |
// data_done should solve those cases ... |
`ifdef USB_ASYNC_REST |
always @(posedge clk or negedge rst) |
`else |
always @(posedge clk) |
`endif |
if(!rst) data_done <= 1'b0; |
else |
if(TxValid_i && ! tx_ip) data_done <= 1'b1; |
else |
if(!TxValid_i) data_done <= 1'b0; |
|
/////////////////////////////////////////////////////////////////// |
// |
// Shift Register |
// |
|
`ifdef USB_ASYNC_REST |
always @(posedge clk or negedge rst) |
`else |
always @(posedge clk) |
`endif |
if(!rst) bit_cnt <= 3'h0; |
else |
if(!tx_ip_sync) bit_cnt <= 3'h0; |
else |
if(fs_ce && !hold) bit_cnt <= bit_cnt + 3'h1; |
|
assign hold = stuff; |
|
always @(posedge clk) |
if(!tx_ip_sync) sd_raw_o <= 1'b0; |
else |
case(bit_cnt) // synopsys full_case parallel_case |
3'h0: sd_raw_o <= hold_reg_d[0]; |
3'h1: sd_raw_o <= hold_reg_d[1]; |
3'h2: sd_raw_o <= hold_reg_d[2]; |
3'h3: sd_raw_o <= hold_reg_d[3]; |
3'h4: sd_raw_o <= hold_reg_d[4]; |
3'h5: sd_raw_o <= hold_reg_d[5]; |
3'h6: sd_raw_o <= hold_reg_d[6]; |
3'h7: sd_raw_o <= hold_reg_d[7]; |
endcase |
|
always @(posedge clk) |
sft_done <= !hold & (bit_cnt == 3'h7); |
|
always @(posedge clk) |
sft_done_r <= sft_done; |
|
assign sft_done_e = sft_done & !sft_done_r; |
|
// Out Data Hold Register |
always @(posedge clk) |
if(ld_sop_d) hold_reg <= 8'h80; |
else |
if(ld_data) hold_reg <= DataOut_i; |
|
always @(posedge clk) hold_reg_d <= hold_reg; |
|
/////////////////////////////////////////////////////////////////// |
// |
// Bit Stuffer |
// |
|
`ifdef USB_ASYNC_REST |
always @(posedge clk or negedge rst) |
`else |
always @(posedge clk) |
`endif |
if(!rst) one_cnt <= 3'h0; |
else |
if(!tx_ip_sync) one_cnt <= 3'h0; |
else |
if(fs_ce) |
begin |
if(!sd_raw_o || stuff) one_cnt <= 3'h0; |
else one_cnt <= one_cnt + 3'h1; |
end |
|
assign stuff = (one_cnt==3'h6); |
|
`ifdef USB_ASYNC_REST |
always @(posedge clk or negedge rst) |
`else |
always @(posedge clk) |
`endif |
if(!rst) sd_bs_o <= 1'h0; |
else |
if(fs_ce) sd_bs_o <= !tx_ip_sync ? 1'b0 : (stuff ? 1'b0 : sd_raw_o); |
|
/////////////////////////////////////////////////////////////////// |
// |
// NRZI Encoder |
// |
|
`ifdef USB_ASYNC_REST |
always @(posedge clk or negedge rst) |
`else |
always @(posedge clk) |
`endif |
if(!rst) sd_nrzi_o <= 1'b1; |
else |
if(!tx_ip_sync || !txoe_r1) sd_nrzi_o <= 1'b1; |
else |
if(fs_ce) sd_nrzi_o <= sd_bs_o ? sd_nrzi_o : ~sd_nrzi_o; |
|
/////////////////////////////////////////////////////////////////// |
// |
// EOP append logic |
// |
|
`ifdef USB_ASYNC_REST |
always @(posedge clk or negedge rst) |
`else |
always @(posedge clk) |
`endif |
if(!rst) append_eop <= 1'b0; |
else |
if(ld_eop_d) append_eop <= 1'b1; |
else |
if(append_eop_sync2) append_eop <= 1'b0; |
|
`ifdef USB_ASYNC_REST |
always @(posedge clk or negedge rst) |
`else |
always @(posedge clk) |
`endif |
if(!rst) append_eop_sync1 <= 1'b0; |
else |
if(fs_ce) append_eop_sync1 <= append_eop; |
|
`ifdef USB_ASYNC_REST |
always @(posedge clk or negedge rst) |
`else |
always @(posedge clk) |
`endif |
if(!rst) append_eop_sync2 <= 1'b0; |
else |
if(fs_ce) append_eop_sync2 <= append_eop_sync1; |
|
`ifdef USB_ASYNC_REST |
always @(posedge clk or negedge rst) |
`else |
always @(posedge clk) |
`endif |
if(!rst) append_eop_sync3 <= 1'b0; |
else |
if(fs_ce) append_eop_sync3 <= append_eop_sync2 | |
(append_eop_sync3 & !append_eop_sync4); // Make sure always 2 bit wide |
|
`ifdef USB_ASYNC_REST |
always @(posedge clk or negedge rst) |
`else |
always @(posedge clk) |
`endif |
if(!rst) append_eop_sync4 <= 1'b0; |
else |
if(fs_ce) append_eop_sync4 <= append_eop_sync3; |
|
assign eop_done = append_eop_sync3; |
|
/////////////////////////////////////////////////////////////////// |
// |
// Output Enable Logic |
// |
|
`ifdef USB_ASYNC_REST |
always @(posedge clk or negedge rst) |
`else |
always @(posedge clk) |
`endif |
if(!rst) txoe_r1 <= 1'b0; |
else |
if(fs_ce) txoe_r1 <= tx_ip_sync; |
|
`ifdef USB_ASYNC_REST |
always @(posedge clk or negedge rst) |
`else |
always @(posedge clk) |
`endif |
if(!rst) txoe_r2 <= 1'b0; |
else |
if(fs_ce) txoe_r2 <= txoe_r1; |
|
`ifdef USB_ASYNC_REST |
always @(posedge clk or negedge rst) |
`else |
always @(posedge clk) |
`endif |
if(!rst) txoe <= 1'b1; |
else |
if(fs_ce) txoe <= !(txoe_r1 | txoe_r2); |
|
/////////////////////////////////////////////////////////////////// |
// |
// Output Registers |
// |
|
`ifdef USB_ASYNC_REST |
always @(posedge clk or negedge rst) |
`else |
always @(posedge clk) |
`endif |
if(!rst) txdp <= 1'b1; |
else |
if(fs_ce) txdp <= phy_mode ? |
(!append_eop_sync3 & sd_nrzi_o) : |
sd_nrzi_o; |
|
`ifdef USB_ASYNC_REST |
always @(posedge clk or negedge rst) |
`else |
always @(posedge clk) |
`endif |
if(!rst) txdn <= 1'b0; |
else |
if(fs_ce) txdn <= phy_mode ? |
(!append_eop_sync3 & ~sd_nrzi_o) : |
append_eop_sync3; |
|
/////////////////////////////////////////////////////////////////// |
// |
// Tx Statemashine |
// |
|
`ifdef USB_ASYNC_REST |
always @(posedge clk or negedge rst) |
`else |
always @(posedge clk) |
`endif |
if(!rst) state <= IDLE; |
else state <= next_state; |
|
always @(state or TxValid_i or data_done or sft_done_e or eop_done or fs_ce) |
begin |
next_state = state; |
tx_ready_d = 1'b0; |
|
ld_sop_d = 1'b0; |
ld_data_d = 1'b0; |
ld_eop_d = 1'b0; |
|
case(state) // synopsys full_case parallel_case |
IDLE: |
if(TxValid_i) |
begin |
ld_sop_d = 1'b1; |
next_state = SOP; |
end |
SOP: |
if(sft_done_e) |
begin |
tx_ready_d = 1'b1; |
ld_data_d = 1'b1; |
next_state = DATA; |
end |
DATA: |
begin |
if(!data_done && sft_done_e) |
begin |
ld_eop_d = 1'b1; |
next_state = EOP1; |
end |
|
if(data_done && sft_done_e) |
begin |
tx_ready_d = 1'b1; |
ld_data_d = 1'b1; |
end |
end |
EOP1: |
if(eop_done) next_state = EOP2; |
EOP2: |
if(!eop_done && fs_ce) next_state = WAIT; |
WAIT: |
if(fs_ce) next_state = IDLE; |
endcase |
end |
|
endmodule |
|
/opb_usblite/tags/R1/pcores/opb_usblite_v1_00_a/hdl/verilog/timescale.v
0,0 → 1,465
`timescale 1ns / 10ps |
/opb_usblite/tags/R1/pcores/opb_usblite_v1_00_a/hdl/verilog/usb_phy.v
0,0 → 1,184
///////////////////////////////////////////////////////////////////// |
//// //// |
//// USB 1.1 PHY //// |
//// //// |
//// //// |
//// Author: Rudolf Usselmann //// |
//// rudi@asics.ws //// |
//// //// |
//// //// |
//// Downloaded from: http://www.opencores.org/cores/usb_phy/ //// |
//// //// |
///////////////////////////////////////////////////////////////////// |
//// //// |
//// Copyright (C) 2000-2002 Rudolf Usselmann //// |
//// www.asics.ws //// |
//// rudi@asics.ws //// |
//// //// |
//// This source file may be used and distributed without //// |
//// restriction provided that this copyright statement is not //// |
//// removed from the file and that any derivative work contains //// |
//// the original copyright notice and the associated disclaimer.//// |
//// //// |
//// THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY //// |
//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED //// |
//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS //// |
//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR //// |
//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, //// |
//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES //// |
//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE //// |
//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR //// |
//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF //// |
//// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT //// |
//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT //// |
//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE //// |
//// POSSIBILITY OF SUCH DAMAGE. //// |
//// //// |
///////////////////////////////////////////////////////////////////// |
|
// CVS Log |
// |
// $Id: usb_phy.v,v 1.4 2003/10/21 05:58:40 rudi Exp $ |
// |
// $Date: 2003/10/21 05:58:40 $ |
// $Revision: 1.4 $ |
// $Author: rudi $ |
// $Locker: $ |
// $State: Exp $ |
// |
// Change History: |
// $Log: usb_phy.v,v $ |
// Revision 1.4 2003/10/21 05:58:40 rudi |
// usb_rst is no longer or'ed with the incomming reset internally. |
// Now usb_rst is simply an output, the application can decide how |
// to utilize it. |
// |
// Revision 1.3 2003/10/19 17:40:13 rudi |
// - Made core more robust against line noise |
// - Added Error Checking and Reporting |
// (See README.txt for more info) |
// |
// Revision 1.2 2002/09/16 16:06:37 rudi |
// Changed top level name to be consistent ... |
// |
// Revision 1.1.1.1 2002/09/16 14:26:59 rudi |
// Created Directory Structure |
// |
// |
// |
// |
// |
// |
// |
// |
|
`include "timescale.v" |
|
module usb_phy(clk, rst, phy_tx_mode, usb_rst, |
|
// Transciever Interface |
txdp, txdn, txoe, |
rxd, rxdp, rxdn, |
|
// UTMI Interface |
DataOut_i, TxValid_i, TxReady_o, RxValid_o, |
RxActive_o, RxError_o, DataIn_o, LineState_o |
); |
|
input clk; |
input rst; |
input phy_tx_mode; |
output usb_rst; |
output txdp, txdn, txoe; |
input rxd, rxdp, rxdn; |
input [7:0] DataOut_i; |
input TxValid_i; |
output TxReady_o; |
output [7:0] DataIn_o; |
output RxValid_o; |
output RxActive_o; |
output RxError_o; |
output [1:0] LineState_o; |
|
/////////////////////////////////////////////////////////////////// |
// |
// Local Wires and Registers |
// |
|
reg [4:0] rst_cnt; |
reg usb_rst; |
wire fs_ce; |
wire rst; |
|
/////////////////////////////////////////////////////////////////// |
// |
// Misc Logic |
// |
|
/////////////////////////////////////////////////////////////////// |
// |
// TX Phy |
// |
|
usb_tx_phy i_tx_phy( |
.clk( clk ), |
.rst( rst ), |
.fs_ce( fs_ce ), |
.phy_mode( phy_tx_mode ), |
|
// Transciever Interface |
.txdp( txdp ), |
.txdn( txdn ), |
.txoe( txoe ), |
|
// UTMI Interface |
.DataOut_i( DataOut_i ), |
.TxValid_i( TxValid_i ), |
.TxReady_o( TxReady_o ) |
); |
|
/////////////////////////////////////////////////////////////////// |
// |
// RX Phy and DPLL |
// |
|
usb_rx_phy i_rx_phy( |
.clk( clk ), |
.rst( rst ), |
.fs_ce( fs_ce ), |
|
// Transciever Interface |
.rxd( rxd ), |
.rxdp( rxdp ), |
.rxdn( rxdn ), |
|
// UTMI Interface |
.DataIn_o( DataIn_o ), |
.RxValid_o( RxValid_o ), |
.RxActive_o( RxActive_o ), |
.RxError_o( RxError_o ), |
.RxEn_i( txoe ), |
.LineState( LineState_o ) |
); |
|
/////////////////////////////////////////////////////////////////// |
// |
// Generate an USB Reset is we see SE0 for at least 2.5uS |
// |
|
`ifdef USB_ASYNC_REST |
always @(posedge clk or negedge rst) |
`else |
always @(posedge clk) |
`endif |
if(!rst) rst_cnt <= 5'h0; |
else |
if(LineState_o != 2'h0) rst_cnt <= 5'h0; |
else |
if(!usb_rst && fs_ce) rst_cnt <= rst_cnt + 5'h1; |
|
always @(posedge clk) |
usb_rst <= (rst_cnt == 5'h1f); |
|
endmodule |
|
/opb_usblite/tags/R1/pcores/opb_usblite_v1_00_a/data/opb_usblite_v2_1_0.pao
0,0 → 1,43
#-- |
#-- opb_usblite - opb_uartlite replacement |
#-- |
#-- opb_usblite is using components from Rudolf Usselmann see |
#-- http://www.opencores.org/cores/usb_phy/ |
#-- and Joris van Rantwijk see http://www.xs4all.nl/~rjoris/fpga/usb.html |
#-- |
#-- Copyright (C) 2010 Ake Rehnman |
#-- |
#-- This program is free software: you can redistribute it and/or modify |
#-- it under the terms of the GNU Lesser General Public License as published by |
#-- the Free Software Foundation, either version 3 of the License, or |
#-- (at your option) any later version. |
#-- |
#-- This program is distributed in the hope that it will be useful, |
#-- but WITHOUT ANY WARRANTY; without even the implied warranty of |
#-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
#-- GNU Lesser General Public License for more details. |
#-- |
#-- You should have received a copy of the GNU Lesser General Public License |
#-- along with this program. If not, see <http://www.gnu.org/licenses/>. |
#-- |
|
lib opb_usblite_v1_00_a timescale.v verilog |
lib opb_usblite_v1_00_a usb_tx_phy.v verilog |
lib opb_usblite_v1_00_a usb_rx_phy.v verilog |
lib opb_usblite_v1_00_a usb_phy.v verilog |
lib opb_usblite_v1_00_a opb_usblite vhdl |
lib opb_usblite_v1_00_a opb_usblite_core vhdl |
lib opb_usblite_v1_00_a usb_control.vhdl vhdl |
lib opb_usblite_v1_00_a usb_init.vhdl vhdl |
lib opb_usblite_v1_00_a usb_packet.vhdl vhdl |
lib opb_usblite_v1_00_a usb_pkg.vhdl vhdl |
lib opb_usblite_v1_00_a usb_serial.vhdl vhdl |
lib opb_usblite_v1_00_a usb_transact.vhdl vhdl |
lib common_v1_00_a family vhdl |
lib common_v1_00_a common_types_pkg vhdl |
lib common_v1_00_a pselect vhdl |
lib common_v1_00_a mux_encode_sel vhdl |
lib common_v1_00_a mux_onehot vhdl |
lib common_v1_00_a or_bits vhdl |
lib common_v1_00_a or_muxcy vhdl |
lib common_v1_00_a or_gate vhdl |
/opb_usblite/tags/R1/pcores/opb_usblite_v1_00_a/data/opb_usblite_v2_1_0.mpd
0,0 → 1,75
#-- |
#-- opb_usblite - opb_uartlite replacement |
#-- |
#-- opb_usblite is using components from Rudolf Usselmann see |
#-- http://www.opencores.org/cores/usb_phy/ |
#-- and Joris van Rantwijk see http://www.xs4all.nl/~rjoris/fpga/usb.html |
#-- |
#-- Copyright (C) 2010 Ake Rehnman |
#-- |
#-- This program is free software: you can redistribute it and/or modify |
#-- it under the terms of the GNU Lesser General Public License as published by |
#-- the Free Software Foundation, either version 3 of the License, or |
#-- (at your option) any later version. |
#-- |
#-- This program is distributed in the hope that it will be useful, |
#-- but WITHOUT ANY WARRANTY; without even the implied warranty of |
#-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
#-- GNU Lesser General Public License for more details. |
#-- |
#-- You should have received a copy of the GNU Lesser General Public License |
#-- along with this program. If not, see <http://www.gnu.org/licenses/>. |
#-- |
|
|
BEGIN opb_usblite |
|
## Peripheral Options |
OPTION IPTYPE = PERIPHERAL |
OPTION IMP_NETLIST = TRUE |
OPTION HDL = VHDL |
OPTION IP_GROUP = MICROBLAZE:PPC:USER |
|
|
## Bus Interfaces |
BUS_INTERFACE BUS = SOPB, BUS_STD = OPB, BUS_TYPE = SLAVE |
|
## Generics for VHDL or Parameters for Verilog |
PARAMETER C_OPB_AWIDTH = 32, DT = INTEGER, BUS = SOPB |
PARAMETER C_OPB_DWIDTH = 32, DT = INTEGER, BUS = SOPB |
PARAMETER C_BASEADDR = 0xffff0000, DT = std_logic_vector(0 to 31), PAIR = C_HIGHADDR, ADDRESS = BASE, BUS = SOPB |
PARAMETER C_HIGHADDR = 0xffff00ff, DT = std_logic_vector, PAIR = C_BASEADDR, ADDRESS = HIGH, BUS = SOPB |
PARAMETER C_SYSRST = 1, DT = std_logic |
PARAMETER C_PHYMODE = 1, DT = std_logic |
PARAMETER C_VENDORID = 0x1234, DT = std_logic_vector(15 downto 0) |
PARAMETER C_PRODUCTID = 0x5678, DT = std_logic_vector(15 downto 0) |
PARAMETER C_VERSIONBCD = 0x0200, DT = std_logic_vector(15 downto 0) |
PARAMETER C_SELFPOWERED = false, DT = BOOLEAN |
PARAMETER C_RXBUFSIZE_BITS = 10, DT = INTEGER |
PARAMETER C_TXBUFSIZE_BITS = 10, DT = INTEGER |
|
## Ports |
PORT OPB_Clk = "", DIR = I, SIGIS = CLK, BUS = SOPB |
PORT OPB_Rst = OPB_Rst, DIR = I, SIGIS = RST, BUS = SOPB |
PORT SYS_Rst = "", DIR = I, SIGIS = RST |
PORT USB_Clk = "", DIR = I, SIGIS = CLK |
PORT OPB_ABus = OPB_ABus, DIR = I, VEC = [0:31], BUS = SOPB |
PORT OPB_BE = OPB_BE, DIR = I, VEC = [0:3], BUS = SOPB |
PORT OPB_RNW = OPB_RNW, DIR = I, BUS = SOPB |
PORT OPB_select = OPB_select, DIR = I, BUS = SOPB |
PORT OPB_seqAddr = OPB_seqAddr, DIR = I, BUS = SOPB |
PORT OPB_DBus = OPB_DBus, DIR = I, VEC = [0:31], BUS = SOPB |
PORT Sl_DBus = Sl_DBus, DIR = O, VEC = [0:31], BUS = SOPB |
PORT Sl_errAck = Sl_errAck, DIR = O, BUS = SOPB |
PORT Sl_retry = Sl_retry, DIR = O, BUS = SOPB |
PORT Sl_toutSup = Sl_toutSup, DIR = O, BUS = SOPB |
PORT Sl_xferAck = Sl_xferAck, DIR = O, BUS = SOPB |
PORT Interrupt = "", DIR = O, LEVEL = HIGH, SIGIS = INTERRUPT, INTERRUPT_PRIORITY = LOW |
PORT txdp = "", DIR = O |
PORT txdn = "", DIR = O |
PORT txoe = "", DIR = O |
PORT rxd = "", DIR = I |
PORT rxdp = "", DIR = I |
PORT rxdn = "", DIR = I |
|
END |
/opb_usblite/tags/R1/drivers/opb_usblite_v1_00_a/src/usblite_l.c
0,0 → 1,43
/* |
-- |
-- opb_usblite - opb_uartlite replacement |
-- |
-- opb_usblite is using components from Rudolf Usselmann see |
-- http://www.opencores.org/cores/usb_phy/ |
-- and Joris van Rantwijk see http://www.xs4all.nl/~rjoris/fpga/usb.html |
-- |
-- Copyright (C) 2010 Ake Rehnman |
-- |
-- This program is free software: you can redistribute it and/or modify |
-- it under the terms of the GNU Lesser General Public License as published by |
-- the Free Software Foundation, either version 3 of the License, or |
-- (at your option) any later version. |
-- |
-- This program is distributed in the hope that it will be useful, |
-- but WITHOUT ANY WARRANTY; without even the implied warranty of |
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
-- GNU Lesser General Public License for more details. |
-- |
-- You should have received a copy of the GNU Lesser General Public License |
-- along with this program. If not, see <http://www.gnu.org/licenses/>. |
-- |
*/ |
#include "usblite_l.h" |
|
/******************************************************************************/ |
void usblite_SendByte(unsigned int base, unsigned char data) |
{ |
while (usblite_mIsTransmitFull(base)); |
|
usblite_out32(base + XUL_TX_FIFO_OFFSET, data); |
} |
|
|
/****************************************************************************/ |
unsigned char usblite_RecvByte(unsigned int base) |
{ |
while (usblite_mIsReceiveEmpty(base)); |
|
return (unsigned char)usblite_in32(base + XUL_RX_FIFO_OFFSET); |
} |
|
/opb_usblite/tags/R1/drivers/opb_usblite_v1_00_a/src/usblite_l.h
0,0 → 1,95
/* |
-- |
-- opb_usblite - opb_uartlite replacement |
-- |
-- opb_usblite is using components from Rudolf Usselmann see |
-- http://www.opencores.org/cores/usb_phy/ |
-- and Joris van Rantwijk see http://www.xs4all.nl/~rjoris/fpga/usb.html |
-- |
-- Copyright (C) 2010 Ake Rehnman |
-- |
-- This program is free software: you can redistribute it and/or modify |
-- it under the terms of the GNU Lesser General Public License as published by |
-- the Free Software Foundation, either version 3 of the License, or |
-- (at your option) any later version. |
-- |
-- This program is distributed in the hope that it will be useful, |
-- but WITHOUT ANY WARRANTY; without even the implied warranty of |
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
-- GNU Lesser General Public License for more details. |
-- |
-- You should have received a copy of the GNU Lesser General Public License |
-- along with this program. If not, see <http://www.gnu.org/licenses/>. |
-- |
*/ |
|
#ifndef USBLITE_L_H /* prevent circular inclusions */ |
#define USBLITE_L_H /* by using protection macros */ |
|
#ifdef __cplusplus |
extern "C" { |
#endif |
|
/* register offsets */ |
|
#define XUL_RX_FIFO_OFFSET 0 /* receive FIFO, read only */ |
#define XUL_TX_FIFO_OFFSET 4 /* transmit FIFO, write only */ |
#define XUL_STATUS_REG_OFFSET 8 /* status register, read only */ |
#define XUL_CONTROL_REG_OFFSET 12 /* control register, write only */ |
|
/* control register bit positions */ |
|
#define XUL_CR_ENABLE_INTR 0x10 /* enable interrupt */ |
#define XUL_CR_FIFO_RX_RESET 0x02 /* reset receive FIFO */ |
#define XUL_CR_FIFO_TX_RESET 0x01 /* reset transmit FIFO */ |
|
/* status register bit positions */ |
|
#define XUL_SR_INTR_ENABLED 0x10 /* interrupt enabled */ |
#define XUL_SR_TX_FIFO_FULL 0x08 /* transmit FIFO full */ |
#define XUL_SR_TX_FIFO_EMPTY 0x04 /* transmit FIFO empty */ |
#define XUL_SR_RX_FIFO_FULL 0x02 /* receive FIFO full */ |
#define XUL_SR_RX_FIFO_VALID_DATA 0x01 /* data in receive FIFO */ |
|
/*****************************************************************************/ |
#define usblite_out32(addr, data) *(unsigned int*)(addr)=(unsigned int)(data) |
|
#define usblite_in32(addr) *(unsigned int*)(addr) |
|
#define usblite_mSetControlReg(BaseAddress, Mask) \ |
usblite_out32((BaseAddress) + XUL_CONTROL_REG_OFFSET, (Mask)) |
|
#define usblite_mGetStatusReg(BaseAddress) \ |
usblite_in32((BaseAddress) + XUL_STATUS_REG_OFFSET) |
|
#define usblite_mIsReceiveEmpty(BaseAddress) \ |
((usblite_mGetStatusReg((BaseAddress)) & XUL_SR_RX_FIFO_VALID_DATA) != \ |
XUL_SR_RX_FIFO_VALID_DATA) |
|
#define usblite_mIsTransmitFull(BaseAddress) \ |
((usblite_mGetStatusReg((BaseAddress)) & XUL_SR_TX_FIFO_FULL) == \ |
XUL_SR_TX_FIFO_FULL) |
|
#define usblite_mIsIntrEnabled(BaseAddress) \ |
((usblite_mGetStatusReg((BaseAddress)) & XUL_SR_INTR_ENABLED) == \ |
XUL_SR_INTR_ENABLED) |
|
#define usblite_mEnableIntr(BaseAddress) \ |
usblite_mSetControlReg((BaseAddress), XUL_CR_ENABLE_INTR) |
|
#define usblite_mDisableIntr(BaseAddress) \ |
usblite_mSetControlReg((BaseAddress), 0) |
|
|
/************************** Function Prototypes *****************************/ |
|
void usblite_SendByte(unsigned int base, unsigned char Data); |
|
unsigned char usblite_RecvByte(unsigned int base); |
|
#ifdef __cplusplus |
} |
#endif |
|
#endif /* end of protection macro */ |
|
/opb_usblite/tags/R1/drivers/opb_usblite_v1_00_a/src/Makefile
0,0 → 1,52
#-- |
#-- opb_usblite - opb_uartlite replacement |
#-- |
#-- opb_usblite is using components from Rudolf Usselmann see |
#-- http://www.opencores.org/cores/usb_phy/ |
#-- and Joris van Rantwijk see http://www.xs4all.nl/~rjoris/fpga/usb.html |
#-- |
#-- Copyright (C) 2010 Ake Rehnman |
#-- |
#-- This program is free software: you can redistribute it and/or modify |
#-- it under the terms of the GNU Lesser General Public License as published by |
#-- the Free Software Foundation, either version 3 of the License, or |
#-- (at your option) any later version. |
#-- |
#-- This program is distributed in the hope that it will be useful, |
#-- but WITHOUT ANY WARRANTY; without even the implied warranty of |
#-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
#-- GNU Lesser General Public License for more details. |
#-- |
#-- You should have received a copy of the GNU Lesser General Public License |
#-- along with this program. If not, see <http://www.gnu.org/licenses/>. |
#-- |
|
|
COMPILER= |
ARCHIVER= |
CP=cp |
COMPILER_FLAGS= |
EXTRA_COMPILER_FLAGS= |
LIB=libxil.a |
|
RELEASEDIR=../../../lib |
INCLUDEDIR=../../../include |
INCLUDES=-I./. -I${INCLUDEDIR} |
|
INCLUDEFILES=usblite_l.h |
LIBSOURCES=*.c |
OUTS = *.o |
|
|
libs: |
echo "Compiling usblite" |
$(COMPILER) $(COMPILER_FLAGS) $(EXTRA_COMPILER_FLAGS) $(INCLUDES) $(LIBSOURCES) |
$(ARCHIVER) -r ${RELEASEDIR}/${LIB} ${OUTS} |
make clean |
|
include: |
${CP} ${INCLUDEFILES} ${INCLUDEDIR} |
|
clean: |
rm -rf ${OUTS} |
|
/opb_usblite/tags/R1/drivers/opb_usblite_v1_00_a/data/opb_usblite_v2_1_0.mdd
0,0 → 1,71
#-- |
#-- opb_usblite - opb_uartlite replacement |
#-- |
#-- opb_usblite is using components from Rudolf Usselmann see |
#-- http://www.opencores.org/cores/usb_phy/ |
#-- and Joris van Rantwijk see http://www.xs4all.nl/~rjoris/fpga/usb.html |
#-- |
#-- Copyright (C) 2010 Ake Rehnman |
#-- |
#-- This program is free software: you can redistribute it and/or modify |
#-- it under the terms of the GNU Lesser General Public License as published by |
#-- the Free Software Foundation, either version 3 of the License, or |
#-- (at your option) any later version. |
#-- |
#-- This program is distributed in the hope that it will be useful, |
#-- but WITHOUT ANY WARRANTY; without even the implied warranty of |
#-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
#-- GNU Lesser General Public License for more details. |
#-- |
#-- You should have received a copy of the GNU Lesser General Public License |
#-- along with this program. If not, see <http://www.gnu.org/licenses/>. |
#-- |
|
OPTION psf_version = 2.1; |
|
BEGIN driver opb_usblite |
|
OPTION supported_peripherals = (opb_usblite); |
OPTION driver_state = ACTIVE; |
OPTION depends = (common_v1_00_a); |
OPTION copyfiles = all; |
|
BEGIN INTERFACE stdin |
PROPERTY header = usblite_l.h; |
FUNCTION name = inbyte, value = usblite_RecvByte; |
END INTERFACE |
|
BEGIN INTERFACE stdout |
PROPERTY header = usblite_l.h; |
FUNCTION name = outbyte, value = usblite_SendByte; |
END INTERFACE |
|
BEGIN INTERFACE stdio |
PROPERTY header = usblite_l.h; |
FUNCTION name = inbyte, value = usblite_RecvByte; |
FUNCTION name = outbyte, value = usblite_SendByte; |
END INTERFACE |
|
BEGIN INTERFACE vxworks5_4 |
END INTERFACE |
|
BEGIN INTERFACE vxworks5_5 |
END INTERFACE |
|
BEGIN INTERFACE vxworks6_1 |
END INTERFACE |
|
BEGIN INTERFACE vxworks6_3 |
END INTERFACE |
|
BEGIN INTERFACE linux |
END INTERFACE |
|
BEGIN ARRAY interrupt_handler |
PROPERTY desc = "Interrupt Handler Information"; |
PROPERTY size = 1, permit = none; |
PARAM name = int_handler, default = XNullHandler, desc = "Name of Interrupt Handler", type = string; |
PARAM name = int_port, default = Interrupt, desc = "Interrupt pin associated with the interrupt handler", permit = none; |
END ARRAY |
|
END driver |
/opb_usblite/tags/R1/schematic/usbif.opj
0,0 → 1,78
(ExpressProject "usbif" |
(ProjectVersion "19981106") |
(ProjectType "PCB") |
(Folder "Design Resources" |
(Folder "Library") |
(NoModify) |
(File ".\usbif.dsn" |
(Type "Schematic Design")) |
(BuildFileAddedOrDeleted "x") |
(CompileFileAddedOrDeleted "x") |
(ANNOTATE_Scope "0") |
(ANNOTATE_Mode "1") |
(ANNOTATE_Action "0") |
(Annotate_Page_Order "0") |
(ANNOTATE_Reset_References_to_1 "FALSE") |
(ANNOTATE_No_Page_Number_Change "FALSE") |
(ANNOTATE_Property_Combine "{Value}{Source Package}{POWER_GROUP}") |
(ANNOTATE_IncludeNonPrimitive "FALSE") |
(ANNOTATE_Refdes_Control_Required "FALSE") |
(Annotate_type "Default") |
(width_pages "100") |
(width_start "80") |
(width_End "80")) |
(Folder "Outputs") |
(Folder "Referenced Projects") |
(PartMRUSelector |
(PAX_TITLEBLOCKX |
(LibraryName "X:\CIS\LIBRARIES\PAX_TITLEBLOCK.OLB") |
(DeviceIndex "0")) |
(Resistor |
(FullPartName "Resistor.Normal") |
(LibraryName "X:\CIS\LIBRARIES\PE_PASSIVE.OLB") |
(DeviceIndex "0")) |
(Zener |
(FullPartName "Zener.Normal") |
(LibraryName "X:\CIS\LIBRARIES\PE_DISCRETE.OLB") |
(DeviceIndex "0")) |
(Capacitor |
(FullPartName "Capacitor.Normal") |
(LibraryName "X:\CIS\LIBRARIES\PE_PASSIVE.OLB") |
(DeviceIndex "0")) |
(VCC_ARROW |
(LibraryName "C:\ORCAD\ORCAD_16.2\TOOLS\CAPTURE\LIBRARY\CAPSYM.OLB") |
(DeviceIndex "0")) |
(GND_SIGNAL |
(LibraryName "C:\ORCAD\ORCAD_16.2\TOOLS\CAPTURE\LIBRARY\CAPSYM.OLB") |
(DeviceIndex "0")) |
("Connector 4+2GND" |
(FullPartName "Connector 4+2GND.Normal") |
(LibraryName "X:\CIS\LIBRARIES\PE_CONNECTOR.OLB") |
(DeviceIndex "0")) |
(USB1T11 |
(FullPartName "USB1T11.Normal") |
(LibraryName "X:\CIS\LIBRARIES\AKRELIB.OLB") |
(DeviceIndex "0"))) |
(LastUsedLibraryBrowseDirectory "X:\CIS\Libraries") |
(GlobalState |
(FileView |
(Path "Design Resources") |
(Path "Design Resources" ".\usbif.dsn") |
(Path "Design Resources" ".\usbif.dsn" "Design Cache") |
(Select "Design Resources" ".\usbif.dsn")) |
(HierarchyView) |
(Doc |
(Type "COrCapturePMDoc") |
(Frame |
(Placement "44 0 1 -1 -1 -4 -23 0 200 0 253")) |
(Tab 0)) |
(Doc |
(Type "COrSchematicDoc") |
(Frame |
(Placement "44 2 3 -1 -1 -4 -23 22 1051 22 302") |
(Scroll "-192 -7") |
(Zoom "65") |
(Occurrence "/")) |
(Path "C:\AKRE\USBTEST\USBIF.DSN") |
(Schematic "SCHEMATIC1") |
(Page "PAGE1")))) |
/opb_usblite/tags/R1/schematic/usbif.pdf
0,0 → 1,83
+\FSQI==%eCmy="W)cQz
+Vh7P\ؑ\tJ>,,1h&Ц
+%,B -<"`\\ +pmJ2%""`^UxSm[K&:<ٚ읣r7ɞ|_ZQ'@\4bvϸlL]DaLP[р`4/_62(=AtDr
+5cU}
+2\̔g3SHbF?c.vX>V=?mS $tXf",k3f6s'4IˋIc\ʬʖ!jW{
+H VD#Zb"UM(0d!I+
+S@R8\p1(׃ iXJb0f4}[W&^y'cLߎ広St1ℓK
+qUG7q:(
+g]Դ!W) #_0ԉht7*[i;B
+tR+zR=}=pOprB:cNq'~֡̓~l''NW8:ϯה RsJ,[@\\̗j,zYԘDQ8KB\,>/.Sz'ж/A6*\\$!{bdl>]]ݜ-P.JH֕2Nf]c=Y%%秿GVJ$۶OcMksSSϞg7G&hSQxmGW'ϧUs|~qq=^8X\,ϧ qU`|]Â>zr
+Ta:t{'+ZNig
+,ch6&tk9H[Hb*qS`bqF3>:8Sz:hj
+tktozDbnfۓx)[t
+Z&?W29zM#vpʔv0+@Á|4]i!a&{lW?<;zj%)t)Z9Mh˫{$3cS
+ڼ'Dgvo FsxU~BJVq3#?ѓHU;iըFg>9|A
+}\u3Fm9li3t%+ƭh,f]+71HzlQϋ1t: n1{UC3`6=k:i]h"-1,U6MN8
+DJ'L:|D*mMbr-C,eѐR+>{eAN~ĿӿO]?%PDF-1.3 |
|
1 0 obj |
<</Type/Pages/Count 1/Kids[4 0 R]>> |
endobj |
2 0 obj |
<</Type/Catalog/Pages 1 0 R>> |
endobj |
3 0 obj |
<</Title (usbif.opj)/Creator (Win2PDF 3.30 http://www.win2pdf.com)/Author (arehnman)/CreationDate (D:20100606141639-22'00')/Producer (PDFlib 3.03 \(Win32\))>> |
endobj |
4 0 obj |
<</Type/Page/Parent 1 0 R/Resources 9 0 R/MediaBox[0 0 841.88 595.27]/Contents[5 0 R]>> |
endobj |
5 0 obj |
<</Length 4569/Filter/FlateDecode>> |
stream |
|
|