/* * SOCLIB_LGPL_HEADER_BEGIN * * This file is part of SoCLib, GNU LGPLv2.1. * * SoCLib is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; version 2.1 of the License. * * SoCLib is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with SoCLib; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA * * SOCLIB_LGPL_HEADER_END * * Copyright (c) UPMC, Lip6, Asim * Alain Greiner 2013 * * Maintainers: alain */ //////////////////////////////////////////////////////////////////////////////// // This component emulates an external IO bus such as PCIe or Hypertransport, // but respect the VCI protocol. It can be attached to one OR SEVERAL clusters, // using a vci_io_bridge component. // It is considered as a local interconnect, for the ADDRESS or SRCID // decoding tables: // - the CMD routing_table decodes the local field of the VCI ADDRESS // to return the local target port // - The RSP routing_table decodes the local field of the VCI SRCID // to return the initator port // It is implemented as two independant crossbars, for VCI commands and // VCI responses respectively. // - The CMD crossbar has nb_ini input ports, and nb_tgt output ports, // including the ports to the vci_io_bridge component(s). // - The RSP crossbar has nb_tgt input ports, and nb_ini output ports. // including the ports to the vci_io_bridge component(s). // For both crossbars, output ports allocation policy is round robin. //////////////////////////////////////////////////////////////////////////////// #include #include #include "vci_buffers.h" #include "../include/vci_iox_network.h" #include "alloc_elems.h" namespace soclib { namespace caba { using soclib::common::alloc_elems; using soclib::common::dealloc_elems; using namespace sc_core; /////////////////////////////////////////////////////////////////////////////////// // The IoXbar class is instanciated twice, to implement the CMD & RSP XBARs /////////////////////////////////////////////////////////////////////////////////// template class IoXbar { // pkt_t type must be VciCmdBuffer or VciRspBuffer // the two following types can be found in these two classes typedef typename pkt_t::input_port_t input_port_t; typedef typename pkt_t::output_port_t output_port_t; const bool m_is_cmd; // CMD XBAR if true const size_t m_inputs; // number of inputs const size_t m_outputs; // number of outputs void* m_rt; // pointer on routing table (CMD or RSP) sc_signal* r_out_allocated; // for each output: allocation state sc_signal* r_out_origin; // for each output: input port index sc_signal* r_in_allocated; // for each input: allocation state sc_signal* r_in_dest; // for each input: output port index public: /////////////////////// IoXbar( bool is_cmd, size_t nb_inputs, size_t nb_outputs, void* rt ) : m_is_cmd( is_cmd ), m_inputs( nb_inputs ), m_outputs( nb_outputs ), m_rt ( rt ) { r_out_allocated = new sc_signal[nb_outputs]; r_out_origin = new sc_signal[nb_outputs]; r_in_allocated = new sc_signal[nb_inputs]; r_in_dest = new sc_signal[nb_inputs]; } //////////// void reset() { for (size_t i=0 ; i tgt " << out << " | "; } } } else { std::cout << "IOX_RSP_XBAR : " << std::dec; for( size_t out=0 ; out ini " << out << " | "; } } } std::cout << std::endl; } /////////////////////////////////////////// void transition( input_port_t **input_port, output_port_t **output_port ) { // loop on the output ports for ( size_t out = 0; out < m_outputs; out++) { if ( r_out_allocated[out].read() ) // possible desallocation { if ( output_port[out]->toPeerEnd() ) { size_t in = r_out_origin[out].read(); r_out_allocated[out] = false; r_in_allocated[in] = false; } } else // possible allocation { // loop on the intput ports bool found = false; for(size_t x = 0 ; (x < m_inputs) and not found ; x++) { size_t in = (x + r_out_origin[out] + 1) % m_inputs; if ( input_port[in]->getVal() ) { size_t req; // requested output port index if ( m_is_cmd ) { AddressDecodingTable* rt = (AddressDecodingTable*)m_rt; req = rt->get_value((uint64_t)(input_port[in]->address.read())); } else { AddressDecodingTable* rt = (AddressDecodingTable*)m_rt; req = rt->get_value((uint32_t)(input_port[in]->rsrcid.read())); } // allocate the output port if requested if ( out == req ) { r_out_allocated[out] = true; r_in_allocated[in] = true; r_out_origin[out] = in; r_in_dest[in] = out; found = true; } } } // end loop inputs } } // end loop outputs } // end transition ////////////////////////////////////////////// void genMealy_ack( input_port_t **input_port, output_port_t **output_port ) { for ( size_t in = 0 ; in < m_inputs ; in++ ) { size_t out = r_in_dest[in].read(); bool ack = r_in_allocated[in].read() and output_port[out]->getAck(); input_port[in]->setAck(ack); } } /////////////////////////////////////////////////////////////////////// void genMealy_val( input_port_t **input_port, output_port_t **output_port ) { for( size_t out = 0 ; out < m_outputs ; out++) { if (r_out_allocated[out]) { size_t in = r_out_origin[out]; pkt_t tmp; tmp.readFrom(*input_port[in]); tmp.writeTo(*output_port[out]); } else { output_port[out]->setVal(false); } } } }; // end class IoXbar /////////////////////////////////////////////////////////////////////////////////// #define tmpl(x) template x VciIoxNetwork /////////////////////////////////////////////////////////////////////////////////// ///////////////////////// tmpl(void)::print_trace() { m_cmd_xbar->print_trace(); m_rsp_xbar->print_trace(); } //////////////////////// tmpl(void)::transition() { if ( ! p_resetn.read() ) { m_cmd_xbar->reset(); m_rsp_xbar->reset(); return; } m_cmd_xbar->transition( m_ports_to_initiator, m_ports_to_target ); m_rsp_xbar->transition( m_ports_to_target, m_ports_to_initiator ); } ////////////////////////////// tmpl(void)::genMealy_cmd_val() { m_cmd_xbar->genMealy_val( m_ports_to_initiator, m_ports_to_target ); } ////////////////////////////// tmpl(void)::genMealy_cmd_ack() { m_cmd_xbar->genMealy_ack( m_ports_to_initiator, m_ports_to_target ); } ////////////////////////////// tmpl(void)::genMealy_rsp_val() { m_rsp_xbar->genMealy_val( m_ports_to_target, m_ports_to_initiator ); } ////////////////////////////// tmpl(void)::genMealy_rsp_ack() { m_rsp_xbar->genMealy_ack( m_ports_to_target, m_ports_to_initiator ); } /////////////////////////////////////////////////////////////////////////// tmpl(/**/)::VciIoxNetwork( sc_core::sc_module_name name, const soclib::common::MappingTable &mt, size_t nb_tgt, size_t nb_ini ) : BaseModule(name), p_clk("clk"), p_resetn("resetn"), p_to_tgt(soclib::common::alloc_elems >( "p_to_tgt", nb_tgt)), p_to_ini(soclib::common::alloc_elems >( "p_to_ini", nb_ini)), m_nb_tgt( nb_tgt ), m_nb_ini( nb_ini ), m_cmd_rt( mt.getLocalIndexFromAddress(0) ), m_rsp_rt( mt.getLocalIndexFromSrcid(0) ) { std::cout << " Building VciIoxNetwork : " << name << std::endl; SC_METHOD(transition); dont_initialize(); sensitive << p_clk.pos(); SC_METHOD(genMealy_cmd_val); // controls to targets CMDVAL dont_initialize(); sensitive << p_clk.neg(); for ( size_t i=0; i*[nb_ini]; for (size_t g = 0 ; g < nb_ini ; g++) m_ports_to_initiator[g] = &p_to_ini[g]; m_ports_to_target = new VciInitiator*[nb_tgt]; for (size_t g = 0 ; g < nb_tgt ; g++) m_ports_to_target[g] = &p_to_tgt[g]; } //////////////////////////// tmpl(/**/)::~VciIoxNetwork() { soclib::common::dealloc_elems(p_to_ini, m_nb_ini); soclib::common::dealloc_elems(p_to_tgt, m_nb_tgt); } }} // Local Variables: // tab-width: 4 // c-basic-offset: 4 // c-file-offsets:((innamespace . 0)(inline-open . 0)) // indent-tabs-mode: nil // End: // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=4:softtabstop=4