📄 usiedpll.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 + -