⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 usiedpll.v

📁 实现USB接口功能的VHDL和verilog完整源代码
💻 V
字号:
/******************************************
	Filename: 	siedpll.v 1.27
******************************************/

/*
The Digital PLL module takes the incoming signal, synchronizes it through
a pair of flops for EACH input (data, plus, minus), and then looks for
edges.  Based on transitions/edges it creates a divide by 4 clock and
outputs synchronized data.  For every transition it readjusts its sampling
and output clock so that it is always sampling in between data transitions.
It also adjusts the output clock, lest the output clock get too far ahead of
or behind the data [Imagine if the bus does 1000 transitions while we do
999, if we didn't keep adjusting the USB clock, eventually we'd miss one] 
*/
module Usiedpll  (
		  // inputs
                  testmode,
                  testreset,
		  clock48,
		  usbclock,
		  rcvin,
		  vpin,
		  vmin,
		  pwronreset,
		  se0reset,
		  syncreset48,
		  //suspend,
		  xmitactive,
		  usboen,
		  
		  // outputs
		  syncidle,
		  syncrcv,
		  syncse0,
		  syncerror,
		  syncreset48out,
		  syncreset,
		  usbreset,
		  usbclockout//,
		  //usbclocksuspendedout,
		  //clock24out
		  );

`include "Usiedplldef.v"

  input           testmode;
  input           testreset;
  input	clock48;
  input	usbclock;
  input	rcvin;
  input	pwronreset;	// synopsys sync_set_reset "pwronreset"
  input	se0reset;
  input	syncreset48;	// synopsys sync_set_reset "syncreset48"
  //input	suspend;
  input	xmitactive;
  input	vpin;
  input	vmin;
  input	usboen;

  output    usbclockout;
  //output    usbclocksuspendedout;
  //output    clock24out;
  output    syncidle;
  output    syncrcv;
  output    syncse0;
  output    syncerror;
  output    syncreset48out;
  output    syncreset;
  output    usbreset;

  reg	    syncidle;
  reg	    syncrcv;
  reg	    syncse0;
  reg	    syncerror;
  reg	    syncreset48out;
  reg	    syncreset48bad;
  reg [1:0] clock48quarter, selectquarter;
  reg	    resetselectquarter, incrselectquarter, decrselectquarter;
  reg	    rcvbad;
  reg [1:0] rcvgood;
  reg [1:0] filterbits;
  reg	    filteredrcvd;
  reg [3:0] vpinflops; // 3 tmp stages and the one i look at
  reg [3:0] vminflops;
  // we have 4 delay stages on rcvin so we need 4 on vm and vp
  wire	    vpingood = vpinflops[3];
  wire	    vmingood = vminflops[3];
  reg [7:0] dpllst, nextdpllst;
  reg	    idleselected, rcvselected, se0selected, errorselected, fsselected, lsselected;
  reg	    removelogicreset;
  reg	    xmitactived1, xmitactive48;

  always @(posedge clock48)
    begin
      syncreset48bad <= pwronreset;
      syncreset48out <= syncreset48bad;
      xmitactive48 <= xmitactive || xmitactived1; // i'm keeping this around longer
                               // and bringing it to the clock48 domain before I use it in
                               // the dpll state machine. I dont want to respond to noise
                               // during the turnaround from us driving to the host driving
    end

always @(posedge clock48)
begin
	// syncreset48 is a pwronreset, only active for a short time
	if (syncreset48)
		clock48quarter <= 2'b00;
	else 
	case (clock48quarter)	// synopsys parallel_case full_case
		2'b00 :	clock48quarter <= 2'b01;
		2'b01 :	clock48quarter <= 2'b10;
		2'b10 :	clock48quarter <= 2'b11;
		2'b11 :	clock48quarter <= 2'b00;
	endcase

	if (resetselectquarter)
		selectquarter <= clock48quarter + 2'b10;	// initially set it to 1/2 clock later
	else if (incrselectquarter)
		selectquarter <= selectquarter + 1'b1;
	else if (decrselectquarter)
		selectquarter <= selectquarter - 1'b1;

	//usbclockout <= ~((clock48quarter == selectquarter) || (clock48quarter == (selectquarter + 1'b1)));
end

wire	usbclockpre = ~((clock48quarter == selectquarter) || (clock48quarter == (selectquarter + 1'b1)));
//wire	usbclocksuspendedpre = ~(suspend || (clock48quarter == selectquarter) || (clock48quarter == (selectquarter + 1'b1)));
//wire	clock24pre = ~suspend && clock48quarter[0];

// special aysnc flop logic for usbclockout 
// syncreset48 is a pwronreset, only active for a short time
wire   rstn;
assign rstn = (testmode)? testreset : ~syncreset48;
dffr clkflop (
	.q (usbclockout),
	.d (usbclockpre),
	.clk (clock48),
	.rstn (rstn)
	);

//// special aysnc flop logic for usbclocksuspendedout 
//dffr clksflop (
//	.q (usbclocksuspendedout),
//	.d (usbclocksuspendedpre),
//	.clk (clock48),
//	.rstn (~pwronreset)
//	);
//
//// special aysnc flop logic for clock24out 
//dffr clk24flop (
//	.q (clock24out),
//	.d (clock24pre),
//	.clk (clock48),
//	.rstn (~pwronreset)
//	);

// find four good usb fast rcv points
  always @(posedge clock48)
    begin
      rcvbad <= rcvin;
      rcvgood <= {rcvgood[0],filteredrcvd};
      filterbits <= {filterbits[0],rcvbad}; // first two storage stages used to
                                               // filter glitches
      vpinflops <= {vpinflops[2:0],vpin};
      vminflops <= {vminflops[2:0],vmin};
    end // always @ (posedge clock48)


  always @(filterbits or rcvgood)
    case (filterbits)
      2'b00 : filteredrcvd = 1'b0; // 0 for 2 clks in a row, call it a 0
      2'b10 : filteredrcvd = rcvgood[0]; // dont get excited, may be a glitch
      2'b01 : filteredrcvd = rcvgood[0]; // dont get excited, may be a glitch
      2'b11 : filteredrcvd = 1'b1; // 1 for 2 clks in a row, call it a 1
   default : filteredrcvd = rcvgood[0];
    endcase

// syncreset48 is a pwronreset, only active for a short time
// grab off the bus at the right moment
  always @(posedge clock48)
    begin
      if (syncreset48)
	begin
	  idleselected <= 1'b1;
	  rcvselected <= 1'b1;
	  se0selected <= 1'b0;
	  errorselected <= 1'b0;
	  fsselected <= 1'b1;
	  lsselected <= 1'b0;
	end
      else if (selectquarter == clock48quarter)	// time to grab rcv
	begin
	  // idle if in state idle OR if were se0selected but won't be now
	  idleselected <= (dpllst == DPLLIDLE) || (se0selected && (vpingood || vmingood));
	  rcvselected <= rcvgood[0];
	  se0selected <= ({vpingood,vmingood} == 2'b00);
	  errorselected <= ({vpingood,vmingood} == 2'b11);
	  fsselected <= ({vpingood,vmingood} == 2'b01);
	  lsselected <= ({vpingood,vmingood} == 2'b10);
	end
      // else leave alone!
    end

// sync up usb rcv to usb clock
  reg usbreset;
  wire	syncresetn;
  always @(posedge usbclock)
    begin
      syncidle <= idleselected;
      syncrcv <= rcvselected;
      syncse0 <= se0selected;
      syncerror <= errorselected;
      usbreset <= ~syncresetn || se0reset; // helps for static timing analysis
      xmitactived1 <= (usboen == 1'b0); // oe is one clock after xmitactive
                      // and here we're delaying it one more even
                                     
    end

wire	clearreset = removelogicreset ? 1'b1 : syncresetn;
wire	syncreset = ~syncresetn;

// special aysnc flop logic for syncreset 
wire   rstn1;
assign rstn1 = (testmode)? testreset : ~pwronreset;
dffr resetflop (
	.q (syncresetn),
	.d (clearreset),
	.clk (usbclock),
	.rstn (rstn1)
	);


// state machine for syncing to the rcv transition edges

  always @(posedge clock48)
    begin
      if (syncreset48)
	dpllst <= DPLLIDLE;
      else
	dpllst <= nextdpllst;
    end

  always @(dpllst or rcvgood or syncreset48 or se0selected or xmitactive48)
    begin
      if (syncreset48 == 1)
	begin
	  resetselectquarter = 1'b1;	
	  incrselectquarter = 1'b0;
	  decrselectquarter = 1'b0;
	  removelogicreset = 1'b0;
	  nextdpllst = DPLLIDLE;
	end
      else
	case (dpllst)	// synopsys parallel_case full_case
	  DPLLIDLE:
	    begin
	      incrselectquarter = 1'b0;
	      decrselectquarter = 1'b0;
	      removelogicreset = 1'b1;
	      if (~xmitactive48 && (rcvgood[1] != rcvgood[0]))	// input transition, leaving idle
		begin
		  resetselectquarter = 1'b1;	
		  nextdpllst = DPLL1ST;
		end
	      else
		begin
		  resetselectquarter = 1'b0;
		  nextdpllst = DPLLIDLE;
		end
	    end
	  DPLL1ST:
	    begin
	      incrselectquarter = 1'b0;
	      decrselectquarter = 1'b0;
	      removelogicreset = 1'b1;
	      if (rcvgood[1] != rcvgood[0])	// 2nd transition, resync pll
		begin
		  resetselectquarter = 1'b1;	
		  nextdpllst = DPLLQ1;
		end
	      else
		begin
		  resetselectquarter = 1'b0;
		  nextdpllst = DPLL1ST;
		end
	    end
	  DPLLQ1:
	    begin
	      resetselectquarter = 1'b0;	
	      incrselectquarter = 1'b0;
	      decrselectquarter = 1'b0;
	      removelogicreset = 1'b1;
	      nextdpllst = DPLLQ2;
	    end
	  DPLLQ2:
	    begin
	      resetselectquarter = 1'b0;	
	      incrselectquarter = 1'b0;
	      decrselectquarter = 1'b0;
	      removelogicreset = 1'b1;
	      nextdpllst = DPLLQ3;
	    end
	  DPLLQ3:
	    begin
	      resetselectquarter = 1'b0;	
	      incrselectquarter = 1'b0;
	      removelogicreset = 1'b1;
	      if (se0selected)
		begin
		  nextdpllst = DPLLSE0;
		  decrselectquarter = 1'b0;
		end
	      else if (rcvgood[1] != rcvgood[0])	// transition
		begin
		  // we need to shrink our clock,
		  // because we saw a transition early
		  nextdpllst = DPLLQ1;
		  decrselectquarter = 1'b1;
		end
	      else
		begin
		  nextdpllst = DPLLQ4;
		  decrselectquarter = 1'b0;
		end
	    end
	  DPLLQ4:
	    begin
	      resetselectquarter = 1'b0;	
	      incrselectquarter = 1'b0;
	      decrselectquarter = 1'b0;
	      removelogicreset = 1'b1;
	      if (rcvgood[1] != rcvgood[0])	// transition
		nextdpllst = DPLLQ1;
	      else
		nextdpllst = DPLLQ5;
	    end
	  DPLLQ5:
	    begin
	      // normally we wouldnt see a transition here
	      // if we do, we need to stretch our clock
	      resetselectquarter = 1'b0;	
	      decrselectquarter = 1'b0;
	      removelogicreset = 1'b1;
	      if (rcvgood[1] != rcvgood[0])	// transition
		begin
		  nextdpllst = DPLLQ1;
		  incrselectquarter = 1'b1;
		end
	      else		// no transition, must have been a 1
		begin
		  nextdpllst = DPLLQ2;
		  incrselectquarter = 1'b0;
		end
	    end
	  DPLLSE0:
	    begin
	      resetselectquarter = 1'b0;	
	      incrselectquarter = 1'b0;
	      decrselectquarter = 1'b0;
	      removelogicreset = 1'b1;
	      if (se0selected)
		nextdpllst = DPLLSE0;
	      else
		nextdpllst = DPLLIDLE;
	    end
	endcase
    end

// make the ascii version of the dpll state
// synopsys translate_off
  reg [8*10:1] dpllstate;
  always @(dpllst)
    case (dpllst)
      DPLLIDLE : dpllstate = "IDLE";
      DPLL1ST : dpllstate = "1ST";
      DPLLQ1 : dpllstate = "Q1";
      DPLLQ2 : dpllstate = "Q2";
      DPLLQ3 : dpllstate = "Q3";
      DPLLQ4 : dpllstate = "Q4";
      DPLLQ5 : dpllstate = "Q5";
      DPLLSE0 : dpllstate = "SE0";
    endcase
// synopsys translate_on

endmodule

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -