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

Subversion Repositories funbase_ip_library

[/] [funbase_ip_library/] [trunk/] [TUT/] [ip.hwp.communication/] [hibi/] [3.0/] [tb/] [sad_tb/] [agent.hh] - Rev 145

Compare with Previous | Blame | View Log

/*
 * Author: Lasse Lehtonen
 *
 * Agent for hibi. Sends packets when told to and checks that correct
 * packets are received. Wrapper types r3 and r4 have different interfaces and 
 * infndefs are needed every now and then.
 *
 * $Id: agent.hh 2008 2011-10-06 13:49:53Z ege $
 *
 */


#ifndef SAD_HIBI_AGENT_HH
#define SAD_HIBI_AGENT_HH

#include "constants.hh"
#include "packet.hh"

#include <queue>
#include <map>
#include <iostream>
#include <iomanip>
#include <sstream>
#include <cstdlib>
using namespace std;

#include <systemc>
using namespace sc_core;
using namespace sc_dt;


template<int addr_width_g, 
         int data_width_g, 
         int comm_width_g,
         int separate_addr_g>
class Agent : public sc_module
{
public:
   sc_in_clk                    clk;
   sc_in<bool>                  rst_n;

   sc_out<sc_bv<comm_width_g> > comm_out;
   sc_out<sc_bv<data_width_g> > data_out;
#ifndef USE_R3_WRAPPERS
   sc_out<bool>                 av_out;
#else
   sc_out<sc_bv<addr_width_g> > addr_out;
#endif
   sc_out<bool>                 we_out;
   sc_out<bool>                 re_out;
   sc_in<sc_bv<comm_width_g> >  comm_in;
   sc_in<sc_bv<data_width_g> >  data_in;
#ifndef USE_R3_WRAPPERS
   sc_in<bool>                  av_in;
#else
   sc_out<sc_bv<addr_width_g> > addr_in;
#endif
   sc_in<bool>                  full_in;
   sc_in<bool>                  one_p_in;
   sc_in<bool>                  empty_in;
   sc_in<bool>                  one_d_in;

#ifdef USE_R3_WRAPPERS
   sc_out<sc_bv<comm_width_g> > msg_comm_out;
   sc_out<sc_bv<data_width_g> > msg_data_out;
   sc_out<sc_bv<addr_width_g> > msg_addr_out;
   sc_out<bool>                 msg_we_out;
   sc_out<bool>                 msg_re_out;
   sc_in<sc_bv<comm_width_g> >  msg_comm_in;
   sc_in<sc_bv<data_width_g> >  msg_data_in;
   sc_in<sc_bv<addr_width_g> >  msg_addr_in;
   sc_in<bool>                  msg_full_in;
   sc_in<bool>                  msg_one_p_in;
   sc_in<bool>                  msg_empty_in;
   sc_in<bool>                  msg_one_d_in;
#endif

   SC_HAS_PROCESS(Agent);


   //* Constructor 
   // Initalize ports to 0 and 
   // tx and rx threads
   Agent(sc_module_name name, unsigned int id, 
         vector<Agent<addr_width_c, data_width_c, 
                      comm_width_c, separate_addr_c>* >& agents)
      : sc_module(name),
        clk("clk"),
        rst_n("rst_n"),
        comm_out("comm_out"),
        data_out("data_out"),
#ifndef USE_R3_WRAPPERS
        av_out("av_out"),
#else
        addr_out("addr_out"),
#endif
        we_out("we_out"),
        re_out("re_out"),
        comm_in("comm_in"),
        data_in("data_in"),
#ifndef USE_R3_WRAPPERS
        av_in("av_in"),
#else
        addr_in("addr_in"),
#endif
        full_in("full_in"),
        one_p_in("one_p_in"),
        empty_in("empty_in"),
        one_d_in("one_d_in"),
#ifdef USE_R3_WRAPPERS
        msg_comm_out("msg_comm_out"),
        msg_data_out("msg_data_out"),
        msg_addr_out("msg_addr_out"),
        msg_we_out("msg_we_out"),
        msg_re_out("msg_re_out"),
        msg_comm_in("msg_comm_in"),
        msg_data_in("msg_data_in"),
        msg_addr_in("msg_addr_in"),
        msg_full_in("msg_full_in"),
        msg_one_p_in("msg_one_p_in"),
        msg_empty_in("msg_empty_in"),
        msg_one_d_in("msg_one_d_in"),
#endif
        _id(id),
        _rxBusyChance(0),
        _txBusyChance(0),
        _agents(agents),
        _locked(false)
   {
      comm_out.initialize(0);
      data_out.initialize(0);
#ifndef USE_R3_WRAPPERS
      av_out.initialize(false);
#else
      addr_out.initialize(0);
#endif
      we_out.initialize(false);
      re_out.initialize(false);
#ifdef USE_R3_WRAPPERS
      msg_comm_out.initialize(0);
      msg_data_out.initialize(0);
      msg_addr_out.initialize(0);
      msg_we_out.initialize(false);
      msg_re_out.initialize(false);
#endif



      // Launch threads for tx and rx
      SC_THREAD(sender);
      SC_THREAD(receiver);

#ifdef USE_R3_WRAPPERS
      // Launch threads for message tx and rx
      SC_THREAD(msg_sender);
      SC_THREAD(msg_receiver);
#endif

   }


   //* Destructor
   ~Agent() 
   {
      freePackets();      
   }
   

   //* Adds packet for this agent to send
   void send(Packet* packet)
   {
#ifdef USE_R3_WRAPPERS
      if(packet->getHibiCommand() == DATA_WR ||
         packet->getHibiCommand() == DATA_RD ||
         packet->getHibiCommand() == DATA_RDL ||
         packet->getHibiCommand() == DATA_WRNP ||
         packet->getHibiCommand() == DATA_WRC)
      {
         _packetsOut.push(packet);
      }
      else
      {
         _msgPacketsOut.push(packet);
      }
#else
      _packetsOut.push(packet);
#endif

      /*
      cout << "At " << setprecision(10) << sc_time_stamp().to_double() << " : "
           << "Agent " << setfill(' ') << setw(3) << dec << _id << " queued   " 
           << commmand2str(packet->getHibiCommand())
           << " packet: " 
           << setw(5) << setfill(' ') << packet->getId() << " to   ";
      if(packet->getHibiCommand() == CFG_WR ||
         packet->getHibiCommand() == CFG_RD)
      {
         cout << "id: " << packet->getDstId() << endl;
      }
      else
      {
         cout << "address: 0x" 
              << hex << setw(8) << setfill('0')
              << packet->getDstAddress().to_uint()
              << endl; 
      }

      */

   }

   //* Tells agent to expect this packet
   void expect(Packet* packet)
   {
      //_packetsIn[packet->getId()] = packet;
      _packetsIn.insert(pair<sc_uint<16>, Packet*>(packet->getId(), packet));
   }

   //* Tells agent to expect this packet, custom id
   void expect(Packet* packet, unsigned int id)
   {
      //_packetsIn[id] = packet;
      _packetsIn.insert(pair<sc_uint<16>, Packet*>(id, packet));
   }


   //* True if all packets have been received
   bool allDone() const
   { 
      return _packetsIn.empty(); 
   }

   //* Print unfinished packet ids
   void printExpected()
   {
      for(map<sc_uint<16>, Packet*>::iterator iter = _packetsIn.begin();
          iter != _packetsIn.end(); ++iter)
      {
         cout << " +- packet " 
              << dec << setw(5) << setfill(' ') << (*iter).second->getId() 
              << " missing " 
              << (*iter).second->getSize() - (*iter).second->getReceived()
              << " words"
              << endl;
      }
   }

   //* Sets RX change to be busy on any clock cycle (0-100)
   void setRxBusyChance(unsigned int chance)
   { _rxBusyChance = chance; }

   //* Sets TX change to be busy on any clock cycle (0-100)
   void setTxBusyChance(unsigned int chance)
   { _txBusyChance = chance; }


private:


   //* Frees all memory elements
   void freePackets()
   {
      while(!_packetsOut.empty())
      {
         // Only pointers on RX side will be deleted as they point
         // to the same object
         _packetsOut.pop();
      }

#ifdef USE_R3_WRAPPERS
      while(!_msgPacketsOut.empty())
      {
         // Only pointers on RX side will be deleted as they point
         // to the same object
         _msgPacketsOut.pop();
      }
#endif

      for(map<sc_uint<16>, Packet*>::iterator iter = _packetsIn.begin();
          iter != _packetsIn.end(); ++iter )
      {
         delete (*iter).second;
      }
   }


   //* TX thread, handles pushing packets to hibi
   void sender()
   {
      while(true)
      {
         // Sync to pos edge
         wait(clk.posedge_event());
         
         // Handle reset
         if(rst_n.read() == false)
         {
            comm_out.write(0);
            data_out.write(0);
#ifndef USE_R3_WRAPPERS
            av_out.write(false);
#else
            addr_out.write(0);
#endif
            we_out.write(false);
            freePackets(); // Deletes all packets
            continue; 
         }



         // No packets to send
         if(_packetsOut.empty()) continue; 



         // There is data to send in the FIFO
         Packet* packet = _packetsOut.front();
         _packetsOut.pop();
         
#ifndef USE_R3_WRAPPERS
         // Put address before data flits in normal mode
         if(separate_addr_g == 0)
         {
            // Wait if NI is full
            while(full_in.read() == true) wait(clk.posedge_event());

            we_out.write(true);
            av_out.write(true);
            comm_out.write(packet->getCommand());
            data_out.write(packet->getDstAddress());

            wait(clk.posedge_event());
         }
#endif



         // Send all flits
         for(unsigned int i = 0; i < packet->getSize();)
         {
            // Occasionally, play dead and not send anything
            // This doesn't work, need second cycle wait, stupido we_out!
            // if((unsigned(rand()) % 100) < _txBusyChance) 
            // {
            //    we_out.write(false);
            //    wait(clk.posedge_event());           
            //    continue; 
            // }

            // Wait if NI is full
            while(full_in.read() == true) 
            {          
               //we_out.write(true);
               wait(clk.posedge_event());
            }       

            we_out.write(true);
            
#ifndef USE_R3_WRAPPERS
            if(separate_addr_g == 0)
            {
               av_out.write(false);
               comm_out.write(packet->getCommand());
               data_out.write(packet->getData());
            }
            else
            {
               // AV is high for the whole packet in SAD mode
               av_out.write(true);
               // Substitute address to MSBs of data_out
               data_out.write((packet->getDstAddress(), 
                               packet->getData().
                               range(data_width_c-addr_width_c-1, 0)));
               comm_out.write(packet->getCommand());
            }
#else
            comm_out.write(packet->getCommand());
            data_out.write(packet->getData());
            addr_out.write(packet->getDstAddress());
#endif      

            wait(clk.posedge_event());
            ++i;
         }



         // Wait if NI is full when last flit is being sent
         while(full_in.read() == true) 
         {             
            wait(clk.posedge_event());
         }
         
         cout << "At " << setprecision(10) << sc_time_stamp().to_double() 
              << " : "
              << "Agent " << setfill(' ') << setw(3) << dec << _id 
              << " sent     " 
              << commmand2str(packet->getHibiCommand())
              << " packet: " 
              << setw(5) << setfill(' ') <<  packet->getId() << " to   ";
         if(packet->getHibiCommand() == CFG_WR ||
            packet->getHibiCommand() == CFG_RD)
         {
            cout << "id: " << packet->getDstId() << endl;
         }
         else
         {
            cout << "address: 0x" 
                 << hex << setw(8) << setfill('0')
                 << packet->getDstAddress().to_uint()
                 << endl; 
         }

         we_out.write(false);
#ifndef USE_R3_WRAPPERS
         av_out.write(false);
#else
         addr_out.write(0);
#endif
         comm_out.write(commands_c[IDLE]);
         data_out.write(0);
         packet = 0;
      }
   }


   //* RX thread, handles receiving packets from hibitys
   void receiver()
   {
      sc_uint<16> packetId;
      bool reading = false;
      
      while(true)
      {
         // Sync to pos edge and handle reset
         wait(clk.posedge_event());
         re_out.write(false); // Default
         if(rst_n.read() == false) 
         {
            continue;
         }

         if(reading)
         {
            reading = false;
            
            if(empty_in.read() == true)
            {
               // There's nothing to read
            }
#ifndef USE_R3_WRAPPERS
            else if(separate_addr_g == 0 && av_in.read() == true) 
            {       
               // Skip the address flit if in normal mode
            }
#endif
            else
            {
               // Check that we're expecting a packet with this ID
               packetId = (data_in.read().range(15, 0).to_uint());
               if(_packetsIn.find(packetId) == _packetsIn.end())
               {
                  ostringstream oss;
                  oss << "At " << setprecision(10) 
                      << sc_time_stamp().to_double()
                      << " : " << "Agent " << setfill(' ') << setw(3) << _id 
                      << " received unexpected flit with id: " << packetId;
                  SC_REPORT_WARNING("warning", oss.str().c_str());
                  re_out.write(true);
                  continue;
               }

               HibiCommand cmd = (*_packetsIn.find(packetId)).second->
                     getHibiCommand();

               // Check that we are not getting normal stuff while locked!
               if(_locked &&
                  cmd != EXCL_WR &&
                  cmd != EXCL_RD &&
                  cmd != EXCL_RELEASE)
               {
                  ostringstream oss;
                  oss << "At " << setprecision(10) 
                      << sc_time_stamp().to_double()
                      << " : " << "Agent " << setfill(' ') << setw(3) << _id 
                      << " received non-exclusive packet while locked, id: " 
                      << packetId;
                  SC_REPORT_WARNING("warning", oss.str().c_str());
               }


               // Lock this agent when getting lock command
               if(cmd == EXCL_LOCK && !_locked)
               { _locked = true; }

               // Release the lock
               if(cmd == EXCL_RELEASE && _locked)
               { _locked = false; }

               //_packetsIn[packetId]->receiveWord();
               (*_packetsIn.find(packetId)).second->receiveWord();
         
               //if(_packetsIn[packetId]->complete())
               if((*_packetsIn.find(packetId)).second->complete())
               {
                  // Packet is fully received, remove it to save some memory
                  cout << "At " 
                       << setprecision(10) << sc_time_stamp().to_double() 
                       << " : " << "Agent " << setfill(' ') << setw(3) << dec 
                       << _id << " received " 
                       << commmand2str(comm_in.read().to_uint()) 
                       << " packet: "
                       << setw(5) << setfill(' ') << packetId << " from ";
                  cout << "address: 0x" 
                       << hex << setw(8) << setfill('0')
                     //<< _packetsIn[packetId]->getSrcAddress().to_uint()
                       << (*_packetsIn.find(packetId)).second->getSrcAddress()
                     .to_uint()
                       << endl;                           

                  if(cmd == DATA_RD ||
                     cmd == MSG_RD ||
                     cmd == EXCL_RD ||
                     cmd == DATA_RDL ||
                     cmd == MSG_RDL)
                  {
                     // Generate response packet
                     Packet* packet = 0;
                     packet = new Packet((*_packetsIn.find(packetId)).second->
                                         getResponseSize(), 
                                         addresses_c[_id], 
                                         (*_packetsIn.find(packetId)).second->
                                         getSrcAddress(),
                                         DATA_WRNP);
                     this->send(packet);
                     for(unsigned int i = 0; i < _agents.size(); ++i)
                     {
                        if(addresses_c[i] == 
                           (*_packetsIn.find(packetId)).second->getSrcAddress())
                        {
                           _agents.at(i)->expect(packet);
                        }
                     }
                  }
                     
                  //delete _packetsIn[packetId];
                  delete (*_packetsIn.find(packetId)).second;
                  //_packetsIn.erase(packetId);
                  _packetsIn.erase(_packetsIn.find(packetId));
               }
            }
         }

         // Do nothing if there's nothing to do...
         if(empty_in.read() == true) continue;

         // Chance to play dead for this cycle
         if((unsigned(rand()) % 100) < _rxBusyChance) continue; 
         

         // Read the flit
         re_out.write(true);
         reading = true;
                 
            
      }
   }


#ifdef USE_R3_WRAPPERS

   //* TX thread, handles pushing packets to hibitys
   void msg_sender()
   {
      while(true)
      {
         // Sync to pos edge
         wait(clk.posedge_event());
         
         // Handle reset
         if(rst_n.read() == false)
         {
            msg_comm_out.write(0);
            msg_data_out.write(0);
            msg_addr_out.write(0);
            msg_we_out.write(false);
            freePackets(); // Deletes all packets
            continue; 
         }

         if(_msgPacketsOut.empty()) continue; // No packets to send      
         
         // Take packets from the FIFO
         Packet* packet = _msgPacketsOut.front();
         _msgPacketsOut.pop();
         

         // Send all flits
         for(unsigned int i = 0; i < packet->getSize();)
         {
            // Chance to play dead for this cycle
            // This doesn't work, need second cycle wait, stupido we_out!
            // if((unsigned(rand()) % 100) < _txBusyChance) 
            // {
            //    we_out.write(false);
            //    wait(clk.posedge_event());           
            //    continue; 
            // }

            // Wait if NI is full
            while(msg_full_in.read() == true) 
            {          
               //msg_we_out.write(true);
               wait(clk.posedge_event());
            }       

            msg_we_out.write(true);
            
            msg_comm_out.write(packet->getCommand());
            msg_data_out.write(packet->getData());
            msg_addr_out.write(packet->getDstAddress());


            wait(clk.posedge_event());
            ++i;
         }

         // Wait if NI is full
         while(msg_full_in.read() == true) 
         {             
            wait(clk.posedge_event());
         }
         
         cout << "At " << setprecision(10) << sc_time_stamp().to_double() 
              << " : "
              << "Agent " << setfill(' ') << setw(3) << dec << _id 
              << " sent     " 
              << commmand2str(packet->getHibiCommand())
              << " packet: " 
              << setw(5) << setfill(' ') <<  packet->getId() << " to   ";
         if(packet->getHibiCommand() == CFG_WR ||
            packet->getHibiCommand() == CFG_RD)
         {
            cout << "id: " << packet->getDstId() << endl;
         }
         else
         {
            cout << "address: 0x" 
                 << hex << setw(8) << setfill('0')
                 << packet->getDstAddress().to_uint()
                 << endl; 
         }

         msg_we_out.write(false);
         msg_addr_out.write(0);
         msg_comm_out.write(commands_c[IDLE]);
         msg_data_out.write(0);
         packet = 0;
      }
   }


   //* RX thread, handles receiving packets from hibitys
   void msg_receiver()
   {
      sc_uint<16> packetId;
      bool reading = false;
      
      while(true)
      {
         // Sync to pos edge and handle reset
         wait(clk.posedge_event());
         msg_re_out.write(false); // Default
         if(rst_n.read() == false) 
         {
            continue;
         }

         if(reading)
         {
            reading = false;
            
            if(msg_empty_in.read() == true)
            {
               // There's nothing to read
            }
            else
            {
               // Check that we're expecting a packet with this ID
               packetId = (msg_data_in.read().range(15, 0).to_uint());
               if(_packetsIn.find(packetId) == _packetsIn.end())
               {
                  ostringstream oss;
                  oss << "At " << setprecision(10) 
                      << sc_time_stamp().to_double()
                      << " : " << "Agent " << setfill(' ') << setw(3) << _id 
                      << " received unexpected flit with id: " << packetId;
                  SC_REPORT_WARNING("warning", oss.str().c_str());
                  msg_re_out.write(true);
                  continue;
               }

               HibiCommand cmd = (*_packetsIn.find(packetId)).second->
                     getHibiCommand();

               // Check that we are not getting normal stuff while locked!
               if(_locked &&
                  cmd != EXCL_WR &&
                  cmd != EXCL_RD &&
                  cmd != EXCL_RELEASE)
               {
                  ostringstream oss;
                  oss << "At " << setprecision(10) 
                      << sc_time_stamp().to_double()
                      << " : " << "Agent " << setfill(' ') << setw(3) << _id 
                      << " received non-exclusive packet while locked, id: " 
                      << packetId;
                  SC_REPORT_WARNING("warning", oss.str().c_str());
               }


               // Lock this agent when getting lock command
               if(cmd == EXCL_LOCK && !_locked)
               { _locked = true; }

               // Release the lock
               if(cmd == EXCL_RELEASE && _locked)
               { _locked = false; }

               //_packetsIn[packetId]->receiveWord();
               (*_packetsIn.find(packetId)).second->receiveWord();
         
               //if(_packetsIn[packetId]->complete())
               if((*_packetsIn.find(packetId)).second->complete())
               {
                  // Packet is fully received, remove it to save some memory
                  cout << "At " 
                       << setprecision(10) << sc_time_stamp().to_double() 
                       << " : " << "Agent " << setfill(' ') << setw(3) << dec 
                       << _id << " received " 
                       << commmand2str(msg_comm_in.read().to_uint()) 
                       << " packet: "
                       << setw(5) << setfill(' ') << packetId << " from ";
                  cout << "address: 0x" 
                       << hex << setw(8) << setfill('0')
                     //<< _packetsIn[packetId]->getSrcAddress().to_uint()
                       << (*_packetsIn.find(packetId)).second->getSrcAddress()
                     .to_uint()
                       << endl;                           

                  if(cmd == DATA_RD ||
                     cmd == MSG_RD ||
                     cmd == EXCL_RD ||
                     cmd == DATA_RDL ||
                     cmd == MSG_RDL)
                  {
                     // Generate response packet
                     Packet* packet = 0;
                     packet = new Packet((*_packetsIn.find(packetId)).second->
                                         getResponseSize(), 
                                         addresses_c[_id], 
                                         (*_packetsIn.find(packetId)).second->
                                         getSrcAddress(),
                                         DATA_WRNP);
                     this->send(packet);
                     for(unsigned int i = 0; i < _agents.size(); ++i)
                     {
                        if(addresses_c[i] == 
                           (*_packetsIn.find(packetId)).second->getSrcAddress())
                        {
                           _agents.at(i)->expect(packet);
                        }
                     }
                  }
                     
                  //delete _packetsIn[packetId];
                  delete (*_packetsIn.find(packetId)).second;
                  //_packetsIn.erase(packetId);
                  _packetsIn.erase(_packetsIn.find(packetId));
               }
            }
         }

         // Do nothing if there's nothing to do...
         if(msg_empty_in.read() == true) continue;

         // Chance to play dead for this cycle
         if((unsigned(rand()) % 100) < _rxBusyChance) continue; 
         

         // Read the flit
         msg_re_out.write(true);
         reading = true;
                 
            
      }
   }



#endif      

   // 
   // Private members
   // 

   // FIFO(s) for packets to be send
   queue<Packet*>            _packetsOut;
#ifdef USE_R3_WRAPPERS
   queue<Packet*>            _msgPacketsOut;
#endif

   // Expected packets by their ID
   multimap<sc_uint<16>, Packet*> _packetsIn;

   // agent identifier
   unsigned int _id; 
   
   // Agent might be busy doing other things occasionally 
   // Hence, transfer do not necessarily happen at max speed
   unsigned int _rxBusyChance;
   unsigned int _txBusyChance;

   // List of all agents is needed to notify them about 
   // new packets
   vector<Agent<addr_width_c, data_width_c, 
                comm_width_c, separate_addr_c>* >& _agents;

   // True when agent is locked
   bool _locked; 

};

#endif

// Local Variables:
// mode: c++
// c-file-style: "ellemtel"
// c-basic-offset: 3
// End:

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.