OpenCores
URL https://opencores.org/ocsvn/ulpi_wrapper/ulpi_wrapper/trunk

Subversion Repositories ulpi_wrapper

[/] [ulpi_wrapper/] [trunk/] [testbench/] [ulpi_driver.cpp] - Rev 3

Compare with Previous | Blame | View Log

#include "ulpi_driver.h"
 
#define CMD_IDLE        0x0
#define CMD_XMIT        0x1
#define CMD_REG_WR      0x2
#define CMD_REG_RD      0x3
 
#define ULPI_CMD_H      7
#define ULPI_CMD_L      6
 
#define ULPI_ADDR_H     5
#define ULPI_ADDR_L     0
 
#define ULPI_PID_H      3
#define ULPI_PID_L      0
 
//-----------------------------------------------------------------
// reg_write
//-----------------------------------------------------------------
void ulpi_driver::reg_write(sc_uint <8> addr, sc_uint <8> data)
{
    m_reg[addr & (ULPI_REG_NUM-1)] = data;
}
//-----------------------------------------------------------------
// reg_read
//-----------------------------------------------------------------
sc_uint <8> ulpi_driver::reg_read(sc_uint <8> addr)
{
    return m_reg[addr & (ULPI_REG_NUM-1)];
}
//-----------------------------------------------------------------
// drive_rxcmd: Drive ULPI RX_CMD
//-----------------------------------------------------------------
void ulpi_driver::drive_rxcmd(sc_uint <2> linestate, bool rx_active, bool rx_error)
{
    sc_uint<8> data = 0;
 
    data.range(ULPI_RXCMD_LS_H, ULPI_RXCMD_LS_L) = linestate;
 
    if (rx_error)
        data.range(ULPI_RXCMD_RXEVENT_H, ULPI_RXCMD_RXEVENT_L) = ULPI_RXEVENT_ERROR;
    else if (rx_active)
        data.range(ULPI_RXCMD_RXEVENT_H, ULPI_RXCMD_RXEVENT_L) = ULPI_RXEVENT_ACTIVE;
    else
        data.range(ULPI_RXCMD_RXEVENT_H, ULPI_RXCMD_RXEVENT_L) = ULPI_RXEVENT_INACTIVE;
 
    // RX_CMD
    ulpi_dir_o.write(true);
    ulpi_nxt_o.write(false);
    ulpi_data_o.write(data);
 
    wait();
}
//-----------------------------------------------------------------
// drive_rxdata: Drive ULPI RX_DATA
//-----------------------------------------------------------------
void ulpi_driver::drive_rxdata(sc_uint <8> data)
{
    // RX_DATA
    ulpi_dir_o.write(true);
    ulpi_nxt_o.write(true);
    ulpi_data_o.write(data);
 
    wait();
}
//-----------------------------------------------------------------
// drive_output: Drive turnaround cycle (-> output)
//-----------------------------------------------------------------
void ulpi_driver::drive_output(bool rx_data)
{
    // Turnaround
    ulpi_dir_o.write(true);
    ulpi_nxt_o.write(rx_data);
    ulpi_data_o.write(0x00);
    wait();
    ulpi_nxt_o.write(false);
}
//-----------------------------------------------------------------
// drive_input: Drive turnaround cycle (-> input)
//-----------------------------------------------------------------
void ulpi_driver::drive_input(void)
{
    // Turnaround
    ulpi_dir_o.write(false);
    ulpi_nxt_o.write(false);
    ulpi_data_o.write(0x00);
 
    wait();
}
//-----------------------------------------------------------------
// drive
//-----------------------------------------------------------------
void ulpi_driver::drive(void) 
{
    drive_input();
 
    // Wait until reset complete
    while (rst_i.read())
        wait();
 
    while (true)
    {
        // PHY -> LINK
        if (m_tx_fifo.num_available())
        {
            sc_uint <9> fifo_data;
            sc_uint <8> data;
            bool        last;
 
            // Turnaround
            drive_output(true);
 
            do
            {
                // RX_CMD
                if (!(rand() % 4))
                {
                    last = false;
 
                    // RX_CMD (RX_ACTIVE = 1)
                    drive_rxcmd(0x2, true, false);
                }
                // RX_DATA
                else
                {
                    last = tx_read(data);
                    drive_rxdata(data);
                }
            }
            while (!last);
 
            // RX_CMD (RX_ACTIVE = 0)
            drive_rxcmd(0x2, false, false);
 
            // Turnaround
            drive_input();
        }
        // LINK -> PHY
        else
        {
            sc_uint <8> data = ulpi_data_i.read();
            sc_uint <2> cmd  = data.range(ULPI_CMD_H,ULPI_CMD_L);
            sc_uint <6> addr = data.range(ULPI_ADDR_H,ULPI_ADDR_L);
            sc_uint <8> pid  = 0;
 
            pid.range(3,0)   = data.range(ULPI_PID_H,ULPI_PID_L);
            pid.range(7,4)   = ~data.range(ULPI_PID_H,ULPI_PID_L);
 
            // Register read
            if (cmd == CMD_REG_RD)
            {
                // Accept command
                ulpi_nxt_o.write(true);
                wait();
 
                // Turnaround
                drive_output(false);
 
                // Data
                data = reg_read(addr);
                ulpi_data_o.write(data);
                wait();
 
                // Turnaround
                drive_input();
            }  
            // Not idle?
            else if (cmd != CMD_IDLE)
            {
                // Accept command
                ulpi_nxt_o.write(true);
                wait();
                ulpi_nxt_o.write(false);              
 
                // Record PID for future use
                bool        last_valid = (cmd == CMD_XMIT);
                sc_uint <8> last_data  = pid;
 
                while (!ulpi_stp_i.read())
                {
                    // Random data accept delay
                    if (!(rand() % 4))
                    {
                        int wait_len = rand() % 8;
 
                        ulpi_nxt_o.write(false);
                        while (!ulpi_stp_i.read() && wait_len--)
                            wait(1);
 
                        if (ulpi_stp_i.read())
                            break;
                    }
 
                    ulpi_nxt_o.write(true);
                    wait();
                    ulpi_nxt_o.write(false);
 
                    if (ulpi_stp_i.read())
                        break;
 
                    sc_uint <8> data = ulpi_data_i.read();
 
                    // Transmit
                    if (cmd == CMD_XMIT)
                    {
                        if (last_valid)
                            rx_write(last_data, false);
 
                        last_valid = true;
                        last_data  = data;
                    }
                    // Register write
                    else if (cmd == CMD_REG_WR)
                    {
                        reg_write(addr, data);
                        addr += 1;
                    }
                }
 
                // Flush pending received byte
                if (last_valid)
                    rx_write(last_data, true);   
            }
 
            wait();
        }
    }
}
//-----------------------------------------------------------------
// write
//-----------------------------------------------------------------
void ulpi_driver::write(sc_uint <8> data, bool last)
{
    sc_uint <9> fifo_data;
 
    fifo_data.range(7,0) = data;
    fifo_data.range(8,8) = last;
 
    m_tx_fifo.write(fifo_data);
}
//-----------------------------------------------------------------
// read
//-----------------------------------------------------------------
bool ulpi_driver::read(sc_uint <8> &data)
{
    sc_uint <9> fifo_data = m_rx_fifo.read();
    data = fifo_data.range(7,0);
    return (bool)fifo_data.range(8,8);
}
//-----------------------------------------------------------------
// rx_write
//-----------------------------------------------------------------
void ulpi_driver::rx_write(sc_uint <8> data, bool last)
{
    sc_uint <9> fifo_data;
 
    fifo_data.range(7,0) = data;
    fifo_data.range(8,8) = last;
 
    m_rx_fifo.write(fifo_data);
}
//-----------------------------------------------------------------
// tx_read
//-----------------------------------------------------------------
bool ulpi_driver::tx_read(sc_uint <8> &data)
{
    sc_uint <9> fifo_data = m_tx_fifo.read();
    data = fifo_data.range(7,0);
    return (bool)fifo_data.range(8,8);
}
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

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