------------------------------------------------------------------------------ -- This file is a part of the GRLIB VHDL IP LIBRARY -- Copyright (C) 2003 - 2008, Gaisler Research -- Copyright (C) 2008 - 2010, Aeroflex Gaisler -- -- This program 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. -- -- 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 General Public License for more details. -- -- You should have received a copy of the GNU General Public License -- along with this program; if not, write to the Free Software -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ----------------------------------------------------------------------------- -- Package: usbsim -- File: usbsim.vhd -- Author: Jonas Ekergarn - Aeroflex Gaisler -- Description: Types, constants and procedures used when simulating both -- GRUSBDC and GRUSB_DCL ------------------------------------------------------------------------------ -- pragma translate_off library ieee; use ieee.std_logic_1164.all; use std.textio.all; library grlib; use grlib.stdlib.all; package usbsim is type octet_vector is array (natural range <>) of std_logic_vector(7 downto 0); type grusb_in_type is record datain : std_logic_vector(15 downto 0); rxactive : std_ulogic; rxvalid : std_ulogic; rxvalidh : std_ulogic; rxerror : std_ulogic; txready : std_ulogic; linestate : std_logic_vector(1 downto 0); nxt : std_ulogic; dir : std_ulogic; vbusvalid : std_ulogic; hostdisconnect : std_ulogic; functesten : std_ulogic; end record; type grusb_out_type is record dataout : std_logic_vector(15 downto 0); txvalid : std_ulogic; txvalidh : std_ulogic; opmode : std_logic_vector(1 downto 0); xcvrselect : std_logic_vector(1 downto 0); termselect : std_ulogic; suspendm : std_ulogic; reset : std_ulogic; stp : std_ulogic; oen : std_ulogic; databus16_8 : std_ulogic; dppulldown : std_ulogic; dmpulldown : std_ulogic; idpullup : std_ulogic; drvvbus : std_ulogic; dischrgvbus : std_ulogic; chrgvbus : std_ulogic; txbitstuffenable : std_ulogic; txbitstuffenableh : std_ulogic; fslsserialmode : std_ulogic; tx_enable_n : std_ulogic; tx_dat : std_ulogic; tx_se0 : std_ulogic; end record; ----------------------------------------------------------------------------- -- various test procedures for usb. ----------------------------------------------------------------------------- --Endpoint numbers constant EP0 : std_logic_vector(3 downto 0) := "0000"; constant EP1 : std_logic_vector(3 downto 0) := "0001"; constant EP2 : std_logic_vector(3 downto 0) := "0010"; constant EP3 : std_logic_vector(3 downto 0) := "0011"; constant EP4 : std_logic_vector(3 downto 0) := "0100"; constant EP5 : std_logic_vector(3 downto 0) := "0101"; constant EP6 : std_logic_vector(3 downto 0) := "0110"; constant EP7 : std_logic_vector(3 downto 0) := "0111"; constant EP8 : std_logic_vector(3 downto 0) := "1000"; constant EP9 : std_logic_vector(3 downto 0) := "1001"; constant EP10 : std_logic_vector(3 downto 0) := "1010"; constant EP11 : std_logic_vector(3 downto 0) := "1011"; constant EP12 : std_logic_vector(3 downto 0) := "1100"; constant EP13 : std_logic_vector(3 downto 0) := "1101"; constant EP14 : std_logic_vector(3 downto 0) := "1110"; constant EP15 : std_logic_vector(3 downto 0) := "1111"; ------------------------------------------------------------------------------- --usb pid constants constant TOUT : std_logic_vector( 3 downto 0) := "0001"; constant TIN : std_logic_vector( 3 downto 0) := "1001"; constant SOF : std_logic_vector( 3 downto 0) := "0101"; constant SETUP : std_logic_vector( 3 downto 0) := "1101"; --data constant DATA0 : std_logic_vector( 3 downto 0) := "0011"; constant DATA1 : std_logic_vector( 3 downto 0) := "1011"; constant DATA2 : std_logic_vector( 3 downto 0) := "0111"; constant MDATA : std_logic_vector( 3 downto 0) := "1111"; --handshake constant TACK : std_logic_vector( 3 downto 0) := "0010"; constant TNAK : std_logic_vector( 3 downto 0) := "1010"; constant TSTALL : std_logic_vector( 3 downto 0) := "1110"; constant TNYET : std_logic_vector( 3 downto 0) := "0110"; --special constant PRE : std_logic_vector( 3 downto 0) := "1100"; constant ERR : std_logic_vector( 3 downto 0) := "1100"; constant SPLIT : std_logic_vector( 3 downto 0) := "1000"; constant PING : std_logic_vector( 3 downto 0) := "0100"; constant RESERVED : std_logic_vector( 3 downto 0) := "0000"; -- line states constant SE0 : std_logic_vector(1 downto 0) := "00"; constant J_STATE : std_logic_vector(1 downto 0) := "01"; constant K_STATE : std_logic_vector(1 downto 0) := "10"; constant SE1 : std_logic_vector(1 downto 0) := "11"; -- opcode constant NORM_OP : std_logic_vector(1 downto 0) := "00"; constant NON_DRIV : std_logic_vector(1 downto 0) := "01"; constant NO_NRZI : std_logic_vector(1 downto 0) := "10"; -- ULPI PHY registers combined with regwrite bits constant FCTRL_WADDR : std_logic_vector(7 downto 0) := X"84"; constant FCTRL_SADDR : std_logic_vector(7 downto 0) := X"85"; constant FCTRL_CADDR : std_logic_vector(7 downto 0) := X"86"; -- ULPI RXCMDs constant RXCMD_novbus : std_logic_vector(7 downto 0) := "00000000"; constant RXCMD_fsidle : std_logic_vector(7 downto 0) := "00001101"; constant RXCMD_hsidle : std_logic_vector(7 downto 0) := "00001100"; constant RXCMD_jstate : std_logic_vector(7 downto 0) := "00001101"; constant RXCMD_kstate : std_logic_vector(7 downto 0) := "00001110"; constant RXCMD_se0state : std_logic_vector(7 downto 0) := "00001100"; constant RXCMD_fsrxactive : std_logic_vector(7 downto 0) := "00011110"; constant RXCMD_hsrxactive : std_logic_vector(7 downto 0) := "00011101"; constant RXCMD_eopj : std_logic_vector(7 downto 0) := "00011101"; constant RXCMD_eopse0 : std_logic_vector(7 downto 0) := "00011100"; type uctrl_type is record termselect : std_ulogic; xcvrselect : std_logic_vector(1 downto 0); opmode : std_logic_vector(1 downto 0); suspendm : std_ulogic; end record; -- init usb signals constant usbi_none : grusb_in_type := ( datain => "ZZZZZZZZ" & "00000000", rxactive => '0', rxvalid => '0', rxvalidh => 'Z', rxerror => '0', txready => '0', linestate => "00", nxt => '0', dir => '0', vbusvalid => '1', hostdisconnect => '0', functesten => '1'); constant usbo_none : grusb_out_type := ( dataout => "ZZZZZZZZ" & "00000000", txvalid => '0', txvalidh => 'Z', opmode => "00", xcvrselect => "00", termselect => '0', suspendm => '0', reset => '0', stp => '0', oen => '0', databus16_8 => '0', dppulldown => '0', dmpulldown => '0', idpullup => '0', drvvbus => '0', dischrgvbus => '0', chrgvbus => '0', txbitstuffenable => '0', txbitstuffenableh => '0', fslsserialmode => '0', tx_enable_n => '0', tx_dat => '0', tx_se0 => '0' ); function crc5 ( constant din : std_logic_vector(10 downto 0)) return std_logic_vector; function crc16 ( constant din : std_logic_vector(7 downto 0); constant crc16in : std_logic_vector(15 downto 0)) return std_logic_vector; function pidtostr( constant pid : std_logic_vector(3 downto 0)) return string; procedure uprint( constant Comment: in String := "-"; constant Severe: in Severity_Level := Note; constant Screen: in Boolean := True); procedure gen_rxcmd ( signal clk : in std_ulogic; signal usbi : out grusb_in_type; constant rxcmd : in std_logic_vector(7 downto 0)); procedure accept_regwrite ( signal clk : in std_ulogic; signal usbi : out grusb_in_type; signal usbo : in grusb_out_type; signal uctrl : out uctrl_type); procedure accept_regread ( signal clk : in std_ulogic; signal usbi : out grusb_in_type; signal usbo : in grusb_out_type; constant vbus : in std_ulogic); procedure ulpi_reset ( signal clk : in std_ulogic; signal usbi : out grusb_in_type; signal usbo : in grusb_out_type; signal uctrl : out uctrl_type; constant pullup : in boolean; constant keepclk : in boolean); procedure sendpacket( signal clk : in std_ulogic; constant len : in integer; constant data : in octet_vector; constant uiface : in integer; constant dwidth : in integer; signal rand : in std_logic_vector(7 downto 0); signal usbi : out grusb_in_type; signal hs : in std_ulogic); procedure receivepacket( signal clk : in std_ulogic; constant uiface : in integer; constant dwidth : in integer; signal rand : in std_logic_vector(7 downto 0); variable len : out integer; variable data : out octet_vector; variable TP : inout boolean; signal usbi : out grusb_in_type; signal usbo : in grusb_out_type; signal hs : in std_ulogic; variable timeout : out boolean); procedure ttoken( signal clk : in std_ulogic; constant len : in integer range 0 to 16:= 3; constant pid : in std_logic_vector(3 downto 0); constant piderr : in boolean := false; constant crcerr : in boolean := false; constant device_address : in std_logic_vector(6 downto 0); constant endpoint_number : in std_logic_vector(3 downto 0); constant uiface : in integer; constant dwidth : in integer; signal rand : in std_logic_vector(7 downto 0); signal usbi : out grusb_in_type; signal hs : in std_ulogic); procedure tsof( signal clk : in std_ulogic; constant len : in integer range 0 to 16 := 3; constant fno : in std_logic_vector(10 downto 0); constant piderr : in boolean; constant crcerr : in boolean; signal rand : in std_logic_vector(7 downto 0); constant uiface : in integer; constant dwidth : in integer; signal usbi : out grusb_in_type; signal hs : in std_ulogic); procedure tdata ( signal clk : in std_ulogic; constant pid : in std_logic_vector(3 downto 0); constant piderr : in boolean := false; constant crcerr : in boolean := false; constant data : in octet_vector; constant len : in integer range 0 to 3072; signal rand : in std_logic_vector(7 downto 0); constant uiface : in integer; constant dwidth : in integer; signal usbi : out grusb_in_type; signal hs : in std_ulogic); procedure rhandshake ( signal clk : in std_ulogic; constant expected : in std_logic_vector(3 downto 0); constant nyet : in boolean := false; constant nak : in boolean := false; signal rand : in std_logic_vector(7 downto 0); constant uiface : in integer; constant dwidth : in integer; signal usbi : out grusb_in_type; signal usbo : in grusb_out_type; variable TP : inout boolean; variable gotnak : out boolean; signal hs : in std_ulogic; variable timeout : out boolean); procedure rhandshake ( signal clk : in std_ulogic; constant expected : in std_logic_vector(3 downto 0); constant nyet : in boolean := false; constant nak : in boolean := false; signal rand : in std_logic_vector(7 downto 0); constant uiface : in integer; constant dwidth : in integer; signal usbi : out grusb_in_type; signal usbo : in grusb_out_type; variable TP : inout boolean; variable gotnak : out boolean; variable gotnyet : out boolean; signal hs : in std_ulogic; variable timeout : out boolean); procedure rdata( signal clk : in std_ulogic; constant expected : in std_logic_vector(3 downto 0); constant nak : in boolean := false; constant nbytes : in integer; constant expdata : in octet_vector; constant ep : in integer; constant device_address : in std_logic_vector(6 downto 0); signal rand : in std_logic_vector(7 downto 0); constant uiface : in integer; constant dwidth : in integer; signal usbi : out grusb_in_type; signal usbo : in grusb_out_type; variable TP : inout boolean; constant verbose : in boolean; signal hs : in std_ulogic; constant retryiso : in boolean; variable timeout : out boolean); procedure rdata( signal clk : in std_ulogic; constant expected : in std_logic_vector(3 downto 0); constant nak : in boolean := false; constant nbytes : in integer; constant expdata : in octet_vector; constant ep : in integer; constant device_address : in std_logic_vector(6 downto 0); signal rand : in std_logic_vector(7 downto 0); constant uiface : in integer; constant dwidth : in integer; signal usbi : out grusb_in_type; signal usbo : in grusb_out_type; variable TP : inout boolean; constant verbose : in boolean; signal hs : in std_ulogic; constant retryiso : in boolean; variable timeout : out boolean; variable recdata : out octet_vector; constant checkdata : in boolean); procedure shandshake ( signal clk : in std_ulogic; constant hpid : in std_logic_vector(3 downto 0); constant uiface : in integer; constant dwidth : in integer; signal rand : in std_logic_vector(7 downto 0); signal usbi : out grusb_in_type; signal hs : in std_ulogic); procedure getstatus ( constant dir : in std_logic_vector(3 downto 0); constant stall : in boolean := false; constant nak : in boolean := true; signal clk : in std_ulogic; signal usbo : in grusb_out_type; signal usbi : out grusb_in_type; constant ep : in integer; signal rand : in std_logic_vector(7 downto 0); constant uiface : in integer; constant dwidth : in integer; constant device_address : in std_logic_vector(6 downto 0); variable TP : inout boolean; signal hs : in std_ulogic; variable timeout : out boolean); procedure hs_handshake ( signal clk : in std_ulogic; signal usbi : out grusb_in_type; signal usbo : in grusb_out_type; signal uctrl : out uctrl_type; signal hs : in std_ulogic; constant uiface : in integer); end usbsim; package body usbsim is ----------------------------------------------------------------------------- --usb crc5 calculator. --in: std_logic_vector(10 downto 0) --out: std_logic_vector(4 downto 0) --desrciption: calculates the inverted usb crc5 value on argument. ----------------------------------------------------------------------------- function crc5 ( constant din : std_logic_vector(10 downto 0)) return std_logic_vector is variable dout : std_logic_vector(4 downto 0); begin dout(4) := din(0) xor din(1) xor din(4) xor din(5) xor din(7) xor din(10); dout(3) := din(0) xor din(3) xor din(4) xor din(6) xor din (9); dout(2) := din(0) xor din(1) xor din(2) xor din(3) xor din(4) xor din(7) xor din(8) xor din(10); dout(1) := din(0) xor din(1) xor din(2) xor din(3) xor din(6) xor din(7) xor din(9) xor '1'; dout(0) := din(0) xor din(1) xor din(2) xor din(5) xor din(6) xor din(8); return dout; end function crc5; ----------------------------------------------------------------------------- --usb crc16 calculator --in: old crc16, din(7 downto 0) --out new crc16 value --descripton: calculates the usb crc16 value from earlier crc16 value and din --crc16in set to X"FFFF" for first calculation. ----------------------------------------------------------------------------- function crc16 ( constant din : std_logic_vector(7 downto 0); constant crc16in : std_logic_vector(15 downto 0)) return std_logic_vector is variable dout : std_logic_vector(15 downto 0); begin dout(15) := din(0) xor din(1) xor din(2) xor din(3) xor din(4) xor din(5) xor din(6) xor din(7) xor crc16in(7) xor crc16in(6) xor crc16in(5) xor crc16in(4) xor crc16in(3) xor crc16in(2) xor crc16in(1) xor crc16in(0); dout(14) := din(0) xor din(1) xor din(2) xor din(3) xor din(4) xor din(5) xor din(6) xor crc16in(6) xor crc16in(5) xor crc16in(4) xor crc16in(3) xor crc16in(2) xor crc16in(1) xor crc16in(0); dout(13) := din(6) xor din(7) xor crc16in(7) xor crc16in(6); dout(12) := din(5) xor din(6) xor crc16in(6) xor crc16in(5); dout(11) := din(4) xor din(5) xor crc16in(5) xor crc16in(4); dout(10) := din(3) xor din(4) xor crc16in(4) xor crc16in(3); dout(9) := din(2) xor din(3) xor crc16in(3) xor crc16in(2); dout(8) := din(1) xor din(2) xor crc16in(2) xor crc16in(1); dout(7) := din(0) xor din(1) xor crc16in(15) xor crc16in(1) xor crc16in(0); dout(6) := din(0) xor crc16in(14) xor crc16in(0); dout(5) := crc16in(13); dout(4) := crc16in(12); dout(3) := crc16in(11); dout(2) := crc16in(10); dout(1) := crc16in(9); dout(0) := din(0) xor din(1) xor din(2) xor din(3) xor din(4) xor din(5) xor din(6) xor din(7) xor crc16in(8) xor crc16in(7) xor crc16in(6) xor crc16in(5) xor crc16in(4) xor crc16in(3) xor crc16in(2) xor crc16in(1) xor crc16in(0); return dout; end function crc16; function pidtostr( constant pid : std_logic_vector(3 downto 0)) return string is variable s : string(1 to 8); begin case pid is when TOUT => s := "OUT "; when TIN => s := "IN "; when SOF => s := "SOF "; when SETUP => s := "SETUP "; when DATA0 => s := "DATA0 "; when DATA1 => s := "DATA1 "; when DATA2 => s := "DATA2 "; when MDATA => s := "MDATA "; when TACK => s := "ACK "; when TNAK => s := "NAK "; when TSTALL => s := "STALL "; when TNYET => s := "NYET "; when PRE => s := "PRE "; when SPLIT => s := "SPLIT "; when PING => s := "PING "; when RESERVED => s := "RESERVED"; when others => s := "Illegal "; end case; return s; end function; ----------------------------------------------------------------------------- -- This procedure prints a message to standard output ----------------------------------------------------------------------------- procedure uprint( constant Comment: in String := "-"; constant Severe: in Severity_Level := Note; constant Screen: in Boolean := True) is variable L: Line; begin if Screen then Write(L, Now, Right, 15); Write(L, " : " & Comment); if Severe = Warning then Write(L, String'(" # Warning, ")); elsif Severe = Error then Write(L, String'(" # Error, ")); elsif Severe = Failure then Write(L, String'(" # Failure, ")); end if; WriteLine(Output, L); end if; end procedure uprint; ----------------------------------------------------------------------------- -- ULPI procedures ----------------------------------------------------------------------------- procedure gen_rxcmd ( signal clk : in std_ulogic; signal usbi : out grusb_in_type; constant rxcmd : in std_logic_vector(7 downto 0)) is begin wait until rising_edge(clk); usbi.dir <= '1'; usbi.nxt <= '0'; wait until rising_edge(clk); usbi.datain(7 downto 0) <= rxcmd; wait until rising_edge(clk); usbi.dir <= '0'; usbi.datain(7 downto 0) <= X"00"; end procedure; procedure accept_regwrite ( signal clk : in std_ulogic; signal usbi : out grusb_in_type; signal usbo : in grusb_out_type; signal uctrl : out uctrl_type) is variable fw, fs, fc : boolean := false; variable suspend : std_ulogic := '1'; begin -- if usbo.dataout(7 downto 6) /= "10" then -- wait until usbo.dataout(7 downto 6) = "10"; -- end if; while usbo.dataout(7 downto 6) /= "10" loop wait for 1 ns; end loop; wait until rising_edge(clk); wait for 1 ps; usbi.nxt <= '1'; if usbo.dataout(7 downto 0) = FCTRL_WADDR then fw := true; end if; if usbo.dataout(7 downto 0) = FCTRL_SADDR then fs := true; end if; if usbo.dataout(7 downto 0) = FCTRL_CADDR then fc := true; end if; wait until falling_edge(clk); wait until falling_edge(clk); if fw then uctrl.xcvrselect(0) <= usbo.dataout(0); uctrl.termselect <= usbo.dataout(2); uctrl.opmode(0) <= usbo.dataout(3); uctrl.opmode(1) <= usbo.dataout(4); suspend := usbo.dataout(6); end if; if fs then if usbo.dataout(0) = '1' then uctrl.xcvrselect(0) <= '1'; end if; if usbo.dataout(2) = '1' then uctrl.termselect <= '1'; end if; if usbo.dataout(3) = '1' then uctrl.opmode(0) <= '1'; end if; if usbo.dataout(4) = '1' then uctrl.opmode(1) <= '1'; end if; if usbo.dataout(6) = '1' then suspend := '1'; end if; end if; if fc then if usbo.dataout(0) = '1' then uctrl.xcvrselect(0) <= '0'; end if; if usbo.dataout(2) = '1' then uctrl.termselect <= '0'; end if; if usbo.dataout(3) = '1' then uctrl.opmode(0) <= '0'; end if; if usbo.dataout(4) = '1' then uctrl.opmode(1) <= '0'; end if; if usbo.dataout(6) = '1' then suspend := '0'; end if; end if; wait until rising_edge(usbo.stp); usbi.nxt <= '0'; if suspend = '0' then wait until rising_edge(clk); usbi.dir <= '1'; wait until rising_edge(clk); usbi.datain(7 downto 0) <= "000000" & J_STATE; for i in 0 to 4 loop wait until rising_edge(clk); end loop; -- i wait until falling_edge(clk); uctrl.suspendm <= '0'; else wait until rising_edge(clk); end if; end procedure; procedure accept_regread ( signal clk : in std_ulogic; signal usbi : out grusb_in_type; signal usbo : in grusb_out_type; constant vbus : in std_ulogic) is begin -- if usbo.dataout(7 downto 6) /= "11" then -- wait until usbo.dataout(7 downto 6) = "11"; -- end if; while usbo.dataout(7 downto 6) /= "11" loop wait for 1 ns; end loop; wait until rising_edge(clk); usbi.nxt <= '1'; wait until rising_edge(clk); usbi.nxt <= '0'; usbi.dir <= '1'; wait until rising_edge(clk); usbi.datain(7 downto 0) <= "000000" & vbus & '0'; wait until rising_edge(clk); usbi.dir <= '0'; end procedure; procedure ulpi_reset ( signal clk : in std_ulogic; signal usbi : out grusb_in_type; signal usbo : in grusb_out_type; signal uctrl : out uctrl_type; constant pullup : in boolean; constant keepclk : in boolean) is begin usbi.dir <= '0'; -- Wait for first txcmd (ulpi reset) accept_regwrite(clk,usbi,usbo,uctrl); -- Assert dir and then generate an rxcmd wait until rising_edge(clk); usbi.dir <= '1'; for i in 0 to 4 loop wait until rising_edge(clk); end loop; usbi.dir <= '0'; gen_rxcmd(clk,usbi,RXCMD_novbus); -- Wait for second txcmd (otg register write) accept_regwrite(clk,usbi,usbo,uctrl); -- Wait for third txcmd (interrupt register write) accept_regwrite(clk,usbi,usbo,uctrl); -- Wait for fourth txcmd (interrupt register write) accept_regwrite(clk,usbi,usbo,uctrl); -- Wait for fifth txcmd (ulpi reset) accept_regwrite(clk,usbi,usbo,uctrl); -- Assert dir and then generate an rxcmd wait until rising_edge(clk); usbi.dir <= '1'; for i in 0 to 4 loop wait until rising_edge(clk); end loop; usbi.dir <= '0'; gen_rxcmd(clk,usbi,RXCMD_novbus); -- If pull-up bit is enabled an extra register write will occur if pullup then accept_regwrite(clk,usbi,usbo,uctrl); end if; if not keepclk then accept_regwrite(clk,usbi,usbo,uctrl); if usbo.suspendm = '1' then if usbo.xcvrselect /= "00" or usbo.termselect /= '0' or usbo.opmode /= "00" then -- Wait for suspend (due to no vbus) wait until usbo.suspendm = '0'; end if; end if; end if; end procedure; procedure sendpacket( signal clk : in std_ulogic; constant len : in integer; constant data : in octet_vector; constant uiface : in integer; constant dwidth : in integer; signal rand : in std_logic_vector(7 downto 0); signal usbi : out grusb_in_type; signal hs : in std_ulogic) is variable i : integer; variable ws : integer; begin wait until rising_edge(clk); if uiface = 0 then usbi.linestate <= K_STATE; if hs = '0' then wait until rising_edge(clk); end if; usbi.rxactive <= '1'; if (dwidth = 8) then --8-bit UTMI mode i := 0; while i < len loop ws := conv_integer(rand(1 downto 0)); if ws /= 0 then for i in 0 to ws-1 loop wait until rising_edge(clk); end loop; end if; usbi.rxvalid <= '1'; usbi.datain(7 downto 0) <= data(i); wait until rising_edge(clk); usbi.rxvalid <= '0'; i := i + 1; end loop; else --16-bit UTMI mode i := 0; while i < len loop ws := conv_integer(rand(1 downto 0)); if ws /= 0 then for i in 0 to ws-1 loop wait until rising_edge(clk); end loop; end if; usbi.rxvalid <= '1'; usbi.datain(7 downto 0) <= data(i); i := i + 1; if (rand(7) = '1') and (i < len) then usbi.rxvalidh <= '1'; usbi.datain(15 downto 8) <= data(i); i := i + 1; end if; wait until rising_edge(clk); usbi.rxvalid <= '0'; usbi.rxvalidh <= '0'; end loop; end if; ws := conv_integer(rand(1 downto 0)); if ws /= 0 then for i in 0 to ws-1 loop wait until rising_edge(clk); end loop; end if; usbi.rxactive <= '0'; if hs = '0' then usbi.linestate <= SE0; wait until clk = '1'; usbi.linestate <= J_STATE; end if; else if hs = '0' then gen_rxcmd(clk,usbi,RXCMD_kstate); wait until rising_edge(clk); end if; usbi.dir <= '1'; usbi.nxt <= '1'; wait until rising_edge(clk); usbi.nxt <= '0'; if hs = '0' then usbi.datain(7 downto 0) <= RXCMD_hsrxactive; else usbi.datain(7 downto 0) <= RXCMD_fsrxactive; end if; i := 0; while i < len loop ws := conv_integer(rand(1 downto 0)); if ws /= 0 then for i in 0 to ws-1 loop wait until rising_edge(clk); end loop; end if; usbi.nxt <= '1'; usbi.datain(7 downto 0) <= data(i); wait until rising_edge(clk); usbi.nxt <= '0'; if hs = '0' then usbi.datain(7 downto 0) <= RXCMD_hsrxactive; else usbi.datain(7 downto 0) <= RXCMD_fsrxactive; end if; i := i + 1; end loop; ws := conv_integer(rand(1 downto 0)); if ws /= 0 then for i in 0 to ws-1 loop wait until rising_edge(clk); end loop; end if; if hs = '1' then usbi.datain(7 downto 0) <= RXCMD_eopse0; else usbi.datain(7 downto 0) <= RXCMD_eopse0; wait until rising_edge(clk); usbi.datain(7 downto 0) <= RXCMD_eopj; end if; wait until rising_edge(clk); usbi.dir <= '0'; usbi.datain(7 downto 0) <= (others=>'0'); end if; wait until rising_edge(clk); end procedure; procedure receivepacket( signal clk : in std_ulogic; constant uiface : in integer; constant dwidth : in integer; signal rand : in std_logic_vector(7 downto 0); variable len : out integer; variable data : out octet_vector; variable TP : inout boolean; signal usbi : out grusb_in_type; signal usbo : in grusb_out_type; signal hs : in std_ulogic; variable timeout : out boolean) is variable ws : integer; variable i : integer; variable pvalid : std_ulogic; variable stp : std_ulogic; begin stp := '0'; if uiface = 0 then usbi.linestate <= K_STATE; if usbo.txvalid = '0' then wait until usbo.txvalid = '1'; end if; i := 0; pvalid := '1'; while usbo.txvalid = '1' loop ws := conv_integer(rand(1 downto 0)); if ws /= 0 then for i in 0 to ws-1 loop wait until rising_edge(clk); end loop; end if; usbi.txready <= '1'; wait until rising_edge(clk); if usbo.txvalid = '1' then data(i) := usbo.dataout(7 downto 0); i := i + 1; if (dwidth = 16) then if usbo.txvalidh = '1' then if pvalid = '0' then uprint("ERROR: txvalidh asserted irregularly"); TP := False; end if; pvalid := '1'; data(i) := usbo.dataout(15 downto 8); i := i + 1; else pvalid := '0'; end if; end if; end if; usbi.txready <= '0'; wait until falling_edge(clk); if usbo.txvalid = '0' then end if; end loop; usbi.txready <= '0'; len := i; if hs = '0' then wait until rising_edge(clk); usbi.linestate <= SE0; wait until rising_edge(clk); usbi.linestate <= J_STATE; end if; else i := 0; -- if usbo.dataout(7 downto 6) /= "01" then -- wait until usbo.dataout(7 downto 6) = "01" for 500 ns; -- end if; while usbo.dataout(7 downto 6) /= "01" loop wait for 1 ns; end loop; if usbo.dataout(7 downto 6) /= "01" then timeout := true; else timeout := false; wait until rising_edge(clk); while stp = '0' loop usbi.nxt <= '1'; wait until rising_edge(clk); data(i) := usbo.dataout(7 downto 0); if i = 0 then data(i)(7 downto 4) := not usbo.dataout(3 downto 0); end if; i := i+1; wait until falling_edge(clk); stp := usbo.stp; end loop; wait until rising_edge(clk); usbi.nxt <= '0'; len := i; if hs = '1' then gen_rxcmd(clk,usbi,RXCMD_jstate); gen_rxcmd(clk,usbi,RXCMD_se0state); else gen_rxcmd(clk,usbi,RXCMD_se0state); gen_rxcmd(clk,usbi,RXCMD_jstate); end if; end if; end if; end procedure; ----------------------------------------------------------------------------- -- usb token packet procedure. -- transmits a token packet, as specified by the input signals ----------------------------------------------------------------------------- procedure ttoken( signal clk : in std_ulogic; constant len : in integer range 0 to 16:= 3; constant pid : in std_logic_vector(3 downto 0); constant piderr : in boolean := false; constant crcerr : in boolean := false; constant device_address : in std_logic_vector(6 downto 0); constant endpoint_number : in std_logic_vector(3 downto 0); constant uiface : in integer; constant dwidth : in integer; signal rand : in std_logic_vector(7 downto 0); signal usbi : out grusb_in_type; signal hs : in std_ulogic) is variable p : octet_vector(0 to 15); variable tmp : std_logic_vector(10 downto 0); variable i : integer; variable ws : integer; begin --build packet for i in 0 to len-1 loop case i is when 0 => --PID p(0) := not PID & PID; --generate pid error if piderr then p(0)(conv_integer(rand(2 downto 0))) := not p(0)(conv_integer(rand(2 downto 0))); end if; when 1 => --ADDR & EP p(1) := endpoint_number(0) & device_address; when 2 => --EP & CRC tmp := endpoint_number & device_address; p(2) := crc5(tmp) & endpoint_number(3 downto 1); if crcerr then p(2)(3+conv_integer(rand(1 downto 0))) := not p(2)(3+conv_integer(rand(1 downto 0))); end if; when others => --EXCESSIVE DATA p(i) := rand; end case; end loop; --packet transmission sendpacket(clk, len, p, uiface, dwidth, rand, usbi, hs); end ttoken; ----------------------------------------------------------------------------- -- usb sof packet procedure. -- transmit specified framenumber procedure tsof( signal clk : in std_ulogic; constant len : in integer range 0 to 16 := 3; constant fno : in std_logic_vector(10 downto 0); constant piderr : in boolean; constant crcerr : in boolean; signal rand : in std_logic_vector(7 downto 0); constant uiface : in integer; constant dwidth : in integer; signal usbi : out grusb_in_type; signal hs : in std_ulogic) is variable ws : integer; variable p : octet_vector(0 to 15); begin --build packet for i in 0 to len-1 loop case i is when 0 => --PID p(0) := not SOF & SOF; --generate pid error if piderr then p(0)(conv_integer(rand(2 downto 0))) := not p(0)(conv_integer(rand(2 downto 0))); end if; when 1 => --fno p(1) := fno(7 downto 0); when 2 => --EP & CRC p(2) := crc5(fno) & fno(10 downto 8); if crcerr then p(2)(3+conv_integer(rand(1 downto 0))) := not p(2)(3+conv_integer(rand(1 downto 0))); end if; when others => --EXCESSIVE DATA p(i) := rand; end case; end loop; --packet transmission sendpacket(clk, len, p, uiface, dwidth, rand, usbi, hs); end tsof; ----------------------------------------------------------------------------- -- usb data packet procedure -- transmits the number of bytes provided. -- calculates and transmits crc16 value procedure tdata ( signal clk : in std_ulogic; constant pid : in std_logic_vector(3 downto 0); constant piderr : in boolean := false; constant crcerr : in boolean := false; constant data : in octet_vector; constant len : in integer range 0 to 3072; signal rand : in std_logic_vector(7 downto 0); constant uiface : in integer; constant dwidth : in integer; signal usbi : out grusb_in_type; signal hs : in std_ulogic) is variable crc : std_logic_vector(15 downto 0) := X"FFFF"; variable p : octet_vector(0 to len+2); variable ws : integer; begin --build packet for i in 0 to len loop case i is when 0 => -- PID p(0) := not pid & pid; if piderr then p(0)(conv_integer(rand(2 downto 0))) := not p(0)(conv_integer(rand(2 downto 0))); end if; when others => p(i) := data(data'low+i-1); crc := crc16(p(i), crc); end case; end loop; crc := not crc; if crcerr then crc(conv_integer(rand(2 downto 0))) := not crc(conv_integer(rand(2 downto 0))); end if; p(len+1) := crc(7 downto 0); p(len+2) := crc(15 downto 8); --packet transmission sendpacket(clk, len+3, p, uiface, dwidth, rand, usbi, hs); end tdata; --------------------------------------------------------------------------- -- usb receive handshake procedure -- checks if the expected handshake was received properly procedure rhandshake ( signal clk : in std_ulogic; constant expected : in std_logic_vector(3 downto 0); constant nyet : in boolean := false; constant nak : in boolean := false; signal rand : in std_logic_vector(7 downto 0); constant uiface : in integer; constant dwidth : in integer; signal usbi : out grusb_in_type; signal usbo : in grusb_out_type; variable TP : inout boolean; variable gotnak : out boolean; signal hs : in std_ulogic; variable timeout : out boolean) is variable res : boolean := false; variable data : octet_vector(0 to 3071); variable len : integer; variable timeoutv : boolean; begin --receive packet receivepacket(clk, uiface, dwidth, rand, len, data, TP, usbi, usbo, hs, timeoutv); timeout := timeoutv; if not timeoutv then --check packet if (len /= 1) then uprint("ERROR: Handshake of illegal length(" & tost(len) &") received"); TP := False; elsif (not data(0)(7 downto 4)) /= data(0)(3 downto 0) then uprint("ERROR: PID and inverted PID fields do not match"); TP := False; end if; gotnak := (data(0)(3 downto 0) = TNAK) and TP; if not ((data(0)(3 downto 0) = expected) or ((data(0)(3 downto 0) = TNYET) and nyet) or ((data(0)(3 downto 0) = TNAK) and nak)) then uprint("ERROR: PIDs do not match"); uprint("Expected: " & pidtostr(expected) & " Received: " & pidtostr(data(0)(3 downto 0))); TP := False; end if; end if; end rhandshake; procedure rhandshake ( signal clk : in std_ulogic; constant expected : in std_logic_vector(3 downto 0); constant nyet : in boolean := false; constant nak : in boolean := false; signal rand : in std_logic_vector(7 downto 0); constant uiface : in integer; constant dwidth : in integer; signal usbi : out grusb_in_type; signal usbo : in grusb_out_type; variable TP : inout boolean; variable gotnak : out boolean; variable gotnyet : out boolean; signal hs : in std_ulogic; variable timeout : out boolean) is variable res : boolean := false; variable data : octet_vector(0 to 3071); variable len : integer; variable timeoutv : boolean; begin --receive packet receivepacket(clk, uiface, dwidth, rand, len, data, TP, usbi, usbo, hs, timeoutv); timeout := timeoutv; if not timeoutv then --check packet if (len /= 1) then uprint("ERROR: Handshake of illegal length(" & tost(len) &") received"); TP := False; elsif (not data(0)(7 downto 4)) /= data(0)(3 downto 0) then uprint("ERROR: PID and inverted PID fields do not match"); TP := False; end if; gotnak := (data(0)(3 downto 0) = TNAK) and TP; gotnyet := (data(0)(3 downto 0) = TNYET) and TP; if not ((data(0)(3 downto 0) = expected) or ((data(0)(3 downto 0) = TNYET) and nyet) or ((data(0)(3 downto 0) = TNAK) and nak)) then uprint("ERROR: PIDs do not match"); uprint("Expected: " & pidtostr(expected) & " Received: " & pidtostr(data(0)(3 downto 0))); TP := False; end if; end if; end rhandshake; ----------------------------------------------------------------------------- -- usb receive data packet procedure -- calculates and compare crc16 value procedure rdata( signal clk : in std_ulogic; constant expected : in std_logic_vector(3 downto 0); constant nak : in boolean := false; constant nbytes : in integer; constant expdata : in octet_vector; constant ep : in integer; constant device_address : in std_logic_vector(6 downto 0); signal rand : in std_logic_vector(7 downto 0); constant uiface : in integer; constant dwidth : in integer; signal usbi : out grusb_in_type; signal usbo : in grusb_out_type; variable TP : inout boolean; constant verbose : in boolean; signal hs : in std_ulogic; constant retryiso : in boolean; -- set to true only when a -- zero byte DATA0 response -- from a isochronous ep -- should lead to a retry of -- the IN variable timeout : out boolean) is variable res : boolean := false; variable crc : std_logic_vector(15 downto 0) := X"FFFF"; variable s : line; variable bytes : integer := 0; variable msg : boolean := false; variable dout : std_logic_vector(7 downto 0); variable err : boolean := false; constant str : string := ", "; variable data : octet_vector(0 to 3071); variable len : integer; begin usbi <= usbi_none; usbi.linestate <= K_STATE; while true loop ttoken(clk, 3, TIN, false, false, device_address, conv_std_logic_vector(ep, 4), uiface, dwidth, rand, usbi, hs); receivepacket(clk, uiface, dwidth, rand, len, data, TP, usbi, usbo, hs, timeout); if (len > 0) then if (data(0)(3 downto 0) = not data(0)(7 downto 4)) then if (nak and (data(0)(3 downto 0) = TNAK)) or (retryiso and data(0)(3 downto 0) = DATA0 and len = 3) then if not msg then if (retryiso and data(0)(3 downto 0) = DATA0 and len = 3) then if verbose then uprint("Zero byte DATA0 received from isochornous endpoint, retry IN"); end if; else if verbose then uprint("NAK received. Device not ready to send data. Trying new IN"); end if; end if; msg := true; end if; next; else if (data(0)(3 downto 0) = expected) then case expected is when TNAK => if not msg then uprint("NAK received. Device not ready to send data. Trying new IN"); msg := true; end if; next; when TSTALL => uprint("STALL PID received. Aborting receive"); err := true; exit; when TNYET => uprint("NYET PID received. Should not be returned for IN tokens. Aborting Receive"); TP := false; err := true; exit; when DATA0 => exit; when DATA1 => exit; when DATA2 => exit; when others => uprint("Illegal PID returned for this stage. Aborting Receive"); TP := false; err := true; exit; end case; else uprint("ERROR: Incorrect PID received. Got: " & pidtostr(data(0)(3 downto 0)) & " Expected: " & pidtostr(expected)); TP := false; err := true; exit; end if; end if; else uprint("ERROR: PID and Inverted PID fields do not match"); TP := False; err := true; exit; end if; else uprint("ERROR: Zero length packet received"); TP := False; err := true; exit; end if; end loop; if not err then if verbose then uprint("Total amount of received bytes: " & tost(len)); end if; if (len-3 /= nbytes) then uprint("ERROR: Wrong amount of data accepted. Expected: " & tost(nbytes) & " Got: " & tost(len-3)); TP := False; end if; for i in 0 to len-1 loop if (i > 0) and (i < len-2) then crc := crc16(data(data'low+i), crc); if data(data'low+i) /= expdata(expdata'low+i-1) then uprint("ERROR in received data. Index: " & tost(i) & " Expected: " & tost(expdata(expdata'low+i-1)) & " got: " & tost(data(data'low+i))); TP := false; end if; end if; if verbose then uprint(tost(data(data'low+i))); end if; end loop; if ((not crc(7 downto 0)) /= data(data'low+len-2)) or ((not crc(15 downto 8)) /= data(data'low+len-1)) then uprint("ERROR: CRC16 checksum do not match"); TP := False; end if; end if; end rdata; ----------------------------------------------------------------------------- -- usb receive data packet procedure -- calculates and compare crc16 value procedure rdata( signal clk : in std_ulogic; constant expected : in std_logic_vector(3 downto 0); constant nak : in boolean := false; constant nbytes : in integer; constant expdata : in octet_vector; constant ep : in integer; constant device_address : in std_logic_vector(6 downto 0); signal rand : in std_logic_vector(7 downto 0); constant uiface : in integer; constant dwidth : in integer; signal usbi : out grusb_in_type; signal usbo : in grusb_out_type; variable TP : inout boolean; constant verbose : in boolean; signal hs : in std_ulogic; constant retryiso : in boolean; -- set to true only when a -- zero byte DATA0 response -- from a isochronous ep -- should lead to a retry of -- the IN variable timeout : out boolean; variable recdata : out octet_vector; constant checkdata : in boolean) is variable res : boolean := false; variable crc : std_logic_vector(15 downto 0) := X"FFFF"; variable s : line; variable bytes : integer := 0; variable msg : boolean := false; variable dout : std_logic_vector(7 downto 0); variable err : boolean := false; constant str : string := ", "; variable data : octet_vector(0 to 3071); variable len : integer; begin usbi <= usbi_none; usbi.linestate <= K_STATE; while true loop ttoken(clk, 3, TIN, false, false, device_address, conv_std_logic_vector(ep, 4), uiface, dwidth, rand, usbi, hs); receivepacket(clk, uiface, dwidth, rand, len, data, TP, usbi, usbo, hs, timeout); if (len > 0) then if (data(0)(3 downto 0) = not data(0)(7 downto 4)) then if (nak and (data(0)(3 downto 0) = TNAK)) or (retryiso and data(0)(3 downto 0) = DATA0 and len = 3) then if not msg then if (retryiso and data(0)(3 downto 0) = DATA0 and len = 3) then if verbose then uprint("Zero byte DATA0 received from isochornous endpoint, retry IN"); end if; else if verbose then uprint("NAK received. Device not ready to send data. Trying new IN"); end if; end if; msg := true; end if; next; else if (data(0)(3 downto 0) = expected) then case expected is when TNAK => if not msg then uprint("NAK received. Device not ready to send data. Trying new IN"); msg := true; end if; next; when TSTALL => uprint("STALL PID received. Aborting receive"); err := true; exit; when TNYET => uprint("NYET PID received. Should not be returned for IN tokens. Aborting Receive"); TP := false; err := true; exit; when DATA0 => exit; when DATA1 => exit; when DATA2 => exit; when others => uprint("Illegal PID returned for this stage. Aborting Receive"); TP := false; err := true; exit; end case; else uprint("ERROR: Incorrect PID received. Got: " & pidtostr(data(0)(3 downto 0)) & " Expected: " & pidtostr(expected)); TP := false; err := true; exit; end if; end if; else uprint("ERROR: PID and Inverted PID fields do not match"); TP := False; err := true; exit; end if; else uprint("ERROR: Zero length packet received"); TP := False; err := true; exit; end if; end loop; if not err then if verbose then uprint("Total amount of received bytes: " & tost(len)); end if; if (len-3 /= nbytes) then uprint("ERROR: Wrong amount of data accepted. Expected: " & tost(nbytes) & " Got: " & tost(len-3)); TP := False; end if; for i in 0 to len-1 loop if (i > 0) and (i < len-2) then crc := crc16(data(data'low+i), crc); if checkdata then if data(data'low+i) /= expdata(expdata'low+i-1) then uprint("ERROR in received data. Index: " & tost(i) & " Expected: " & tost(expdata(expdata'low+i-1)) & " got: " & tost(data(data'low+i))); TP := false; end if; end if; recdata(recdata'low+i-1) := data(data'low+i); end if; if verbose then uprint(tost(data(data'low+i))); end if; end loop; if ((not crc(7 downto 0)) /= data(data'low+len-2)) or ((not crc(15 downto 8)) /= data(data'low+len-1)) then uprint("ERROR: CRC16 checksum do not match"); TP := False; end if; end if; end rdata; --------------------------------------------------------------------------- -- usb transmit handshake procedure -- sends specified handshake packet procedure shandshake ( signal clk : in std_ulogic; constant hpid : in std_logic_vector(3 downto 0); constant uiface : in integer; constant dwidth : in integer; signal rand : in std_logic_vector(7 downto 0); signal usbi : out grusb_in_type; signal hs : in std_ulogic) is variable p : octet_vector(0 to 0); begin p(0) := not hpid & hpid; sendpacket(clk, 1, p, uiface, dwidth, rand, usbi, hs); end shandshake; ----------------------------------------------------------------------------- -- get device status procedure getstatus ( constant dir : in std_logic_vector(3 downto 0); constant stall : in boolean := false; constant nak : in boolean := true; signal clk : in std_ulogic; signal usbo : in grusb_out_type; signal usbi : out grusb_in_type; constant ep : in integer; signal rand : in std_logic_vector(7 downto 0); constant uiface : in integer; constant dwidth : in integer; constant device_address : in std_logic_vector(6 downto 0); variable TP : inout boolean; signal hs : in std_ulogic; variable timeout : out boolean) is variable pid : std_logic_vector(3 downto 0); variable data : octet_vector(0 to 0); variable gotnak : boolean; begin if dir = TIN then if stall then pid := TSTALL; else pid := DATA1; end if; rdata(clk, pid, nak, 0, data, ep, device_address, rand, uiface, dwidth, usbi, usbo, TP, false, hs, false, timeout); shandshake(clk, TACK, uiface, dwidth, rand, usbi, hs); elsif dir = TOUT then if stall then pid := TSTALL; else pid := TACK; end if; gotnak := true; while gotnak loop ttoken(clk, 3, TOUT, false, false, device_address, conv_std_logic_vector(ep, 4), uiface, dwidth, rand, usbi, hs); tdata(clk, DATA1, false, false, data(0 to 0), 0, rand, uiface, dwidth, usbi, hs); rhandshake (clk, pid, false, nak, rand, uiface, dwidth, usbi, usbo, TP, gotnak, hs, timeout); end loop; end if; end getstatus; procedure hs_handshake ( signal clk : in std_ulogic; signal usbi : out grusb_in_type; signal usbo : in grusb_out_type; signal uctrl : out uctrl_type; signal hs : in std_ulogic; constant uiface : in integer) is begin usbi.linestate <= SE0; if uiface = 1 then gen_rxcmd(clk,usbi,RXCMD_se0state); accept_regwrite(clk,usbi,usbo,uctrl); if usbo.xcvrselect(0) = '1' then wait until usbo.xcvrselect(0) = '0'; end if; else wait until usbo.xcvrselect(0) = '0'; end if; if uiface = 0 then if usbo.txvalid = '0' then wait until usbo.txvalid = '1'; end if; else if usbo.dataout(7 downto 0) = "00000000" then wait until usbo.dataout(7 downto 0) /= "00000000"; end if; end if; if uiface = 0 then usbi.txready <= '1'; usbi.linestate <= K_STATE; wait until usbo.txvalid = '0'; usbi.linestate <= K_STATE; usbi.txready <= '0'; else wait until rising_edge(clk); usbi.nxt <= '1'; wait until rising_edge(usbo.stp); wait until rising_edge(clk); usbi.nxt <= '0'; end if; wait for 50 us; for i in 0 to 5 loop if (i mod 2) = 0 then usbi.linestate <= K_STATE; if uiface = 1 then gen_rxcmd(clk,usbi,RXCMD_kstate); end if; else usbi.linestate <= J_STATE; if uiface = 1 then gen_rxcmd(clk,usbi,RXCMD_jstate); end if; end if; if uiface = 1 then if i = 5 then accept_regwrite(clk,usbi,usbo,uctrl); end if; end if; wait for 45 us; end loop; usbi.linestate <= SE0; if uiface = 1 then gen_rxcmd(clk,usbi,RXCMD_se0state); else if usbo.termselect /= '0' then wait until usbo.termselect = '0'; end if; end if; end hs_handshake; end usbsim;