/* * * 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 , 2008 * Christophe Choichillon , 2011 * * Maintainers: alain, Christophe Choichillon */ ///////////////////////////////////////////////////////////////////////// // This component is a multi-segments Ram controller. // // It supports only the compact VCI packets defined // in the VCI advanced specification: // - A READ burst command packet (such a cache line request) // contains one single flit. // The response packet length is defined by the PLEN field. // The zero value for the PLEN field is not supported. // An ERROR response packets contain one single flit, // - WRITE burst command packets at consecutive addresses are supported. // The zero value for the PLEN field is not supported. // Write response packets contain always one single flit. // - The LL & SC command packets are supported, but the packet // must contain one single flit. // The RAM latency is a parameter, that can have a zero value. //////////////////////////////////////////////////////////////////////// // Implementation note: This component does not contain any FIFO, // and is controlled by a single FSM. // The latency counter is decremented in the IDLE state. // The VCI command is analysed and checked in the CMD_GET state. // - For read, ll or sc commands, the command is acknowledged in // the CMD_STATE. It is executed and the response is sent in the // RSP_READ, RSP_LL or RSP_SC states. // - For write commands, the command is acknowledged in the CMD_STATE, // or in the CMD_WRITE & CMD_ERROR states in case of bursts. // The command is executed in the CMD_WRITE state, or in the RSP_WRITE // state for the last flit of a burst. The response packet is sent // in the RSP_WRITE state. ///////////////////////////////////////////////////////////////////////// #include #include #include "vci_synthetic_target.h" namespace soclib { namespace caba { using namespace soclib; #define tmpl(x) template x VciSyntheticTarget ////////////////////////// tmpl(/**/)::VciSyntheticTarget( sc_module_name insname, const soclib::common::IntTab index, const soclib::common::MappingTable &mt, const soclib::common::Loader &loader, const uint32_t latency) : caba::BaseModule(insname), m_loader(loader), m_seglist(mt.getSegmentList(index)), m_latency(latency), r_llsc_buf((size_t)(1<::iterator seg; for ( seg = m_seglist.begin() ; seg != m_seglist.end() ; seg++ ) m_nbseg++; m_ram = new ram_t*[m_nbseg]; m_seg = new soclib::common::Segment*[m_nbseg]; size_t i = 0; size_t word_size = vci_param::B; // B is VCI's cell size for ( seg = m_seglist.begin() ; seg != m_seglist.end() ; seg++ ) { m_ram[i] = new ram_t[(seg->size()+word_size-1)/word_size]; m_seg[i] = &(*seg); i++; } } /////////////////////////// tmpl(/**/)::~VciSyntheticTarget() { for (size_t i=0 ; ibaseAddress(), m_seg[i]->size()); for ( size_t addr = 0 ; addr < m_seg[i]->size()/vci_param::B ; ++addr ) m_ram[i][addr] = le_to_machine(m_ram[i][addr]); } } //////////////////// tmpl(void)::reset() { for ( size_t i=0 ; isize()); m_cpt_read = 0; m_cpt_write = 0; if (m_latency) { r_fsm_state = FSM_IDLE; r_latency_count = m_latency - 1; } else { r_fsm_state = FSM_CMD_GET; r_latency_count = 0; } r_llsc_buf.clearAll(); } ///////////////////////////////////////////////////////////////////////////// tmpl(bool)::write(size_t seg, vci_addr_t addr, vci_data_t wdata, vci_be_t be) { if ( m_seg[seg]->contains(addr) ) { size_t index = (size_t)((addr - m_seg[seg]->baseAddress()) / vci_param::B); vci_data_t cur = m_ram[seg][index]; vci_data_t mask = vci_param::be2mask(be); m_ram[seg][index] = (cur & ~mask) | (wdata & mask); m_cpt_write++; return true; } return false; } ///////////////////////////////////////////////////////////////// tmpl(bool)::read(size_t seg, vci_addr_t addr, vci_data_t &rdata ) { if ( m_seg[seg]->contains(addr) ) { size_t index = (size_t)((addr - m_seg[seg]->baseAddress()) / vci_param::B); rdata = m_ram[seg][index]; m_cpt_read++; return true; } return false; } ////////////////////////// tmpl(void)::print_trace() { const char* state_str[] = { "IDLE", "CMD_GET", "CMD_WRITE", "CMD_ERROR", "RSP_READ", "RSP_WRITE", "RSP_LL", "RSP_SC", "RSP_ERROR" }; std::cout << "Simple_ram " << name() << " : state = " << state_str[r_fsm_state] << " / latency_count = " << r_latency_count << " / flit_count = " << r_flit_count << std::endl; } ///////////////////////// tmpl(void)::transition() { if (!p_resetn) { reset(); reload(); return; } #ifdef SOCLIB_MODULE_DEBUG std::cout << "Synthetic_target : " << name() << std::endl; std::cout << " fsm_state = " << r_fsm_state << " latency_count = " << r_latency_count << std::endl; #endif switch ( r_fsm_state ) { case FSM_IDLE: // unreachable state if m_latency == 0 { if ( p_vci.cmdval.read() ) { if (r_latency_count.read() == 0) { r_fsm_state = FSM_CMD_GET; r_latency_count = m_latency - 1; } else { r_latency_count = r_latency_count.read() - 1; } } break; } case FSM_CMD_GET: { if ( !p_vci.cmdval.read() ) break; vci_addr_t address = p_vci.address.read(); bool error = true; for ( size_t index = 0 ; indexcontains(address)) && (m_seg[index]->contains(address + p_vci.plen.read() - vci_param::B)) ) { error = false; r_seg_index = index; } } } r_address = address; r_be = p_vci.be.read(); r_wdata = p_vci.wdata.read(); r_srcid = p_vci.srcid.read(); r_trdid = p_vci.trdid.read(); r_pktid = p_vci.pktid.read(); if ( error ) { if( p_vci.eop.read() ) r_fsm_state = FSM_RSP_ERROR; else r_fsm_state = FSM_CMD_ERROR; } else { assert( (p_vci.plen.read() != 0) && "VCI command packets should have plen != 0"); if ( p_vci.cmd.read() == vci_param::CMD_WRITE ) { r_contig = p_vci.contig.read(); if( p_vci.eop.read() ) r_fsm_state = FSM_RSP_WRITE; else r_fsm_state = FSM_CMD_WRITE; } else if ( p_vci.cmd.read() == vci_param::CMD_READ ) { r_flit_count = p_vci.plen.read()/vci_param::B; r_contig = p_vci.contig.read(); r_fsm_state = FSM_RSP_READ; assert( p_vci.eop.read() && "VCI read command packets should be one flit"); } else if ( p_vci.cmd.read() == vci_param::CMD_STORE_COND ) { r_fsm_state = FSM_RSP_SC; assert( p_vci.eop.read() && "VCI sc command packets should be one flit"); } else if ( p_vci.cmd.read() == vci_param::CMD_LOCKED_READ ) { r_fsm_state = FSM_RSP_LL; assert( p_vci.eop.read() && "VCI ll command packets should be one flit"); } } break; } case FSM_CMD_WRITE: { assert( write (r_seg_index, r_address , r_wdata, r_be ) && "out of bounds access in a write burst" ); if ( p_vci.cmdval.read() ) { vci_addr_t next_address = r_address.read() + (vci_addr_t)vci_param::B; assert( ((r_contig && (next_address == p_vci.address.read())) || (!r_contig && (r_address.read() == p_vci.address.read()))) && "addresses must be contiguous or constant in a VCI write burst" ); r_address = p_vci.address.read(); r_be = p_vci.be.read(); r_wdata = p_vci.wdata.read(); if ( p_vci.eop.read() ) r_fsm_state = FSM_RSP_WRITE; } break; } case FSM_RSP_WRITE: { if (r_address.read() != 0x3) assert( write (r_seg_index, r_address , r_wdata, r_be ) && "out of bounds access in a write burst" ); if( p_vci.rspack.read() ) { if( m_latency ) r_fsm_state = FSM_IDLE; else r_fsm_state = FSM_CMD_GET; } break; } case FSM_RSP_READ: { if ( p_vci.rspack.read() ) { r_flit_count = r_flit_count - 1; if ( r_contig ) r_address = r_address.read() + vci_param::B; if ( r_flit_count == 1) // last flit { if( m_latency ) r_fsm_state = FSM_IDLE; else r_fsm_state = FSM_CMD_GET; } } break; } case FSM_CMD_ERROR: { if ( p_vci.cmdval.read() && p_vci.eop.read() ) { r_fsm_state = FSM_RSP_ERROR; } break; } case FSM_RSP_ERROR: { if ( p_vci.rspack.read() ) { if( m_latency ) r_fsm_state = FSM_IDLE; else r_fsm_state = FSM_CMD_GET; } break; } case FSM_RSP_LL: { if ( p_vci.rspack.read() ) { r_llsc_buf.doLoadLinked(r_address.read(), r_srcid.read()); if( m_latency ) r_fsm_state = FSM_IDLE; else r_fsm_state = FSM_CMD_GET; } break; } case FSM_RSP_SC: { if ( p_vci.rspack.read() ) { if ( r_llsc_buf.isAtomic(r_address.read(), r_srcid.read()) ) { r_llsc_buf.accessDone(r_address.read()); write (r_seg_index, r_address , r_wdata, r_be); } if( m_latency ) r_fsm_state = FSM_IDLE; else r_fsm_state = FSM_CMD_GET; } break; } } // end switch fsm_state } // end transition() /////////////////////// tmpl(void)::genMoore() { switch ( r_fsm_state ) { case FSM_IDLE: { p_vci.cmdack = false; p_vci.rspval = false; p_vci.rdata = 0; p_vci.rsrcid = 0; p_vci.rtrdid = 0; p_vci.rpktid = 0; p_vci.rerror = 0; p_vci.reop = false; break; } case FSM_CMD_GET: case FSM_CMD_WRITE: case FSM_CMD_ERROR: { p_vci.cmdack = true; p_vci.rspval = false; p_vci.rdata = 0; p_vci.rsrcid = 0; p_vci.rtrdid = 0; p_vci.rpktid = 0; p_vci.rerror = 0; p_vci.reop = false; break; } case FSM_RSP_WRITE: { p_vci.cmdack = false; p_vci.rspval = true; p_vci.rdata = 0; p_vci.rsrcid = r_srcid.read(); p_vci.rtrdid = r_trdid.read(); p_vci.rpktid = r_pktid.read(); p_vci.rerror = vci_param::ERR_NORMAL; p_vci.reop = true; break; } case FSM_RSP_READ: { vci_data_t rdata; assert( read(r_seg_index, r_address, rdata) && "out of bounds access in a read burst" ); p_vci.cmdack = false; p_vci.rspval = true; p_vci.rdata = rdata; p_vci.rsrcid = r_srcid.read(); p_vci.rtrdid = r_trdid.read(); p_vci.rpktid = r_pktid.read(); p_vci.rerror = vci_param::ERR_NORMAL; p_vci.reop = (r_flit_count.read() == 1); break; } case FSM_RSP_LL: { vci_data_t rdata; assert( read(r_seg_index, r_address, rdata) && "out of bounds access in a ll access" ); p_vci.cmdack = false; p_vci.rspval = true; p_vci.rdata = rdata; p_vci.rsrcid = r_srcid.read(); p_vci.rtrdid = r_trdid.read(); p_vci.rpktid = r_pktid.read(); p_vci.rerror = vci_param::ERR_NORMAL; p_vci.reop = true; break; } case FSM_RSP_SC: { p_vci.cmdack = false; p_vci.rspval = true; if ( r_llsc_buf.isAtomic(r_address.read(), r_srcid.read()) ) p_vci.rdata = 0; else p_vci.rdata = 1; p_vci.rsrcid = r_srcid.read(); p_vci.rtrdid = r_trdid.read(); p_vci.rpktid = r_pktid.read(); p_vci.rerror = vci_param::ERR_NORMAL; p_vci.reop = true; break; } case FSM_RSP_ERROR: { p_vci.cmdack = false; p_vci.rspval = true; p_vci.rdata = 0; p_vci.rsrcid = r_srcid.read(); p_vci.rtrdid = r_trdid.read(); p_vci.rpktid = r_pktid.read(); p_vci.rerror = vci_param::ERR_GENERAL_DATA_ERROR; p_vci.reop = true; break; } } // end switch fsm_state } // end genMoore() }}