OpenCores
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
    from Rev 3 to Rev 4
    Reverse comparison

Rev 3 → Rev 4

/rtl/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
/testbench/wbl_driver.h File deleted \ No newline at end of file
/testbench/tb_top.v
39,27 → 39,21
(
.ulpi_clk60_i(ulpi_clk60_i)
, .ulpi_rst_i(ulpi_rst_i)
, .ulpi_data_i(ulpi_data_i)
, .ulpi_data_o(ulpi_data_o)
, .ulpi_data_out_i(ulpi_data_i)
, .ulpi_data_in_o(ulpi_data_o)
, .ulpi_dir_i(ulpi_dir_i)
, .ulpi_nxt_i(ulpi_nxt_i)
, .ulpi_stp_o(ulpi_stp_o)
, .reg_addr_i(reg_addr_i)
, .reg_stb_i(reg_stb_i)
, .reg_we_i(reg_we_i)
, .reg_data_i(reg_data_i)
, .reg_data_o(reg_data_o)
, .reg_ack_o(reg_ack_o)
, .utmi_txvalid_i(utmi_txvalid_i)
, .utmi_txready_o(utmi_txready_o)
, .utmi_rxvalid_o(utmi_rxvalid_o)
, .utmi_rxactive_o(utmi_rxactive_o)
, .utmi_rxerror_o(utmi_rxerror_o)
, .utmi_data_o(utmi_data_o)
, .utmi_data_i(utmi_data_i)
, .utmi_data_in_o(utmi_data_o)
, .utmi_data_out_i(utmi_data_i)
, .utmi_xcvrselect_i(utmi_xcvrselect_i)
, .utmi_termselect_i(utmi_termselect_i)
, .utmi_opmode_i(utmi_opmode_i)
, .utmi_op_mode_i(utmi_opmode_i)
, .utmi_dppulldown_i(utmi_dppulldown_i)
, .utmi_dmpulldown_i(utmi_dmpulldown_i)
, .utmi_linestate_o(utmi_linestate_o)
/testbench/ulpi_wrapper_tb.cpp
45,8 → 45,6
ulpi_rst_i.write(false);
wait(1);
 
m_reg.write(ULPI_REG_SCRATCH, last_wr);
 
int cycles = 0;
while (true)
{
55,18 → 53,6
if (wait_len)
wait(wait_len);
 
// Random register write
if (rand() & 1)
{
last_wr = rand();
m_reg.write(ULPI_REG_SCRATCH, last_wr);
}
// Random register read
else
{
sc_assert(m_reg.read(ULPI_REG_SCRATCH) == last_wr);
}
 
if (!(rand() % 32))
{
if (rand() & 1)
/testbench/ulpi_wrapper_tb.h
6,7 → 6,6
 
#include "ulpi_driver.h"
#include "utmi_driver.h"
#include "wbl_driver.h"
 
class ulpi_wrapper_tb: public sc_module
{
19,12 → 18,6
sc_signal< bool > ulpi_dir_i;
sc_signal< bool > ulpi_nxt_i;
sc_signal< bool > ulpi_stp_o;
sc_signal< sc_uint<8> > reg_addr_i;
sc_signal< bool > reg_stb_i;
sc_signal< bool > reg_we_i;
sc_signal< sc_uint<8> > reg_data_i;
sc_signal< sc_uint<8> > reg_data_o;
sc_signal< bool > reg_ack_o;
sc_signal< bool > utmi_txvalid_i;
sc_signal< bool > utmi_txready_o;
sc_signal< bool > utmi_rxvalid_o;
42,7 → 35,7
ulpi_wrapper_tb(sc_module_name name): sc_module(name),
m_dut("tb_top"),
m_vpi_clk("tb_top.ulpi_clk60_i"),
m_ulpi("m_ulpi"), m_utmi("m_utmi"), m_reg("m_reg"),
m_ulpi("m_ulpi"), m_utmi("m_utmi"),
m_phy_link_queue(2048), m_link_phy_queue(2048)
{
m_dut.ulpi_clk60_i(m_vpi_clk.m_clk);
52,12 → 45,6
m_dut.ulpi_dir_i(ulpi_dir_i);
m_dut.ulpi_nxt_i(ulpi_nxt_i);
m_dut.ulpi_stp_o(ulpi_stp_o);
m_dut.reg_addr_i(reg_addr_i);
m_dut.reg_stb_i(reg_stb_i);
m_dut.reg_we_i(reg_we_i);
m_dut.reg_data_i(reg_data_i);
m_dut.reg_data_o(reg_data_o);
m_dut.reg_ack_o(reg_ack_o);
m_dut.utmi_txvalid_i(utmi_txvalid_i);
m_dut.utmi_txready_o(utmi_txready_o);
m_dut.utmi_rxvalid_o(utmi_rxvalid_o);
92,13 → 79,6
m_utmi.utmi_rxvalid_i(utmi_rxvalid_o);
m_utmi.utmi_rxactive_i(utmi_rxactive_o);
 
m_reg.addr_o(reg_addr_i);
m_reg.data_o(reg_data_i);
m_reg.data_i(reg_data_o);
m_reg.we_o(reg_we_i);
m_reg.stb_o(reg_stb_i);
m_reg.ack_i(reg_ack_o);
 
SC_CTHREAD(testbench, m_vpi_clk.m_clk);
SC_CTHREAD(phy_tx, m_vpi_clk.m_clk);
SC_CTHREAD(phy_rx, m_vpi_clk.m_clk);
112,7 → 92,6
 
ulpi_driver m_ulpi;
utmi_driver m_utmi;
wbl_driver m_reg;
 
sc_fifo < sc_uint <9> > m_phy_link_queue;
sc_fifo < sc_uint <9> > m_link_phy_queue;
/testbench/ulpi_wrapper_vpi.h
13,12 → 13,6
sc_in <bool> ulpi_dir_i;
sc_in <bool> ulpi_nxt_i;
sc_out <bool> ulpi_stp_o;
sc_in <sc_uint<8> > reg_addr_i;
sc_in <bool> reg_stb_i;
sc_in <bool> reg_we_i;
sc_in <sc_uint<8> > reg_data_i;
sc_out <sc_uint<8> > reg_data_o;
sc_out <bool> reg_ack_o;
sc_in <bool> utmi_txvalid_i;
sc_out <bool> utmi_txready_o;
sc_out <bool> utmi_rxvalid_o;
37,8 → 31,6
{
sc_vpi_module_read_output_int(ulpi_data_o, "ulpi_data_o");
sc_vpi_module_read_output_int(ulpi_stp_o, "ulpi_stp_o");
sc_vpi_module_read_output_int(reg_data_o, "reg_data_o");
sc_vpi_module_read_output_int(reg_ack_o, "reg_ack_o");
sc_vpi_module_read_output_int(utmi_txready_o, "utmi_txready_o");
sc_vpi_module_read_output_int(utmi_rxvalid_o, "utmi_rxvalid_o");
sc_vpi_module_read_output_int(utmi_rxactive_o, "utmi_rxactive_o");
54,10 → 46,6
sc_vpi_module_write_input_int(ulpi_data_i, "ulpi_data_i");
sc_vpi_module_write_input_int(ulpi_dir_i, "ulpi_dir_i");
sc_vpi_module_write_input_int(ulpi_nxt_i, "ulpi_nxt_i");
sc_vpi_module_write_input_int(reg_addr_i, "reg_addr_i");
sc_vpi_module_write_input_int(reg_stb_i, "reg_stb_i");
sc_vpi_module_write_input_int(reg_we_i, "reg_we_i");
sc_vpi_module_write_input_int(reg_data_i, "reg_data_i");
sc_vpi_module_write_input_int(utmi_txvalid_i, "utmi_txvalid_i");
sc_vpi_module_write_input_int(utmi_data_i, "utmi_data_i");
sc_vpi_module_write_input_int(utmi_xcvrselect_i, "utmi_xcvrselect_i");
76,12 → 64,6
, ulpi_dir_i ("ulpi_dir_i")
, ulpi_nxt_i ("ulpi_nxt_i")
, ulpi_stp_o ("ulpi_stp_o")
, reg_addr_i ("reg_addr_i")
, reg_stb_i ("reg_stb_i")
, reg_we_i ("reg_we_i")
, reg_data_i ("reg_data_i")
, reg_data_o ("reg_data_o")
, reg_ack_o ("reg_ack_o")
, utmi_txvalid_i ("utmi_txvalid_i")
, utmi_txready_o ("utmi_txready_o")
, utmi_rxvalid_o ("utmi_rxvalid_o")
103,12 → 85,6
register_signal("ulpi_dir_i");
register_signal("ulpi_nxt_i");
register_signal("ulpi_stp_o");
register_signal("reg_addr_i");
register_signal("reg_stb_i");
register_signal("reg_we_i");
register_signal("reg_data_i");
register_signal("reg_data_o");
register_signal("reg_ack_o");
register_signal("utmi_txvalid_i");
register_signal("utmi_txready_o");
register_signal("utmi_rxvalid_o");

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.