// Copyright (C) 2006 Free Software Initiative of Japan (FSIJ)
//
// Author: NIIBE Yutaka
//
module usb_rx_sof(clk,
rx_dp_in,
rx_dn_in,
sof_blink, ack, err, syn);
input clk;
input rx_dp_in;
input rx_dn_in;
output ack;
output reg err;
output sof_blink;
reg [9:0] sof_count;
wire rx_clk, k, j, se0, rx_active, syn_err, sof;
output syn;
rx_phy rx_phy(clk, rx_dp_in, rx_dn_in, rx_clk, k, j, se0);
syn_detect syn_detect(rx_clk, k, j, se0, rx_active, syn_err, syn);
sof_ack_detect sof_ack_detect(rx_clk, j, rx_active, sof, ack);
always @ (posedge clk)
if (sof_count == 10'b0)
err <= 1'b0;
else if (syn_err)
err <= 1'b1;
always @ (negedge sof)
if (sof_count >= 999)
sof_count <= 0;
else
sof_count <= sof_count + 1;
assign sof_blink = sof_count[9];
endmodule
//
// ~~~~____~~~~____~~~~____~~~~__ rx_dp_in
//
// ~~~~~____~~~~____~~~~____~~~~_ rx_dp_1
//
//
// ~~~~~~____~~~~____~~~~____~~~~ rx_dp
//
// _____~___~___~___~___~___~___~ rx_edge
//
// 3012301230123012301230123
// 0012301230123012301230123
// 1301201230123012301230123
// 2012301230123012301230123
//
// _______~___~___~___~___~___~___~___ rx_clk
//
module rx_phy(clk, rx_dp_in, rx_dn_in, rx_clk, k, j, se0);
input clk, rx_dp_in, rx_dn_in;
output rx_clk, k, j, se0;
reg [1:0] state;
reg rx_dp_1, rx_dn_1;
reg rx_dp, rx_dn;
always @(posedge clk) rx_dp_1 <= rx_dp_in;
always @(posedge clk) rx_dp <= rx_dp_1;
always @(posedge clk) rx_dn_1 <= rx_dn_in;
always @(posedge clk) rx_dn <= rx_dn_1;
wire rx_edge;
assign rx_edge = (rx_dp_1 != rx_dp);
assign rx_clk = (state == 2'h1);
assign k = !rx_dp & rx_dn;
assign j = rx_dp & !rx_dn;
assign se0 = !rx_dp & !rx_dn;
always @(posedge clk)
if (rx_edge)
case (state)
2'h0: state <= 2'h0;
2'h1: state <= 2'h3;
2'h2: state <= 2'h0;
2'h3: state <= 2'h0;
endcase
else
case (state)
2'h0: state <= 2'h1;
2'h1: state <= 2'h2;
2'h2: state <= 2'h3;
2'h3: state <= 2'h0;
endcase
endmodule
module syn_detect(rx_clk, k, j, se0, rx_active, syn_err, syn);
input rx_clk, k, j, se0;
output reg rx_active, syn_err;
reg [2:0] syn_state;
reg syn;
output syn;
reg dup;
parameter IDLE = 3'h0,
K1 = 3'h1,
J1 = 3'h2,
K2 = 3'h3,
J2 = 3'h4,
K3 = 3'h5,
J3 = 3'h6,
K4 = 3'h7;
always @(posedge rx_clk)
if (syn|syn_err) rx_active <= 1'b1;
else if (se0) rx_active <= 1'b0;
always @(negedge rx_clk)
begin
syn <= 1'b0;
syn_err <= 1'b0;
syn_state <= IDLE;
if (!rx_active)
case (syn_state)
IDLE:
begin
dup <= 1'b0;
if (k) syn_state <= K1;
end
K1:
if (j) syn_state <= J1;
else if (k && !dup) begin dup <= 1'b1; syn_state <= K1; end
else syn_err <= 1'b1;
J1:
if (k) syn_state <= K2;
else if (j && !dup) begin dup <= 1'b1; syn_state <= J1; end
else syn_err <= 1'b1;
K2:
if (j) syn_state <= J2;
else if (k && !dup) begin dup <= 1'b1; syn_state <= K2; end
else syn_err <= 1'b1;
J2:
if (k) syn_state <= K3;
else syn_err <= 1'b1;
K3:
if (j) syn_state <= J3;
else syn_err <= 1'b1;
J3:
if (k) syn_state <= K4;
else syn_err <= 1'b1;
K4:
if (k) syn <= 1'b1;
else syn_err <= 1'b1;
endcase
end
endmodule
module sof_ack_detect(rx_clk, rx, rx_active, sof, ack);
input rx_clk, rx, rx_active;
output reg sof, ack;
reg rx_r;
wire nrzi;
wire drop_bit;
reg [7:0] pid;
reg [2:0] one_cnt;
reg [2:0] byte_clk;
reg stop;
always @(negedge rx_clk)
rx_r <= rx;
assign drop_bit = (one_cnt == 3'h6);
assign nrzi = (rx_r == rx);
always @(negedge rx_clk)
if (nrzi && !drop_bit) one_cnt <= one_cnt + 3'h1;
else one_cnt <= 3'h0;
always @(negedge rx_clk)
if (!rx_active) begin
byte_clk <= 3'h0;
sof <= 1'b0;
stop <= 1'b0;
end
else if (!stop && !drop_bit) begin
pid = {nrzi, pid[7:1]};
byte_clk = byte_clk + 3'h1;
if (byte_clk == 3'h0) begin
stop <= 1'b1;
case (pid)
8'ha5:
sof <= 1'b1;
8'hd2:
ack <= !ack;
endcase
end
end
endmodule