www.pudn.com > noc.rar > netif_b.cpp


/*
 *  TU Eindhoven
 *  Eindhoven, The Netherlands
 *
 *  Name            :   netif.cpp
 *
 *  Author          :   A.S.Slusarczyk@tue.nl
 *
 *  Date            :   15-09-2003
 *
 *  Function        :   Generic network interface module for the network of Ecube routers
 *                      with arbitrary length packets
 *
 */

#include "netif_b.h"

// buffering packet data to send
void NETWORK_INTERFACE::buffer_out_process()
{
  if( rst.read() )
    buffer_out.write(0);
  else if( write_data.read() )
    buffer_out.write(reg_data_in);
    
}

// buffering destination address for the packet
void NETWORK_INTERFACE::buffer_addr_process()
{
  sc_bv<2*ADDRESS_LEN> addr = reg_data_in.read().range(2*ADDRESS_LEN-1,0);
    
  if( rst.read() )
    buffer_addr.write(0);
  else if( write_addr.read() )
    buffer_addr.write(addr);
}

void NETWORK_INTERFACE::register_packet_end()
{
  if( rst.read() )
    packet_end_reg.write(0);
  else if( wr_packet_end.read() )
    packet_end_reg.write(packet_end.read());
    
}

// FSM sending a packet
void NETWORK_INTERFACE::send_logic()
{
  bool req_out_v, send_rdy_v, wr_packet_end_v;
  sc_bv data_out_v;
  sc_bv flit_type_v = 0;
  sc_bv addrx = buffer_addr.read().range(2*ADDRESS_LEN-1,ADDRESS_LEN), 
    addry = buffer_addr.read().range(ADDRESS_LEN-1,0);
  sc_bv<16> flit_data_v = 0;
    
  next_send_flit = send_flit.read();
  send_next_state = SEND_IDLE;
  req_out_v = false;
  send_rdy_v = false;
  wr_packet_end_v = false;
  
  switch( send_current_state.read() ){
  case SEND_IDLE:
    // idle - wait for send signal from processor
    if( send.read() ){
      // send header flit
      send_next_state = SEND;
      next_send_flit = HEADER;
      wr_packet_end_v = true; // check if the last-packet-word marker is set
    }
    else {
      send_next_state = SEND_IDLE;
      next_send_flit = NONE;
      send_rdy_v = true;
    }
    break;
    
  case SEND:
    // sending - assert network request, output flit
    req_out_v = true;
    switch( send_flit.read() ){
    case HEADER:
      flit_type_v = 0x1;
      flit_data_v = (addrx,addry);
      break;
    case DATA:
      flit_type_v = 0x0;
      flit_data_v = buffer_out.read().range(31,16);
      break;
    case TAIL:
      // if its the last packet word, mark flit as trailer
      flit_type_v = (packet_end_reg.read() ? 0x2 : 0x0);
      flit_data_v = buffer_out.read().range(15,0);
      break;
    }
    if( ack_in.read() ){
      // flit acknowledged - can send next one
      // withdraw request, wait for ack to disappear
#ifdef NETPRINT
      cout << name() << " sent flit t=" << flit_type_v << " data=" << hex << flit_data_v.to_uint() << dec << " @ " << sc_time_stamp() << endl;
#endif
      send_next_state = WAIT_ACK_OFF;
    }
    else
      send_next_state = SEND;
    break;
      
  case WAIT_ACK_OFF:
    // wait for ack to disappear
    if( ! ack_in.read() )
      {
        // send next flit of the word, or check if next word is there
        switch( send_flit.read() ){
        case HEADER:
          send_next_state = SEND;
          next_send_flit = DATA;
          break;
        case DATA:
          send_next_state = SEND;
          next_send_flit = TAIL;
          break;
        case TAIL:
          send_next_state = WAIT_SEND_OFF;
          next_send_flit = NONE;
          send_rdy_v = true;
          break;
        }
      }
    else
      send_next_state = WAIT_ACK_OFF;
      
    break;
   
  case WAIT_SEND_OFF:
    // assert send_ready, wait for send to be withdrawn
    send_rdy_v = true;
    if( !send.read() )
      if( packet_end_reg.read() ) 
        // if it was last word of the packet - goto idle
        send_next_state = SEND_IDLE;
      else 
        // otherwise - wait for processor to supply next packet word
        send_next_state = NEXT_WORD;
    else 
      send_next_state = WAIT_SEND_OFF;
    break;   

  case NEXT_WORD:
    // wait for processor to supply next word of the packet
    next_send_flit = DATA;
    if( send.read() ){
      // send next word
      send_next_state = SEND;
      wr_packet_end_v = true;
    }
    else {
      send_next_state = NEXT_WORD;
      send_rdy_v = true;
    }
    break;
  }
  
  wr_packet_end.write(wr_packet_end_v);
  req_out.write(req_out_v);
  send_rdy.write(send_rdy_v);
  data_out.write( (flit_type_v, flit_data_v) );
}

// state update of the sending FSM
void NETWORK_INTERFACE::send_change_state()
{
  if( rst.read() ){
    send_current_state = SEND_IDLE;
    send_flit = NONE;
  }
  else{
    send_current_state = send_next_state;
    send_flit = next_send_flit;
  }
}


// FSM receiving packets
void NETWORK_INTERFACE::rcv_logic()
{
  bool ack_out_v, data_rdy_v, rcv_packet_end_v;
  sc_uint<2> flit_type = sc_bv<2>(data_in.read().range(17,16));
  
  rcv_next_state = RCV_IDLE;
  next_rcv_flit = rcv_flit.read();

  buffer_in_n =  buffer_in.read();
  ack_out_v = false;
  data_rdy_v = false;
  rcv_packet_end_v = false;
  
  switch( rcv_current_state.read() )
    {
    case RCV_IDLE:
      // idle - wait for request from network
      
      if( req_in.read() ){

#ifdef NETPRINT
        cout << name() << " rcv flit " << hex << data_in.read().to_uint() << dec << " @ " << sc_time_stamp() << endl;
#endif
        // discard flit if it's header, store in buffer if it's data
        rcv_next_state = ACK;
        switch(rcv_flit.read()){
        case NONE:
          buffer_in_n = 0;
          next_rcv_flit = HEADER;
          break;
        case HEADER: 
          buffer_in_n = 0;
          break;
        case DATA: 
          buffer_in_n = (data_in.read().range(15,0), buffer_in.read().range(15,0)); 
          break;
        case TAIL: 
          buffer_in_n = (buffer_in.read().range(31,16), data_in.read().range(15,0)); 
          break;
        }
      }
      else
        rcv_next_state = RCV_IDLE;
      break;
      
    case ACK:
      // acknowledge flit and wait until request is withdrawn
      ack_out_v = true;
      if( ! req_in.read() ){
        // flit transmission finished
        
        switch(rcv_flit.read()){
        case HEADER: 
          // got header, wait for data
          rcv_next_state = RCV_IDLE;
          next_rcv_flit = DATA; 
          break;
        case DATA: 
          // got data high, get data low
          rcv_next_state = RCV_IDLE;
          next_rcv_flit = TAIL; 
          break;
        case TAIL: 
          // got data low - check if it's tail flit or another data follows
          // and wait for the processor to read the received data
          rcv_next_state = WAIT_READ;
          if( flit_type == 2 ) next_rcv_flit = NONE;
          else next_rcv_flit = DATA;
#ifdef NETPRINT
          cout << name() << " received data " << hex << buffer_in.read().to_uint() << dec << " @ " << sc_time_stamp() << endl;
#endif          
          break;
        }
          
      }
      else
        rcv_next_state = ACK;
        
      break;

    case WAIT_READ:
      // assert data ready and wait for processor to read the data
      data_rdy_v = true;
      // if the next expected flit is header - it's the last word of packet
      rcv_packet_end_v = (rcv_flit.read() == NONE);
      
      if( read.read() ){
#ifdef NETPRINT
        cout << name() << " data read " << hex << buffer_in.read().to_uint() << dec << " @ " << sc_time_stamp() << endl;
#endif          
        rcv_next_state = RCV_IDLE;
      }
      else
        rcv_next_state = WAIT_READ;
      break;
    }
    
  ack_out.write(ack_out_v);
  data_rdy.write(data_rdy_v);
  rcv_packet_end.write(rcv_packet_end_v);
}

// state update of the receiving FSM
void NETWORK_INTERFACE::rcv_change_state()
{
  if( rst.read() ){
    rcv_current_state = RCV_IDLE;
    rcv_flit = NONE;
    buffer_in.write(0);
  }
  else{
    rcv_current_state = rcv_next_state;
    rcv_flit = next_rcv_flit;
    buffer_in.write(buffer_in_n);
  }
}