URL
https://opencores.org/ocsvn/ulpi_wrapper/ulpi_wrapper/trunk
Subversion Repositories ulpi_wrapper
Compare Revisions
- This comparison shows the changes necessary to convert path
/ulpi_wrapper/trunk/rtl
- from Rev 3 to Rev 4
- ↔ Reverse comparison
Rev 3 → Rev 4
/ulpi_wrapper.v
1,8 → 1,8
//----------------------------------------------------------------- |
// ULPI (Link) Wrapper |
// V0.1 |
// V1.0 |
// Ultra-Embedded.com |
// Copyright 2015 |
// Copyright 2015-2018 |
// |
// Email: admin@ultra-embedded.com |
// |
42,21 → 42,12
// ULPI Interface (PHY) |
input ulpi_clk60_i, |
input ulpi_rst_i, |
input [7:0] ulpi_data_i, |
output [7:0] ulpi_data_o, |
input [7:0] ulpi_data_out_i, |
output [7:0] ulpi_data_in_o, |
input ulpi_dir_i, |
input ulpi_nxt_i, |
output ulpi_stp_o, |
|
// Register access (Wishbone pipelined access type) |
// NOTE: Tie inputs to 0 if unused |
input [7:0] reg_addr_i, |
input reg_stb_i, |
input reg_we_i, |
input [7:0] reg_data_i, |
output [7:0] reg_data_o, |
output reg_ack_o, |
|
// UTMI Interface (SIE) |
input utmi_txvalid_i, |
output utmi_txready_o, |
63,11 → 54,11
output utmi_rxvalid_o, |
output utmi_rxactive_o, |
output utmi_rxerror_o, |
output [7:0] utmi_data_o, |
input [7:0] utmi_data_i, |
output [7:0] utmi_data_in_o, |
input [7:0] utmi_data_out_i, |
input [1:0] utmi_xcvrselect_i, |
input utmi_termselect_i, |
input [1:0] utmi_opmode_i, |
input [1:0] utmi_op_mode_i, |
input utmi_dppulldown_i, |
input utmi_dmpulldown_i, |
output [1:0] utmi_linestate_o |
101,8 → 92,6
reg termselect_q; |
reg [1:0] opmode_q; |
reg phy_reset_q; |
reg auto_wr_q; |
reg reg_wr_q; |
|
always @ (posedge ulpi_clk60_i or posedge ulpi_rst_i) |
if (ulpi_rst_i) |
117,14 → 106,14
begin |
xcvrselect_q <= utmi_xcvrselect_i; |
termselect_q <= utmi_termselect_i; |
opmode_q <= utmi_opmode_i; |
opmode_q <= utmi_op_mode_i; |
|
if (mode_update_q && (state_q == STATE_CMD) && (ulpi_data_o == REG_FUNC_CTRL)) |
if (mode_update_q && (state_q == STATE_CMD) && (ulpi_data_in_o == REG_FUNC_CTRL)) |
begin |
mode_update_q <= 1'b0; |
phy_reset_q <= 1'b0; |
end |
else if (opmode_q != utmi_opmode_i || |
else if (opmode_q != utmi_op_mode_i || |
termselect_q != utmi_termselect_i || |
xcvrselect_q != utmi_xcvrselect_i) |
mode_update_q <= 1'b1; |
149,7 → 138,7
dppulldown_q <= utmi_dppulldown_i; |
dmpulldown_q <= utmi_dmpulldown_i; |
|
if (otg_update_q && (state_q == STATE_CMD) && (ulpi_data_o == REG_OTG_CTRL)) |
if (otg_update_q && (state_q == STATE_CMD) && (ulpi_data_in_o == REG_OTG_CTRL)) |
otg_update_q <= 1'b0; |
else if (dppulldown_q != utmi_dppulldown_i || |
dmpulldown_q != utmi_dmpulldown_i) |
169,65 → 158,7
|
wire turnaround_w = ulpi_dir_q ^ ulpi_dir_i; |
|
reg ulpi_rxcmd_q; |
always @ (posedge ulpi_clk60_i or posedge ulpi_rst_i) |
if (ulpi_rst_i) |
ulpi_rxcmd_q <= 1'b0; |
// Switch to input with NXT asserted in turnaround cycle |
else if (!ulpi_dir_q && ulpi_dir_i && ulpi_nxt_i) |
ulpi_rxcmd_q <= 1'b1; |
// Switch to output (turnaround cycle) |
else if (ulpi_dir_q && !ulpi_dir_i) |
ulpi_rxcmd_q <= 1'b0; |
|
//----------------------------------------------------------------- |
// Register Access |
//----------------------------------------------------------------- |
reg reg_wr_pending_q; |
reg reg_rd_pending_q; |
reg [7:0] reg_addr_q; |
reg [7:0] reg_data_q; |
reg reg_ack_q; |
|
wire reg_ready_w = (reg_wr_pending_q && state_q == STATE_REG && ulpi_nxt_i && reg_wr_q) || |
(reg_rd_pending_q && !turnaround_w && ulpi_dir_i && !ulpi_rxcmd_q); |
|
always @ (posedge ulpi_clk60_i or posedge ulpi_rst_i) |
if (ulpi_rst_i) |
begin |
reg_wr_pending_q <= 1'b0; |
reg_rd_pending_q <= 1'b0; |
reg_addr_q <= 8'b0; |
end |
else if (reg_stb_i) |
begin |
reg_addr_q <= reg_addr_i; |
reg_wr_pending_q <= reg_we_i; |
reg_rd_pending_q <= ~reg_we_i; |
end |
else if (reg_ready_w) |
begin |
reg_wr_pending_q <= 1'b0; |
reg_rd_pending_q <= 1'b0; |
end |
|
always @ (posedge ulpi_clk60_i or posedge ulpi_rst_i) |
if (ulpi_rst_i) |
reg_data_q <= 8'b0; |
else if (reg_stb_i && reg_we_i) |
reg_data_q <= reg_data_i; |
|
assign reg_data_o = utmi_data_o; |
|
always @ (posedge ulpi_clk60_i or posedge ulpi_rst_i) |
if (ulpi_rst_i) |
reg_ack_q <= 1'b0; |
else |
reg_ack_q <= reg_ready_w; |
|
assign reg_ack_o = reg_ack_q; |
|
//----------------------------------------------------------------- |
// Rx - Tx delay |
//----------------------------------------------------------------- |
localparam TX_DELAY_W = 3; |
271,7 → 202,7
// Push |
if (utmi_txvalid_i && utmi_txready_o) |
begin |
tx_buffer_q[tx_wr_idx_q] <= utmi_data_i; |
tx_buffer_q[tx_wr_idx_q] <= utmi_data_out_i; |
tx_valid_q[tx_wr_idx_q] <= 1'b1; |
|
tx_wr_idx_q <= tx_wr_idx_q + 1'b1; |
311,169 → 242,136
reg [7:0] utmi_data_q; |
|
always @ (posedge ulpi_clk60_i or posedge ulpi_rst_i) |
if (ulpi_rst_i) |
begin |
if (ulpi_rst_i) |
state_q <= STATE_IDLE; |
ulpi_data_q <= 8'b0; |
data_q <= 8'b0; |
ulpi_stp_q <= 1'b1; |
|
utmi_rxvalid_q <= 1'b0; |
utmi_rxerror_q <= 1'b0; |
utmi_rxactive_q <= 1'b0; |
utmi_linestate_q <= 2'b0; |
utmi_data_q <= 8'b0; |
end |
else |
begin |
ulpi_stp_q <= 1'b0; |
utmi_rxvalid_q <= 1'b0; |
|
// Turnaround: Input + NXT - set RX_ACTIVE |
if (turnaround_w && ulpi_dir_i && ulpi_nxt_i) |
begin |
state_q <= STATE_IDLE; |
ulpi_data_q <= 8'b0; |
data_q <= 8'b0; |
ulpi_stp_q <= 1'b0; |
|
utmi_rxvalid_q <= 1'b0; |
utmi_rxerror_q <= 1'b0; |
utmi_rxactive_q <= 1'b0; |
utmi_linestate_q <= 2'b0; |
utmi_data_q <= 8'b0; |
auto_wr_q <= 1'b0; |
reg_wr_q <= 1'b0; |
utmi_rxactive_q <= 1'b1; |
end |
else |
// Turnaround: Input -> Output - reset RX_ACTIVE |
else if (turnaround_w && !ulpi_dir_i) |
begin |
ulpi_stp_q <= 1'b0; |
utmi_rxvalid_q <= 1'b0; |
utmi_rxactive_q <= 1'b0; |
end |
// Non-turnaround cycle |
else if (!turnaround_w) |
begin |
//----------------------------------------------------------------- |
// Input: RX_CMD (status) |
//----------------------------------------------------------------- |
if (ulpi_dir_i && !ulpi_nxt_i) |
begin |
// Phy status |
utmi_linestate_q <= ulpi_data_out_i[1:0]; |
|
if (!turnaround_w) |
case (ulpi_data_out_i[5:4]) |
2'b00: |
begin |
utmi_rxactive_q <= 1'b0; |
utmi_rxerror_q <= 1'b0; |
end |
2'b01: |
begin |
utmi_rxactive_q <= 1'b1; |
utmi_rxerror_q <= 1'b0; |
end |
2'b11: |
begin |
utmi_rxactive_q <= 1'b1; |
utmi_rxerror_q <= 1'b1; |
end |
default: |
; // HOST_DISCONNECTED |
endcase |
end |
//----------------------------------------------------------------- |
// Input: RX_DATA |
//----------------------------------------------------------------- |
else if (ulpi_dir_i && ulpi_nxt_i) |
begin |
//----------------------------------------------------------------- |
// Input: RX_DATA |
//----------------------------------------------------------------- |
if (ulpi_dir_i && ulpi_rxcmd_q) |
utmi_rxvalid_q <= 1'b1; |
utmi_data_q <= ulpi_data_out_i; |
end |
//----------------------------------------------------------------- |
// Output |
//----------------------------------------------------------------- |
else if (!ulpi_dir_i) |
begin |
// IDLE: Pending mode update |
if ((state_q == STATE_IDLE) && mode_update_q) |
begin |
utmi_rxvalid_q <= ulpi_nxt_i; |
utmi_data_q <= ulpi_data_i; |
data_q <= {1'b0, 1'b1, phy_reset_q, opmode_q, termselect_q, xcvrselect_q}; |
ulpi_data_q <= REG_FUNC_CTRL; |
|
// No valid data, extract phy status |
if (!ulpi_nxt_i) |
begin |
utmi_linestate_q <= ulpi_data_i[1:0]; |
state_q <= STATE_CMD; |
end |
// IDLE: Pending OTG control update |
else if ((state_q == STATE_IDLE) && otg_update_q) |
begin |
data_q <= {5'b0, dmpulldown_q, dppulldown_q, 1'b0}; |
ulpi_data_q <= REG_OTG_CTRL; |
|
case (ulpi_data_i[5:4]) |
2'b00: |
begin |
utmi_rxactive_q <= 1'b0; |
utmi_rxerror_q <= 1'b0; |
end |
2'b01: |
begin |
utmi_rxactive_q <= 1'b1; |
utmi_rxerror_q <= 1'b0; |
end |
2'b11: |
begin |
utmi_rxactive_q <= 1'b1; |
utmi_rxerror_q <= 1'b1; |
end |
default: |
; // HOST_DISCONNECTED |
endcase |
end |
// RxValid (so force RxActive) |
else |
utmi_rxactive_q <= 1'b1; |
state_q <= STATE_CMD; |
end |
//----------------------------------------------------------------- |
// Input: REG_DATA |
//----------------------------------------------------------------- |
else if (ulpi_dir_i) |
// IDLE: Pending transmit |
else if ((state_q == STATE_IDLE) && utmi_tx_ready_w) |
begin |
utmi_rxvalid_q <= 1'b0; |
utmi_data_q <= ulpi_data_i; |
ulpi_data_q <= REG_TRANSMIT | {4'b0, utmi_tx_data_w[3:0]}; |
state_q <= STATE_DATA; |
end |
//----------------------------------------------------------------- |
// Output |
//----------------------------------------------------------------- |
else |
begin |
// IDLE: Pending mode update |
if ((state_q == STATE_IDLE) && mode_update_q) |
// Command |
else if ((state_q == STATE_CMD) && ulpi_nxt_i) |
begin |
// Write Register |
state_q <= STATE_REG; |
ulpi_data_q <= data_q; |
end |
// Data (register write) |
else if (state_q == STATE_REG && ulpi_nxt_i) |
begin |
state_q <= STATE_IDLE; |
ulpi_data_q <= 8'b0; // IDLE |
ulpi_stp_q <= 1'b1; |
end |
// Data |
else if (state_q == STATE_DATA && ulpi_nxt_i) |
begin |
// End of packet |
if (!utmi_tx_ready_w) |
begin |
data_q <= {1'b0, 1'b1, phy_reset_q, opmode_q, termselect_q, xcvrselect_q}; |
ulpi_data_q <= REG_FUNC_CTRL; |
|
state_q <= STATE_CMD; |
auto_wr_q <= 1'b1; |
reg_wr_q <= 1'b0; |
end |
// IDLE: Pending OTG control update |
else if ((state_q == STATE_IDLE) && otg_update_q) |
begin |
data_q <= {5'b0, dmpulldown_q, dppulldown_q, 1'b0}; |
ulpi_data_q <= REG_OTG_CTRL; |
|
state_q <= STATE_CMD; |
auto_wr_q <= 1'b1; |
reg_wr_q <= 1'b0; |
end |
// IDLE: Pending register access |
else if ((state_q == STATE_IDLE) && (reg_wr_pending_q || reg_rd_pending_q)) |
begin |
data_q <= reg_data_q; |
|
if (reg_wr_pending_q) |
ulpi_data_q <= REG_WRITE | {2'b0, reg_addr_q[5:0]}; |
else |
ulpi_data_q <= REG_READ | {2'b0, reg_addr_q[5:0]}; |
|
state_q <= STATE_CMD; |
auto_wr_q <= 1'b0; |
reg_wr_q <= reg_wr_pending_q; |
end |
// IDLE: Pending transmit |
else if ((state_q == STATE_IDLE) && utmi_tx_ready_w) |
begin |
ulpi_data_q <= REG_TRANSMIT | {4'b0, utmi_tx_data_w[3:0]}; |
state_q <= STATE_DATA; |
auto_wr_q <= 1'b0; |
reg_wr_q <= 1'b0; |
end |
// Command |
else if ((state_q == STATE_CMD) && ulpi_nxt_i) |
begin |
// Read Register |
if (!reg_wr_q && !auto_wr_q) |
begin |
state_q <= STATE_IDLE; |
ulpi_data_q <= 8'b0; |
end |
// Write Register |
else |
begin |
state_q <= STATE_REG; |
ulpi_data_q <= data_q; |
end |
end |
// Data (register write) |
else if (state_q == STATE_REG && ulpi_nxt_i) |
begin |
state_q <= STATE_IDLE; |
ulpi_data_q <= 8'b0; // IDLE |
ulpi_stp_q <= 1'b1; |
auto_wr_q <= 1'b0; |
reg_wr_q <= 1'b0; |
end |
// Data |
else if (state_q == STATE_DATA && ulpi_nxt_i) |
else |
begin |
// End of packet |
if (!utmi_tx_ready_w) |
begin |
state_q <= STATE_IDLE; |
ulpi_data_q <= 8'b0; // IDLE |
ulpi_stp_q <= 1'b1; |
end |
else |
begin |
state_q <= STATE_DATA; |
ulpi_data_q <= utmi_tx_data_w; |
end |
state_q <= STATE_DATA; |
ulpi_data_q <= utmi_tx_data_w; |
end |
end |
end |
end |
end |
end |
|
// Accept from buffer |
assign utmi_tx_accept_w = ((state_q == STATE_IDLE) && !(mode_update_q || otg_update_q || turnaround_w || reg_wr_pending_q || reg_rd_pending_q) && !ulpi_dir_i) || |
assign utmi_tx_accept_w = ((state_q == STATE_IDLE) && !(mode_update_q || otg_update_q || turnaround_w) && !ulpi_dir_i) || |
(state_q == STATE_DATA && ulpi_nxt_i && !ulpi_dir_i); |
|
//----------------------------------------------------------------- |
480,14 → 378,16
// Assignments |
//----------------------------------------------------------------- |
// ULPI Interface |
assign ulpi_data_o = ulpi_data_q; |
assign ulpi_data_in_o = ulpi_data_q; |
assign ulpi_stp_o = ulpi_stp_q; |
|
// UTMI Interface |
assign utmi_linestate_o = utmi_linestate_q; |
assign utmi_data_o = utmi_data_q; |
assign utmi_data_in_o = utmi_data_q; |
assign utmi_rxerror_o = utmi_rxerror_q; |
assign utmi_rxactive_o = utmi_rxactive_q; |
assign utmi_rxvalid_o = utmi_rxvalid_q; |
|
|
|
endmodule |