/* -*- c++ -*- * File : vci_io_bridge.cpp * Copyright (c) UPMC, Lip6, SoC * Authors: Cassio Fraga, Alain Greiner * * 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 */ #include #include "arithmetics.h" #include "alloc_elems.h" #include "../include/vci_io_bridge.h" ////// debug services /////////////////////////////////////////////////////// // All debug messages are conditionned by two variables: // - compile time : DEBUG_*** : defined below // - execution time : m_debug_*** : defined by constructor arguments // m_debug_activated = (m_debug_ok) and (m_cpt_cycle > m_debug_start_cycle) ///////////////////////////////////////////////////////////////////////////////// #define DEBUG_DMA_CMD 1 #define DEBUG_DMA_RSP 1 #define DEBUG_TLB_MISS 1 #define DEBUG_CONFIG_CMD 1 #define DEBUG_CONFIG_RSP 1 #define DEBUG_MISS_WTI 1 namespace soclib { namespace caba { namespace { const char *dma_cmd_fsm_state_str[] = { "DMA_CMD_IDLE", "DMA_CMD_FIFO_PUT_CMD", "DMA_CMD_FIFO_PUT_RSP", "DMA_CMD_MISS_WAIT", "DMA_CMD_WAIT_EOP", }; const char *dma_rsp_fsm_state_str[] = { "DMA_RSP_IDLE", "DMA_RSP_FIFO_PUT", }; const char *tlb_fsm_state_str[] = { "TLB_IDLE", "TLB_MISS", "TLB_PTE1_GET", "TLB_PTE1_SELECT", "TLB_PTE1_UPDT", "TLB_PTE2_GET", "TLB_PTE2_SELECT", "TLB_PTE2_UPDT", "TLB_WAIT", "TLB_RETURN", "TLB_INVAL_CHECK", }; const char *config_cmd_fsm_state_str[] = { "CONFIG_CMD_IDLE", "CONFIG_CMD_FIFO_PUT_CMD", "CONFIG_CMD_FIFO_PUT_RSP", }; const char *config_rsp_fsm_state_str[] = { "CONFIG_RSP_IDLE", "CONFIG_RSP_FIFO_PUT", }; const char *miss_wti_fsm_state_str[] = { "MISS_WTI_IDLE_MISS", "MISS_WTI_IDLE_WTI", "MISS_WTI_CMD_WTI", "MISS_WTI_RSP_WTI", "MISS_WTI_CMD_MISS", "MISS_WTI_RSP_MISS", }; } #define tmpl(...) template __VA_ARGS__ VciIoBridge //////////////////////// tmpl(/**/)::VciIoBridge( sc_module_name name, const soclib::common::MappingTable &mt_ext, const soclib::common::MappingTable &mt_int, const soclib::common::MappingTable &mt_iox, const soclib::common::IntTab &int_tgtid, // INT network TGTID const soclib::common::IntTab &int_srcid, // INT network SRCID const soclib::common::IntTab &iox_tgtid, // IOX network TGTID const bool has_irqs, const size_t dcache_words, const size_t iotlb_ways, const size_t iotlb_sets, const uint32_t debug_start_cycle, const bool debug_ok) : soclib::caba::BaseModule(name), p_clk("p_clk"), p_resetn("p_resetn"), p_vci_ini_ram("p_vci_ini_ram"), p_vci_tgt_iox("p_vci_tgt_iox"), p_vci_ini_iox("p_vci_ini_iox"), p_vci_tgt_int("p_vci_tgt_int"), p_vci_ini_int("p_vci_ini_int"), m_words( dcache_words ), m_has_irqs( has_irqs ), // INT & IOX Network m_int_seglist( mt_int.getSegmentList( int_tgtid )), m_int_srcid( mt_int.indexForId( int_srcid )), m_iox_seglist( mt_iox.getSegmentList( iox_tgtid )), m_iotlb_ways(iotlb_ways), m_iotlb_sets(iotlb_sets), m_debug_start_cycle(debug_start_cycle), m_debug_ok(debug_ok), // addressable registers r_iommu_ptpr("r_iommu_ptpr"), r_iommu_active("r_iommu_active"), r_iommu_bvar("r_iommu_bvar"), r_iommu_etr("r_iommu_etr"), r_iommu_bad_id("r_iommu_bad_id"), r_iommu_wti_paddr("r_iommu_wti_paddr"), r_iommu_peri_wti(alloc_elems >("r_peri_wti_paddr", 32)), // DMA_CMD FSM registers r_dma_cmd_fsm("r_dma_cmd_fsm"), r_dma_cmd_vaddr("r_dma_cmd_vaddr"), r_dma_cmd_paddr("r_dma_cmd_paddr"), //DMA_RSP FSM registers r_dma_rsp_fsm("r_dma_rsp_fsm"), // CONFIG_CMD FSM registers r_config_cmd_fsm("r_config_cmd_fsm"), r_config_cmd_rdata("r_config_cmd_rdata"), r_config_cmd_error("r_config_cmd_error"), r_config_cmd_inval_vaddr("r_config_cmd_inval_vaddr"), // CONFIG_RSP FSM registers r_config_rsp_fsm("r_config_rsp_fsm"), // TLB FSM registers r_tlb_fsm("r_tlb_fsm"), r_waiting_transaction("r_waiting_transaction"), r_tlb_miss_type("r_tlb_miss_type"), r_tlb_miss_error("r_tlb_miss_error"), r_tlb_paddr("r_tlb_paddr"), r_tlb_pte_flags("r_tlb_pte_flags"), r_tlb_pte_ppn("r_tlb_pte_ppn"), r_tlb_way("r_tlb_way"), r_tlb_set("r_tlb_set"), r_tlb_buf_valid("r_tlb_buf_valid"), r_tlb_buf_tag("r_tlb_buf_tag"), r_tlb_buf_vaddr("r_tlb_buf_vaddr"), r_tlb_buf_big_page("r_tlb_buf_big_page"), // MISS_WTI_CMD FSM registers r_miss_wti_cmd_fsm("r_miss_wti_cmd_fsm"), r_miss_wti_cmd_index("r_miss_wti_cmd_index"), // MISS_WTI_CMD FSM registers r_miss_wti_rsp_fsm("r_miss_wti_rsp_fsm"), r_miss_wti_rsp_error("r_miss_wti_rsp_error"), // allocator for CONFIG_RSP & DMA_RSP fifos r_alloc_fifo_config_rsp_local("r_alloc_fifo_config_rsp_local"), r_alloc_fifo_dma_rsp_local("r_alloc_fifo_dma_rsp_local"), // IRQs registers r_irq_pending(alloc_elems >("r_irq_pending", 32)), r_irq_request(alloc_elems >("r_irq_request", 32)), // TLB for IOMMU r_iotlb("iotlb", 0, iotlb_ways, iotlb_sets, vci_param_int::N), // Inter-FSM communications r_dma_tlb_req("r_dma_tlb_req"), r_config_tlb_req("r_config_tlb_req"), r_tlb_miss_req("r_tlb_miss_req"), // DMA_CMD FIFOs m_dma_cmd_addr_fifo("m_dma_cmd_addr_fifo",2), m_dma_cmd_srcid_fifo("m_dma_cmd_srcid_fifo",2), m_dma_cmd_trdid_fifo("m_dma_cmd_trdid_fifo",2), m_dma_cmd_pktid_fifo("m_dma_cmd_pktid_fifo",2), m_dma_cmd_be_fifo("m_dma_cmd_be_fifo",2), m_dma_cmd_cmd_fifo("m_dma_cmd_cmd_fifo",2), m_dma_cmd_contig_fifo("m_dma_cmd_contig_fifo",2), m_dma_cmd_data_fifo("m_dma_cmd_data_fifo",2), m_dma_cmd_eop_fifo("m_dma_cmd_eop_fifo",2), m_dma_cmd_cons_fifo("m_dma_cmd_cons_fifo",2), m_dma_cmd_plen_fifo("m_dma_cmd_plen_fifo",2), m_dma_cmd_wrap_fifo("m_dma_cmd_wrap_fifo",2), m_dma_cmd_cfixed_fifo("m_dma_cmd_cfixed_fifo",2), m_dma_cmd_clen_fifo("m_dma_cmd_clen_fifo",2), // DMA_RSP FIFOs m_dma_rsp_data_fifo("m_dma_rsp_data_fifo",2), m_dma_rsp_rsrcid_fifo("m_dma_rsp_rsrcid_fifo",2), m_dma_rsp_rtrdid_fifo("m_dma_rsp_rtrdid_fifo",2), m_dma_rsp_rpktid_fifo("m_dma_rsp_rpktid_fifo",2), m_dma_rsp_reop_fifo("m_dma_rsp_reop_fifo",2), m_dma_rsp_rerror_fifo("m_dma_rsp_rerror_fifo",2), // CONFIG_CMD FIFOs m_config_cmd_addr_fifo("m_config_cmd_addr_fifo",2), m_config_cmd_srcid_fifo("m_config_cmd_srcid_fifo",2), m_config_cmd_trdid_fifo("m_config_cmd_trdid_fifo",2), m_config_cmd_pktid_fifo("m_config_cmd_pktid_fifo",2), m_config_cmd_be_fifo("m_config_cmd_be_fifo",2), m_config_cmd_cmd_fifo("m_config_cmd_cmd_fifo",2), m_config_cmd_contig_fifo("m_config_cmd_contig_fifo",2), m_config_cmd_data_fifo("m_config_cmd_data_fifo",2), m_config_cmd_eop_fifo("m_config_cmd_eop_fifo",2), m_config_cmd_cons_fifo("m_config_cmd_cons_fifo",2), m_config_cmd_plen_fifo("m_config_cmd_plen_fifo",2), m_config_cmd_wrap_fifo("m_config_cmd_wrap_fifo",2), m_config_cmd_cfixed_fifo("m_config_cmd_cfixed_fifo",2), m_config_cmd_clen_fifo("m_config_cmd_clen_fifo",2), // CONFIG_RSP FIFOs m_config_rsp_data_fifo("m_config_rsp_data_fifo",2), m_config_rsp_rsrcid_fifo("m_config_rsp_rsrcid_fifo",2), m_config_rsp_rtrdid_fifo("m_config_rsp_rtrdid_fifo",2), m_config_rsp_rpktid_fifo("m_config_rsp_rpktid_fifo",2), m_config_rsp_reop_fifo("m_config_rsp_reop_fifo",2), m_config_rsp_rerror_fifo("m_config_rsp_rerror_fifo",2) { std::cout << " - Building VciIoBridge : " << name << std::endl; // checking segments on INT network assert ( ( not m_int_seglist.empty() ) and "VCI_IO_BRIDGE ERROR : no segment allocated on INT network"); std::list::iterator int_seg; for ( int_seg = m_int_seglist.begin() ; int_seg != m_int_seglist.end() ; int_seg++ ) { std::cout << " => segment " << int_seg->name() << " / base = " << std::hex << int_seg->baseAddress() << " / size = " << int_seg->size() << std::endl; } // checking segments on IOX network assert ( ( not m_iox_seglist.empty() ) and "VCI_IO_BRIDGE ERROR : no segment allocated on IOX network"); std::list::iterator iox_seg; for ( iox_seg = m_iox_seglist.begin() ; iox_seg != m_iox_seglist.end() ; iox_seg++ ) { std::cout << " => segment " << iox_seg->name() << " / base = " << std::hex << iox_seg->baseAddress() << " / size = " << iox_seg->size() << std::endl; } assert( (vci_param_int::N == vci_param_ext::N) and "VCI_IO_BRIDGE ERROR: VCI ADDRESS widths must be equal on the 3 networks"); assert( (vci_param_int::N <= 64) and "VCI_IO_BRIDGE ERROR: VCI ADDRESS width cannot be bigger than 64 bits"); assert( ((vci_param_int::B == 4) or (vci_param_int::B == 8)) and "VCI_IO_BRIDGE ERROR: VCI DATA width must be 32 or 64 bits on internal network"); assert( ((vci_param_ext::B == 4) or (vci_param_ext::B == 8)) and "VCI_IO_BRIDGE ERROR: VCI DATA width must be 32 or 64 bits on external network"); assert( (vci_param_int::S == vci_param_ext::S) and "VCI_IO_BRIDGE ERROR: SRCID widths must be equal on the 3 networks"); // contruct 32 IRQ ports if required if ( has_irqs ) { for ( size_t n=0 ; n<32 ; n++ ) p_irq[n] = new sc_core::sc_in; } // Cache line buffer r_tlb_buf_data = new uint32_t[dcache_words]; SC_METHOD(transition); dont_initialize(); sensitive << p_clk.pos(); SC_METHOD(genMoore); dont_initialize(); sensitive << p_clk.neg(); } ///////////////////////////////////// tmpl(/**/)::~VciIoBridge() ///////////////////////////////////// { delete [] r_iommu_peri_wti; delete [] r_tlb_buf_data; soclib::common::dealloc_elems(p_irq, 32); soclib::common::dealloc_elems(r_irq_request, 32); soclib::common::dealloc_elems(r_irq_pending, 32); } //////////////////////////////////// tmpl(void)::print_trace(size_t mode) //////////////////////////////////// { // b0 : IOtlb trace std::cout << std::dec << "IO_BRIDGE " << name() << std::endl; std::cout << " " << dma_cmd_fsm_state_str[r_dma_cmd_fsm.read()] << " | " << dma_rsp_fsm_state_str[r_dma_rsp_fsm.read()] << " | " << tlb_fsm_state_str[r_tlb_fsm.read()] << " | " << config_cmd_fsm_state_str[r_config_cmd_fsm.read()] << " | " << config_rsp_fsm_state_str[r_config_rsp_fsm.read()] << " | " << miss_wti_fsm_state_str[r_miss_wti_cmd_fsm.read()] << std::endl; if(mode & 0x01) { std::cout << " IOTLB" << std::endl; r_iotlb.printTrace(); } if(mode & 0x02) { } } //////////////////////// tmpl(void)::print_stats() //////////////////////// { std::cout << name() << std::endl << "- IOTLB MISS RATE = " << (float)m_cpt_iotlb_miss/m_cpt_iotlb_read << std::endl << "- IOTLB MISS COST = " << (float)m_cost_iotlb_miss/m_cpt_iotlb_miss << std::endl << "- IOTLB MISS TRANSACTION COST = " << (float)m_cost_iotlbmiss_transaction/m_cpt_iotlbmiss_transaction << std::endl << "- IOTLB MISS TRANSACTION RATE (OVER ALL MISSES) = " << (float)m_cpt_iotlbmiss_transaction/m_cpt_iotlb_miss << std::endl; } //////////////////////// tmpl(void)::clear_stats() //////////////////////// { m_cpt_iotlb_read = 0; m_cpt_iotlb_miss = 0; m_cost_iotlb_miss = 0; m_cpt_iotlbmiss_transaction = 0; m_cost_iotlbmiss_transaction = 0; } ///////////////////////// tmpl(void)::transition() ///////////////////////// { if ( not p_resetn.read() ) { r_dma_cmd_fsm = DMA_CMD_IDLE; r_dma_rsp_fsm = DMA_RSP_IDLE; r_tlb_fsm = TLB_IDLE; r_config_cmd_fsm = CONFIG_CMD_IDLE; r_config_rsp_fsm = CONFIG_RSP_IDLE; r_miss_wti_cmd_fsm = MISS_WTI_CMD_IDLE; r_miss_wti_rsp_fsm = MISS_WTI_RSP_IDLE; r_alloc_fifo_config_rsp_local = true; r_alloc_fifo_dma_rsp_local = true; r_tlb_buf_valid = false; r_iommu_active = false; r_iommu_wti_enable = false; // initializing FIFOs m_dma_cmd_addr_fifo.init(); m_dma_cmd_srcid_fifo.init(); m_dma_cmd_trdid_fifo.init(); m_dma_cmd_pktid_fifo.init(); m_dma_cmd_be_fifo.init(); m_dma_cmd_cmd_fifo.init(); m_dma_cmd_contig_fifo.init(); m_dma_cmd_data_fifo.init(); m_dma_cmd_eop_fifo.init(); m_dma_cmd_cons_fifo.init(); m_dma_cmd_plen_fifo.init(); m_dma_cmd_wrap_fifo.init(); m_dma_cmd_cfixed_fifo.init(); m_dma_cmd_clen_fifo.init(); m_dma_rsp_rsrcid_fifo.init(); m_dma_rsp_rtrdid_fifo.init(); m_dma_rsp_rpktid_fifo.init(); m_dma_rsp_data_fifo.init(); m_dma_rsp_rerror_fifo.init(); m_dma_rsp_reop_fifo.init(); m_config_cmd_addr_fifo.init(); m_config_cmd_srcid_fifo.init(); m_config_cmd_trdid_fifo.init(); m_config_cmd_pktid_fifo.init(); m_config_cmd_be_fifo.init(); m_config_cmd_cmd_fifo.init(); m_config_cmd_contig_fifo.init(); m_config_cmd_data_fifo.init(); m_config_cmd_eop_fifo.init(); m_config_cmd_cons_fifo.init(); m_config_cmd_plen_fifo.init(); m_config_cmd_wrap_fifo.init(); m_config_cmd_cfixed_fifo.init(); m_config_cmd_clen_fifo.init(); m_config_rsp_rsrcid_fifo.init(); m_config_rsp_rtrdid_fifo.init(); m_config_rsp_rpktid_fifo.init(); m_config_rsp_data_fifo.init(); m_config_rsp_rerror_fifo.init(); m_config_rsp_reop_fifo.init(); // SET/RESET Communication flip-flops r_dma_tlb_req = false; r_config_tlb_req = false; r_tlb_miss_req = false; // Debug variable m_debug_activated = false; for ( size_t n=0 ; n<32 ; n++ ) { r_irq_pending[n] = false; r_irq_request[n] = false; } // activity counters m_cpt_total_cycles = 0; m_cpt_iotlb_read = 0; m_cpt_iotlb_miss = 0; m_cpt_iotlbmiss_transaction = 0; m_cost_iotlbmiss_transaction = 0; m_cpt_trt_dma_full = 0; m_cpt_trt_dma_full_cost = 0; m_cpt_trt_config_full = 0; m_cpt_trt_config_full_cost = 0; for (uint32_t i=0; i<32 ; ++i) m_cpt_fsm_dma_cmd [i] = 0; for (uint32_t i=0; i<32 ; ++i) m_cpt_fsm_dma_rsp [i] = 0; for (uint32_t i=0; i<32 ; ++i) m_cpt_fsm_tlb [i] = 0; for (uint32_t i=0; i<32 ; ++i) m_cpt_fsm_config_cmd [i] = 0; for (uint32_t i=0; i<32 ; ++i) m_cpt_fsm_config_rsp [i] = 0; for (uint32_t i=0; i<32 ; ++i) m_cpt_fsm_miss_wti_cmd [i] = 0; for (uint32_t i=0; i<32 ; ++i) m_cpt_fsm_miss_wti_rsp [i] = 0; return; } // default values for FIFOs bool dma_cmd_fifo_put = false; bool dma_cmd_fifo_get = false; bool dma_rsp_fifo_put = false; bool dma_rsp_fifo_get = false; bool config_cmd_fifo_put = false; bool config_cmd_fifo_get = false; bool config_rsp_fifo_put = false; bool config_rsp_fifo_get = false; #ifdef INSTRUMENTATION m_cpt_fsm_dma_cmd [r_dma_cmd_fsm.read()] ++; m_cpt_fsm_dma_rsp [r_dma_rsp_fsm.read() ] ++; m_cpt_fsm_tlb [r_tlb_fsm.read() ] ++; m_cpt_fsm_config_cmd [r_config_cmd_fsm.read() ] ++; m_cpt_fsm_config_rsp [r_config_rsp_fsm.read() ] ++; m_cpt_fsm_miss_wti_cmd [r_miss_wti_cmd_fsm.read() ] ++; m_cpt_fsm_miss_wti_rsp [r_miss_wti_rsp_fsm.read() ] ++; #endif m_cpt_total_cycles++; m_debug_activated = (m_cpt_total_cycles > m_debug_start_cycle) and m_debug_ok; ////////////////////////////////////////////////////////////////////////////// // The DMA_CMD_FSM handles DMA transactions requested by peripherals // It makes the address translation if IOMMU is activated. /////////////////////////////////////////////////////////////////////////////// switch( r_dma_cmd_fsm.read() ) { ////////////////// case DMA_CMD_IDLE: // waiting DMA VCI transaction { if ( p_vci_tgt_iox.cmdval.read() ) // compute physical address { if ( not r_iommu_active.read() ) // tlb not activated { #if DEBUG_DMA_CMD if( m_debug_activated ) std::cout << " IOMMU not activated" << std::endl; #endif // put DMA transaction into DMA_CMD fifo r_dma_cmd_paddr = p_vci_tgt_iox.address.read(); r_dma_cmd_fsm = DMA_CMD_FIFO_PUT_CMD; } else if (r_tlb_fsm.read() == TLB_IDLE || r_tlb_fsm.read() == TLB_WAIT ) // tlb access possible { vci_addr_t iotlb_paddr; pte_info_t iotlb_flags; size_t iotlb_way; size_t iotlb_set; vci_addr_t iotlb_nline; bool iotlb_hit; #ifdef INSTRUMENTATION m_cpt_iotlb_read++; #endif iotlb_hit = r_iotlb.translate(p_vci_tgt_iox.address.read(), &iotlb_paddr, &iotlb_flags, &iotlb_nline, // unused &iotlb_way, // unused &iotlb_set ); // unused if ( iotlb_hit ) // tlb hit { if ( not iotlb_flags.w and // access right violation (p_vci_tgt_iox.cmd.read() == vci_param_ext::CMD_WRITE) ) { // put DMA response error into DMA_RSP fifo r_iommu_etr = MMU_WRITE_ACCES_VIOLATION; r_iommu_bvar = p_vci_tgt_iox.address.read(); r_iommu_bad_id = p_vci_tgt_iox.srcid.read(); r_dma_cmd_fsm = DMA_CMD_FIFO_PUT_RSP; #if DEBUG_DMA_CMD if( m_debug_activated ) std::cout << " TLB HIT but writable violation" << std::endl; #endif } else // no access rights violation { #if DEBUG_DMA_CMD if( m_debug_activated ) std::cout << " TLB HIT" << std::endl; #endif // put DMA transaction into DMA_CMD fifo r_dma_cmd_paddr = iotlb_paddr; r_dma_cmd_fsm = DMA_CMD_FIFO_PUT_CMD; } } else // TLB miss { #ifdef INSTRUMENTATION m_cpt_iotlb_miss++; #endif // register virtual address, and send request to TLB FSM r_dma_cmd_vaddr = p_vci_tgt_iox.address.read(); r_dma_tlb_req = true; r_dma_cmd_fsm = DMA_CMD_MISS_WAIT; #if DEBUG_DMA_CMD if( m_debug_activated ) std::cout << " TLB MISS" << std::endl; #endif } // end !hit } // end if tlb_activated } // end if cmdval break; } ////////////////////////// case DMA_CMD_FIFO_PUT_CMD: // put a DMA transaction in DMA_CMD fifo // if contig, VCI address must be incremented { if ( p_vci_tgt_iox.cmdval && m_dma_cmd_addr_fifo.wok() ) { dma_cmd_fifo_put = true; if ( p_vci_tgt_iox.contig.read() ) r_dma_cmd_paddr = r_dma_cmd_paddr.read() + vci_param_ext::B; if ( p_vci_tgt_iox.eop.read() ) r_dma_cmd_fsm = DMA_CMD_IDLE; #if DEBUG_DMA_CMD if( m_debug_activated ) std::cout << " Push into DMA_CMD fifo:" << " address = " << std::hex << r_dma_cmd_paddr.read() << " srcid = " << p_vci_tgt_iox.srcid.read() << " trdid = " << p_vci_tgt_iox.trdid.read() << " wdata = " << p_vci_tgt_iox.wdata.read() << " be = " << p_vci_tgt_iox.be.read() << " contig = " << p_vci_tgt_iox.contig.read() << " eop = " << std::dec << p_vci_tgt_iox.eop.read() << " plen = " << std::dec << p_vci_tgt_iox.plen.read() << std::endl; #endif } break; } ////////////////////// case DMA_CMD_WAIT_EOP: // An error has been detected on the VCI DMA command // consume the VCI packet before sending the error response { if ( p_vci_tgt_iox.eop.read() ) r_dma_cmd_fsm = DMA_CMD_FIFO_PUT_RSP; break; } ////////////////////////// case DMA_CMD_FIFO_PUT_RSP: // try to put a response error in DMA_RSP fifo // The FIFO is shared with DMA_RSP FSM // and we must we wait for allocation... { if ( r_alloc_fifo_dma_rsp_local.read() ) { dma_rsp_fifo_put = true; if( m_dma_rsp_data_fifo.wok() ) { #if DEBUG_DMA_CMD if( m_debug_activated ) std::cout << " Put a response error to a DMA transaction." << std::endl; #endif r_dma_cmd_fsm = DMA_CMD_IDLE; } } break; } /////////////////////// case DMA_CMD_MISS_WAIT: // waiting completion of a TLB miss // we must test a possible page fault error... { if ( not r_dma_tlb_req.read() ) // TLB miss completed { if ( r_tlb_miss_error.read() ) // Error reported by TLB FSM { r_iommu_etr = MMU_READ_PT2_UNMAPPED; r_iommu_bvar = r_dma_cmd_vaddr.read(); r_iommu_bad_id = p_vci_tgt_iox.srcid.read(); r_dma_cmd_fsm = DMA_CMD_FIFO_PUT_RSP; } else // No error { r_dma_cmd_fsm = DMA_CMD_IDLE; } } break; } } // end switch DMA_CMD FSM ////////////////////////////////////////////////////////////////////////////// // The DMA_RSP_FSM handles the RAM responses to peripherals DMA transactions. ////////////////////////////////////////////////////////////////////////////// switch( r_dma_rsp_fsm.read() ) { ////////////////// case DMA_RSP_IDLE: // waiting a response from RAM betwork { if ( p_vci_ini_ram.rspval.read() ) { r_dma_rsp_fsm = DMA_RSP_FIFO_PUT; } break; } ////////////////////// case DMA_RSP_FIFO_PUT: { if(p_vci_ini_ram.rspval.read() and not r_alloc_fifo_dma_rsp_local.read() ) { dma_rsp_fifo_put = true; if(p_vci_ini_ram.reop.read()) r_dma_rsp_fsm = DMA_RSP_IDLE; #if DEBUG_DMA_RSP if( m_debug_activated ) std::cout << " Push response into DMA_RSP fifo:" << " / rsrcid = " << std::hex << p_vci_ini_ram.rsrcid.read() << " / rtrdid = " << p_vci_ini_ram.rtrdid.read() << " / rdata = " << std::hex << p_vci_ini_ram.rdata.read() << " / rerror = " << p_vci_ini_ram.rerror.read() << " / reop = " << p_vci_ini_ram.reop.read() << std::endl; #endif } break; } } // end switch DMA_RSP_FSM ////////////////////////////////////////////////////////////////////////////////// // The TLB FSM handles TLB miss request (from DMA_CMD FSM), // and the PTE inval request (from CONFIG_CMD FSM). // PTE inval request have highest priority. In case of TLB miss, // this fsm searchs the requested PTE on the prefetch buffer. // In case of buffer miss, it request the MISS_WTI FSM to access the memory. // It bypass the first level page table access if possible. // It reset the r_dma_tlb_req flip-flop to signal TLB miss completion. // An unexpected, but possible page fault is signaled in r_tlb_miss_error flip_flop. //////////////////////////////////////////////////////////////////////////////////// switch (r_tlb_fsm.read()) { ////////////// case TLB_IDLE: // In case of TLB miss request, chek the prefetch buffer first // PTE inval request are handled as unmaskable interrupts { if ( r_config_tlb_req ) // Request from CONFIG FSM for a PTE invalidation { r_config_tlb_req = false; r_waiting_transaction = false; r_tlb_fsm = TLB_INVAL_CHECK; } else if ( r_dma_tlb_req.read() ) // request from DMA_CMD for a TLB Miss { // Checking prefetch buffer if( not r_tlb_buf_big_page ) // small page => PTE2 { if( r_tlb_buf_valid && // Hit on prefetch buffer (r_tlb_buf_vaddr.read() == (r_dma_cmd_vaddr.read()& ~PTE2_LINE_OFFSET & ~K_PAGE_OFFSET_MASK))) { size_t pte_offset = (r_dma_cmd_vaddr.read()& PTE2_LINE_OFFSET)>>12; uint32_t pte_flags = r_tlb_buf_data[2*pte_offset]; uint32_t pte_ppn = r_tlb_buf_data[2*pte_offset+1]; // Bit valid checking if ( not ( pte_flags & PTE_V_MASK) ) // unmapped { std::cout << "VCI_IO_BRIDGE ERROR : " << name() << " Page Table entry unmapped" << std::endl; r_tlb_miss_error = true; r_dma_tlb_req = false; #if DEBUG_TLB_MISS if ( m_debug_activated ) std::cout << " PTE2 Unmapped" << std::hex << " / paddr = " << r_tlb_paddr.read() << " / PTE_FLAGS = " << pte_flags << " / PTE_PPN = " << pte_ppn << std::endl; #endif break; } // valid PTE2 : we must update the TLB r_tlb_pte_flags = pte_flags; r_tlb_pte_ppn = pte_ppn; r_tlb_fsm = TLB_PTE2_SELECT; #if DEBUG_TLB_MISS if ( m_debug_activated ) std::cout << " Hit on prefetch buffer: PTE2" << std::hex << " / PTE_FLAGS = " << pte_flags << " / PTE_PPN = " << pte_ppn << std::endl; #endif break; } } else // big page => PTE1 { if( r_tlb_buf_valid && // Hit on prefetch buffer (r_tlb_buf_vaddr.read() == (r_dma_cmd_vaddr.read()& ~PTE1_LINE_OFFSET & ~M_PAGE_OFFSET_MASK ))) { size_t pte_offset = (r_dma_cmd_vaddr.read()& PTE1_LINE_OFFSET)>>21; uint32_t pte_flags = r_tlb_buf_data[pte_offset]; // Bit valid checking if ( not ( pte_flags & PTE_V_MASK) ) // unmapped { std::cout << "VCI_IO_BRIDGE ERROR : " << name() << " Page Table entry unmapped" << std::endl; r_tlb_miss_error = true; r_dma_tlb_req = false; #if DEBUG_TLB_MISS if ( m_debug_activated ) std::cout << " PTE1 Unmapped" << std::hex << " / paddr = " << r_tlb_paddr.read() << " / PTE = " << pte_flags << std::endl; #endif break; } // valid PTE1 : we must update the TLB r_tlb_pte_flags = pte_flags; r_tlb_fsm = TLB_PTE1_SELECT; #if DEBUG_TLB_MISS if ( m_debug_activated ) std::cout << " Hit on prefetch buffer: PTE1" << std::hex << " / paddr = " << r_tlb_paddr.read() << std::hex << " / PTE1 = " << pte_flags << std::endl; #endif break; } } // prefetch buffer miss r_tlb_fsm = TLB_MISS; #if DEBUG_TLB_MISS if ( m_debug_activated ) std::cout << " Miss on prefetch buffer" << std::hex << " / vaddr = " << r_dma_cmd_vaddr.read() << std::endl; #endif } break; } ////////////// case TLB_MISS: // handling tlb miss { uint32_t ptba = 0; bool bypass; vci_addr_t pte_paddr; #ifdef INSTRUMENTATION m_cpt_iotlbmiss_transaction++; #endif // evaluate bypass in order to skip first level page table access bypass = r_iotlb.get_bypass(r_dma_cmd_vaddr.read(), &ptba); // Request MISS_WTI_FSM a transaction on INT Network if ( not bypass ) // Read PTE1/PTD1 in XRAM { #if DEBUG_TLB_MISS if ( m_debug_activated ) std::cout << " Read PTE1/PTD1 in memory" << std::endl; #endif pte_paddr = (vci_addr_t)((r_iommu_ptpr.read()) << (INDEX1_NBITS+2)) | (vci_addr_t)((r_dma_cmd_vaddr.read() >> PAGE_M_NBITS) << 2); r_tlb_paddr = pte_paddr; r_tlb_miss_req = true; r_tlb_miss_type = PTE1_MISS; r_tlb_fsm = TLB_WAIT; } else // Read PTE2 in XRAM { #if DEBUG_TLB_MISS if ( m_debug_activated ) std::cout << " Read PTE2 in memory" << std::endl; #endif //&PTE2 = PTBA + IX2 * 8 pte_paddr = (vci_addr_t)ptba << PAGE_K_NBITS | (vci_addr_t)(r_dma_cmd_vaddr.read()&PTD_ID2_MASK)>>(PAGE_K_NBITS-3); r_tlb_paddr = pte_paddr; r_tlb_miss_req = true; r_tlb_miss_type = PTE2_MISS; r_tlb_fsm = TLB_WAIT; } break; } ////////////////// case TLB_PTE1_GET: // Try to read a PT1 entry in the miss buffer { uint32_t entry; vci_addr_t line_number = (vci_addr_t)((r_tlb_paddr.read())&(CACHE_LINE_MASK)); size_t word_position = (size_t)( ((r_tlb_paddr.read())&(~CACHE_LINE_MASK))>>2 ); // Hit test. Just to verify. // Hit must happen, since we've just finished its' miss transaction bool hit = (r_tlb_buf_valid && (r_tlb_buf_tag.read()== line_number) ); assert(hit and "Error: No hit on prefetch buffer after Miss Transaction"); entry = r_tlb_buf_data[word_position]; // Bit valid checking if ( not ( entry & PTE_V_MASK) ) // unmapped { //must not occur! std::cout << "IOMMU ERROR " << name() << "TLB_IDLE state" << std::endl << "The Page Table entry ins't valid (unmapped)" << std::endl; r_tlb_miss_error = true; r_dma_tlb_req = false; r_tlb_fsm = TLB_IDLE; #if DEBUG_TLB_MISS if ( m_debug_activated ) { std::cout << " First level entry Unmapped" << std::hex << " / paddr = " << r_tlb_paddr.read() << std::hex << " / PTE = " << entry << std::endl; } #endif break; } if( entry & PTE_T_MASK ) // PTD : me must access PT2 { // register bypass r_iotlb.set_bypass( r_dma_cmd_vaddr.read(), entry & ((1 << (vci_param_int::N-PAGE_K_NBITS)) - 1), 0); //nline, unused //&PTE2 = PTBA + IX2 * 8 // ps: PAGE_K_NBITS corresponds also to the size of a second level page table r_tlb_paddr = (vci_addr_t)(entry & ((1<<(vci_param_int::N-PAGE_K_NBITS))-1)) << PAGE_K_NBITS | (vci_addr_t)(((r_dma_cmd_vaddr.read() & PTD_ID2_MASK) >> PAGE_K_NBITS) << 3); r_tlb_miss_req = true; r_tlb_miss_type = PTE2_MISS; r_tlb_fsm = TLB_WAIT; #ifdef INSTRUMENTATION m_cpt_iotlbmiss_transaction++; #endif #if DEBUG_TLB_MISS if ( m_debug_activated ) std::cout << " Success. Search PTE2" << std::hex << " / PADDR = " << r_tlb_paddr.read() << " / PTD = " << entry << std::endl; #endif } else // PTE1 : we must update the IOTLB // Should not occur if working only with small pages { r_tlb_pte_flags = entry; r_tlb_fsm = TLB_PTE1_SELECT; #if DEBUG_TLB_MISS if ( m_debug_activated ) std::cout << " Success. Big page" << std::hex << " / paddr = " << r_tlb_paddr.read() << std::hex << " / PTE1 = " << entry << std::endl; #endif } break; } ///////////////////// case TLB_PTE1_SELECT: // select a slot for PTE1 { size_t way; size_t set; r_iotlb.select( r_dma_cmd_vaddr.read(), true, // PTE1 &way, &set ); #ifdef INSTRUMENTATION m_cpt_iotlb_read++; #endif #if DEBUG_TLB_MISS if ( m_debug_activated ) std::cout << " Select a slot in TLB" << " / way = " << std::dec << way << " / set = " << set << std::endl; #endif r_tlb_way = way; r_tlb_set = set; r_tlb_fsm = TLB_PTE1_UPDT; break; } /////////////////// case TLB_PTE1_UPDT: // write a new PTE1 in tlb // not necessary to treat the L/R bit { uint32_t pte = r_tlb_pte_flags.read(); r_tlb_paddr = (vci_addr_t)( ((r_tlb_pte_flags.read() & PPN1_MASK) << 21) | (r_dma_cmd_vaddr.read()& M_PAGE_OFFSET_MASK) ); // update TLB r_iotlb.write( true, // 2M page pte, 0, // argument unused for a PTE1 r_dma_cmd_vaddr.read(), r_tlb_way.read(), r_tlb_set.read(), 0 ); //we set nline = 0 #ifdef INSTRUMENTATION m_cpt_iotlb_write++; #endif #if DEBUG_TLB_MISS if ( m_debug_activated ) { std::cout << " write PTE1 in TLB" << " / set = " << std::dec << r_tlb_set.read() << " / way = " << r_tlb_way.read() << std::endl; r_iotlb.printTrace(); } #endif // next state r_tlb_fsm = TLB_RETURN; // exit sub-fsm break; } ////////////////// case TLB_PTE2_GET: // Try to read a PTE2 (64 bits) in the miss buffer { uint32_t pte_flags; uint32_t pte_ppn; vci_addr_t line_number = (vci_addr_t)((r_tlb_paddr.read())&(CACHE_LINE_MASK)); size_t word_position = (size_t)( ((r_tlb_paddr.read())&(~CACHE_LINE_MASK))>>2 ); // Hit test. Just to verify. bool hit = (r_tlb_buf_valid && (r_tlb_buf_tag.read()== line_number) ); assert(hit and "Error: No hit on prefetch buffer after Miss Transaction"); pte_flags= r_tlb_buf_data[word_position]; pte_ppn= r_tlb_buf_data[word_position+1]; //because PTE2 is 2 words long // Bit valid checking if ( not ( pte_flags & PTE_V_MASK) ) // unmapped { //must not occur! std::cout << "IOMMU ERROR " << name() << "TLB_IDLE state" << std::endl << "The Page Table entry ins't valid (unmapped)" << std::endl; r_tlb_miss_error = true; r_dma_tlb_req = false; r_tlb_fsm = TLB_IDLE; #if DEBUG_TLB_MISS if ( m_debug_activated ) std::cout << " PTE2 Unmapped" << std::hex << " / PADDR = " << r_tlb_paddr.read() << " / PTE = " << pte_flags << std::endl; #endif break; } r_tlb_pte_flags = pte_flags; r_tlb_pte_ppn = pte_ppn; r_tlb_fsm = TLB_PTE2_SELECT; #if DEBUG_TLB_MISS if ( m_debug_activated ) std::cout << " Mapped" << std::hex << " / PTE_FLAGS = " << pte_flags << " / PTE_PPN = " << pte_ppn << std::endl; #endif break; } //////////////////////////// case TLB_PTE2_SELECT: // select a slot for PTE2 { size_t way; size_t set; r_iotlb.select( r_dma_cmd_vaddr.read(), false, // PTE2 &way, &set ); #ifdef INSTRUMENTATION m_cpt_iotlb_read++; #endif #if DEBUG_TLB_MISS if ( m_debug_activated ) { std::cout << " Select a slot in IOTLB:"; std::cout << " way = " << std::dec << way << " / set = " << set << std::endl; } #endif r_tlb_way = way; r_tlb_set = set; r_tlb_fsm = TLB_PTE2_UPDT; break; } /////////////////// case TLB_PTE2_UPDT: // write a new PTE2 in tlb // not necessary to treat the L/R bit { uint32_t pte_flags = r_tlb_pte_flags.read(); uint32_t pte_ppn = r_tlb_pte_ppn.read(); r_tlb_paddr = (vci_addr_t)( ((r_tlb_pte_ppn.read() & PPN2_MASK) << 12) | (r_dma_cmd_vaddr.read()& K_PAGE_OFFSET_MASK) ); // update TLB for a PTE2 r_iotlb.write( false, // 4K page pte_flags, pte_ppn, r_dma_cmd_vaddr.read(), r_tlb_way.read(), r_tlb_set.read(), 0 ); // nline = 0 #ifdef INSTRUMENTATION m_cpt_iotlb_write++; #endif #if DEBUG_TLB_MISS if ( m_debug_activated ) { std::cout << " write PTE2 in IOTLB"; std::cout << " / set = " << std::dec << r_tlb_set.read() << " / way = " << r_tlb_way.read() << std::endl; r_iotlb.printTrace(); } #endif // next state r_tlb_fsm = TLB_RETURN; break; } ////////////// case TLB_WAIT: // waiting completion of a miss transaction from MISS_WTI FSM // PTE inval request are handled as unmaskable interrupts { if ( r_config_tlb_req ) // Request from CONFIG FSM for a PTE invalidation { r_config_tlb_req = false; r_waiting_transaction = true; r_tlb_fsm = TLB_INVAL_CHECK; } #ifdef INSTRUMENTATION m_cost_iotlbmiss_transaction++; #endif if ( not r_tlb_miss_req ) // Miss transaction is done { if ( r_miss_wti_rsp_error.read() ) // bus error { r_miss_wti_rsp_error = false; r_tlb_miss_error = true; r_dma_tlb_req = false; r_tlb_fsm = TLB_IDLE; } else if(r_tlb_miss_type == PTE1_MISS) { r_tlb_fsm = TLB_PTE1_GET; } else { r_tlb_fsm = TLB_PTE2_GET; } } break; } //////////////// case TLB_RETURN: // reset r_dma_tlb_req flip-flop to signal TLB miss completion // possible errors are signaled through r_tlb_miss_error { #if DEBUG_TLB_MISS if ( m_debug_activated ) std::cout << " IOTLB MISS completed" << std::endl; #endif r_dma_tlb_req = false; r_tlb_fsm = TLB_IDLE; break; } ///////////////////// case TLB_INVAL_CHECK: // request from CONFIG_FSM to invalidate all PTE in a given line // checks the necessity to invalidate prefetch buffer { // If a transaction is pending, no need to invalidate the prefetch // We can ignore it, since we'll replace the line. // The new line is necessarily up-to-date if(!r_waiting_transaction.read() && r_tlb_buf_valid) { if(!r_tlb_buf_big_page) { if( r_tlb_buf_vaddr.read() == (r_config_cmd_inval_vaddr.read()& ~PTE2_LINE_OFFSET) ) // The virtual address corresponds to one entry on the buffer line { r_tlb_buf_valid = false; //change here for individual invalidation } } else // First level entries on buffer. Unused if only small pages { if( r_tlb_buf_vaddr.read() == (r_config_cmd_inval_vaddr.read()& ~PTE1_LINE_OFFSET) ) // The virtual address corresponds to one entry on the buffer line { r_tlb_buf_valid = false; //change here for individual invalidation } } } // Invalidation on IOTLB bool ok; ok = r_iotlb.inval(r_config_cmd_inval_vaddr.read()); if(r_waiting_transaction.read()) r_tlb_fsm =TLB_WAIT; else r_tlb_fsm = TLB_IDLE; break; } } //end switch r_tlb_fsm //////////////////////////////////////////////////////////////////////////////// // The CONFIG_CMD_FSM handles the VCI commands from the INT network. // This FSM is mainly intended to handle single flit config transactions, // but it can also handle software driven, multi-flits data transactions. // - The configuration requests can be local (IO_BRIDGE config registers) // or remote (config registers of peripherals on IOX network). // - The data requests are always remote. // In case of local config, this FSM put a VCI response in CONFIG_RSP fifo. // In case of remote transaction, it put the VCI command in CONFIG_CMD fifo. /////////////////////////////////////////////////////////////////////////////// switch( r_config_cmd_fsm.read() ) { ///////////////////// case CONFIG_CMD_IDLE: // waiting VCI command { if ( p_vci_tgt_int.cmdval.read() ) { #if DEBUG_CONFIG_CMD if( m_debug_activated ) std::cout << " Command received" << " / address = " << std::hex << p_vci_tgt_int.address.read() << " / srcid = " << std::dec << p_vci_tgt_int.srcid.read() << " / trdid = " << p_vci_tgt_int.trdid.read() << " / wdata = " << std::hex << p_vci_tgt_int.wdata.read() << " / be = " << p_vci_tgt_int.be.read() << " / plen = " << std::dec << p_vci_tgt_int.plen.read() << " / eop = " << p_vci_tgt_int.eop.read() << std::endl; #endif vci_addr_t paddr = p_vci_tgt_int.address.read(); bool read = (p_vci_tgt_int.cmd.read() == vci_param_int::CMD_READ); uint32_t cell = (uint32_t)((paddr & 0x1FF)>>2); // The "local" segment must be the first in the seglist soclib::common::Segment seg = m_int_seglist.front(); if ( seg.contains(paddr) ) // IO_BRIDGE itself { uint32_t rdata = 0; bool rerror = false; if ( not read && (cell == IOB_IOMMU_PTPR) ) // WRITE PTPR { r_iommu_ptpr = (uint32_t)p_vci_tgt_int.wdata.read(); } else if ( read && (cell == IOB_IOMMU_PTPR) ) // READ PTPR { rdata = r_iommu_ptpr.read(); } else if( not read && (cell == IOB_WTI_ENABLE)) // WRITE WTI_ENABLE { r_iommu_wti_enable = p_vci_tgt_int.wdata.read(); } else if( read && (cell == IOB_WTI_ENABLE)) // READ WTI ENABLE { rdata = r_iommu_wti_enable.read(); } else if( read && (cell == IOB_IOMMU_BVAR)) // READ BVAR { rdata = r_iommu_bvar.read(); } else if( read && (cell == IOB_IOMMU_ETR)) // READ ETR { rdata = r_iommu_etr.read(); } else if( read && (cell == IOB_IOMMU_BAD_ID)) // READ BAD_ID { rdata = r_iommu_bad_id.read(); } else if( not read && (cell == IOB_INVAL_PTE)) // WRITE INVAL_PTE { r_config_tlb_req = true; r_config_cmd_inval_vaddr = (uint32_t)p_vci_tgt_int.wdata.read(); } else if( not read && (cell == IOB_WTI_ADDR_LO)) // WRITE WTI_PADDR_LO { r_iommu_wti_paddr = (vci_addr_t)p_vci_tgt_int.wdata.read(); } else if( read && (cell == IOB_WTI_ADDR_LO)) // READ WTI_PADDR_LO { rdata = (uint32_t)r_iommu_wti_paddr.read(); } else if( not read && (cell == IOB_WTI_ADDR_HI)) // WRITE WTI_PADDR_HI { r_iommu_wti_paddr = (r_iommu_wti_paddr.read() & 0x00000000FFFFFFFFLL) | ((vci_addr_t)p_vci_tgt_int.wdata.read())<<32; } else if( read && (cell == IOB_WTI_ADDR_HI)) // READ WTI_PADDR_HI { rdata = (uint32_t)(r_iommu_wti_paddr.read()>>32); } else if( not read && ((cell >= IOB_PERI_WTI_BEGIN) // WRITE PERI WTI && (cell< (IOB_PERI_WTI_BEGIN + 64))) ) { size_t index = (cell - IOB_PERI_WTI_BEGIN)/2; bool high = (cell - IOB_PERI_WTI_BEGIN)%2; if ( high ) r_iommu_peri_wti[index] = // set 32 MSB bits (r_iommu_peri_wti[index].read() & 0x00000000FFFFFFFFLL) | ((vci_addr_t)p_vci_tgt_int.wdata.read())<<32; else r_iommu_peri_wti[index] = // set 32 LSB bits (vci_addr_t)p_vci_tgt_int.wdata.read(); } else if( read && ((cell >= IOB_PERI_WTI_BEGIN) // READ PERI WTI && (cell< (IOB_PERI_WTI_BEGIN + 64))) ) { size_t index = (cell - IOB_PERI_WTI_BEGIN)/2; bool high = (cell - IOB_PERI_WTI_BEGIN)%2; if ( high ) rdata = (uint32_t)(r_iommu_peri_wti[index].read()>>32); else rdata = (uint32_t)(r_iommu_peri_wti[index].read()); } else // Error: Wrong address, or invalid operation. { rerror = true; } r_config_cmd_rdata = rdata; r_config_cmd_error = rerror; r_config_cmd_fsm = CONFIG_CMD_FIFO_PUT_RSP; } else // remote peripheral { r_config_cmd_fsm = CONFIG_CMD_FIFO_PUT_CMD; } } // end if cmdval break; } ///////////////////////////// case CONFIG_CMD_FIFO_PUT_CMD: // transmit VCI command from the INT network // to the CONFIG_CMD fifo to IOX network { config_cmd_fifo_put = true; if ( p_vci_tgt_int.cmdval.read() and m_config_cmd_addr_fifo.wok() ) { #if DEBUG_CONFIG_CMD if( m_debug_activated ) std::cout << " Transmit VCI command to IOX network" << " : address = " << std::hex << p_vci_tgt_int.address.read() << " / srcid = " << p_vci_tgt_int.srcid.read() << std::endl; #endif if( p_vci_tgt_int.eop.read() ) r_config_cmd_fsm = CONFIG_CMD_IDLE; } break; } ///////////////////////////// case CONFIG_CMD_FIFO_PUT_RSP: // Try to put a response in CONFIG_RSP fifo, // for a local configuration transaction. // The FIFO is shared with CONFIG_RSP FSM // and must we wait for allocation... { if ( p_vci_tgt_int.cmdval.read() and r_alloc_fifo_config_rsp_local.read() ) { config_rsp_fifo_put = true; if ( m_config_rsp_data_fifo.wok() ) { #if DEBUG_CONFIG_CMD if( m_debug_activated ) std::cout << " Response to a local configuration request" << std::endl; #endif if( p_vci_tgt_int.eop.read() ) r_config_cmd_fsm = CONFIG_CMD_IDLE; } } break; } } // end switch CONFIG_CMD FSM ////////////////////////////////////////////////////////////////////////////// // The CONFIG_RSP_FSM handles the VCI responses from the periherals // on the IOX network and writes the responses in the CONFIG_RSP fifo. // The VCI response flit is only consumed in the FIFO_PUT state. // This FSM is mainly intended to handle single flit config transactions, // but it can also handle software driven, multi-flits data transactions. ////////////////////////////////////////////////////////////////////////////// switch( r_config_rsp_fsm.read() ) { ///////////////////// case CONFIG_RSP_IDLE: // waiting a VCI response from IOX network { if ( p_vci_ini_iox.rspval.read() ) { r_config_rsp_fsm = CONFIG_RSP_FIFO_PUT; } break; } ///////////////////////// case CONFIG_RSP_FIFO_PUT: // try to write into CONFIG_RSP fifo // as soon as it is allocated { if ( p_vci_ini_iox.rspval.read() and not r_alloc_fifo_config_rsp_local.read() ) { config_rsp_fifo_put = true; if ( m_config_rsp_data_fifo.wok() ) { if ( p_vci_ini_iox.reop.read() ) r_config_rsp_fsm = CONFIG_RSP_IDLE; #if DEBUG_CONFIG_RSP if( m_debug_activated ) std::cout << " Push response into CONFIG_RSP fifo:" << " / rsrcid = " << std::hex << p_vci_ini_iox.rsrcid.read() << " / rtrdid = " << p_vci_ini_iox.rtrdid.read() << " / rdata = " << p_vci_ini_iox.rdata.read() << " / reop = " << p_vci_ini_iox.reop.read() << " / rerror = " << p_vci_ini_iox.rerror.read() << std::endl; #endif } } break; } } // end switch CONFIG_RSP FSM ///////////////////////////////////////////////////////////////////////////////// // If the IOB component has IRQ ports, the IRQ FSM detects all changes // on the 32 p_irq[i] ports and request a VCI write transaction to the // MISS_INIT FSM, using the 64 r_irq_request[i] and r_irq_pending[i] flip-flops. ///////////////////////////////////////////////////////////////////////////////// if ( m_has_irqs ) { for ( size_t i = 0; i<32; ++i ) { r_irq_request[i] = ( p_irq[i]->read() == not r_irq_pending[i].read() ); r_irq_pending[i] = p_irq[i]->read(); } } /////////////////////////////////////////////////////////////////////////////////// // The MISS_WTI_CMD FSM send VCI commands on the Internal Network. // It handles PTE MISS requests from TLB_MISS FSM and software IRQs. // It supports several simultaneous VCI transactions. //////////////////////////////////////////////////////////////////////////////////// switch ( r_miss_wti_cmd_fsm.read() ) { /////////////////////// case MISS_WTI_CMD_IDLE: // TLB MISS have highest priority { if ( r_tlb_miss_req.read() ) { r_miss_wti_cmd_fsm = MISS_WTI_CMD_MISS; } else if ( r_iommu_wti_enable.read() ) { // checking if there is a new pending interrupt bool found = false; size_t n; for ( n = 0 ; (n < 32) and not found ; n++ ) { if ( r_irq_request[n] ) found = true; } if ( found ) { r_miss_wti_cmd_index = n; r_miss_wti_cmd_fsm = MISS_WTI_CMD_WTI; } } break; } ////////////////////// case MISS_WTI_CMD_WTI: // send a single flit IRQ WRITE on INT Network // address is defined by IRQ_VECTOR[r_miss_wti_index] // data is defined by r_irq_pending[r_miss_wti_index] { if ( p_vci_ini_int.cmdack ) { // reset the request r_irq_request[r_miss_wti_cmd_index.read()] = false; r_miss_wti_cmd_fsm = MISS_WTI_RSP_WTI; #if DEBUG_MISS_WTI if( m_debug_activated ) std::cout << " Send WTI write command on Internal Network" << " / IRQID = " << std::dec << r_miss_wti_cmd_index.read() << std::endl; #endif } break; } /////////////////////// case MISS_WTI_CMD_MISS: // send a TLB MISS request on INT Network { if ( p_vci_ini_int.cmdack ) { r_tlb_buf_tag = ( (r_tlb_paddr.read()) & CACHE_LINE_MASK ); r_tlb_buf_valid = true; if( r_tlb_miss_type.read() == PTE1_MISS ) r_tlb_buf_vaddr = (r_dma_cmd_vaddr.read() & ~M_PAGE_OFFSET_MASK & ~PTE1_LINE_OFFSET); else r_tlb_buf_vaddr = (r_dma_cmd_vaddr.read() & ~K_PAGE_OFFSET_MASK & ~PTE2_LINE_OFFSET); r_miss_wti_cmd_fsm = MISS_WTI_RSP_MISS; #if DEBUG_MISS_WTI if( m_debug_activated ) std::cout << " Send TLB MISS command on Internal Network" << std::hex << " / address = " <<(vci_addr_t)((r_tlb_paddr.read())& CACHE_LINE_MASK) << std::endl; #endif } break; } } // end switch r_miss_wti_cmd_fsm /////////////////////////////////////////////////////////////////////////////////// // The MISS_WTI_RSP FSM handles VCI responses on the Internal Network. // it can be response to TLB MISS (read transaction) or WTI (write transaction). // It supports several simultaneous VCI transactions. //////////////////////////////////////////////////////////////////////////////////// switch ( r_miss_wti_rsp_fsm.read() ) { case MISS_WTI_RSP_IDLE: // waiting a VCI response { if ( p_vci_ini_int.rspval.read() ) { if ( p_vci_ini_int.rpktid.read() == PKTID_READ ) // it's a TLB MISS response { r_miss_wti_rsp_fsm = MISS_WTI_RSP_MISS; r_miss_wti_rsp_count = 0; } else // it's a WTI WRITE response { r_miss_wti_rsp_fsm = MISS_WTI_RSP_WTI; } } break; } ////////////////////// case MISS_WTI_RSP_WTI: // Handling response to a WTI transaction { assert( p_vci_ini_int.reop.read() and "VCI_IO_BRIDGE ERROR: IRQ Write response should have one single flit" ); assert( ( (p_vci_ini_int.rerror.read()&0x1) == 0 ) and "VCI_IO_BRIDGE ERROR: IRQ Write response error !!!" ); // TODO traiter error using the IOMMU IRQ #if DEBUG_MISS_WTI if( m_debug_activated ) std::cout << " Response to WTI write" << std::endl; #endif r_miss_wti_rsp_fsm = MISS_WTI_RSP_IDLE; break; } /////////////////////// case MISS_WTI_RSP_MISS: // Handling response to a TLB MISS transaction { if ( p_vci_ini_int.rspval.read() ) { if ( (p_vci_ini_int.rerror.read()&0x1) != 0 ) // error reported { r_miss_wti_rsp_error = true; if ( p_vci_ini_int.reop.read() ) { r_miss_wti_cmd_fsm = MISS_WTI_RSP_IDLE; r_tlb_miss_req = false; } #if DEBUG_MISS_WTI if( m_debug_activated ) std::cout << " ERROR " << std::endl; #endif } else // no error { bool eop = p_vci_ini_int.reop.read(); #if DEBUG_MISS_WTI if( m_debug_activated ) std::cout << " Response to a tlb miss transaction" << " / Count = " << r_miss_wti_rsp_count.read() << " / Data = " << std::hex << p_vci_ini_int.rdata.read() << std::endl; #endif assert(((eop == (r_miss_wti_rsp_count.read() == (m_words-1)))) and "VCI_IO_BRIDGE ERROR: invalid length for a TLB MISS response"); r_tlb_buf_data[r_miss_wti_rsp_count.read()] = p_vci_ini_int.rdata.read(); r_miss_wti_rsp_count = r_miss_wti_rsp_count.read() + 1; if ( eop ) { r_tlb_miss_req = false; //reset the request flip-flop r_miss_wti_cmd_fsm = MISS_WTI_RSP_IDLE; } } } break; } } // end switch r_miss_wti_rsp_fsm ///////////////////////////////////////////////////////////////////////// // This flip-flop allocates the access to the CONFIG_RSP fifo // with a round robin priority between 2 clients FSMs : // - CONFIG_CMD : to put a response to a local config command. // - CONFIG_RSP : to put a response to a peripheral config command. // The ressource is always allocated. // A new allocation occurs when the owner FSM is not using it, // and the other FSM is requiring it. ///////////////////////////////////////////////////////////////////////// if ( r_alloc_fifo_config_rsp_local.read() ) { if ( (r_config_rsp_fsm.read() == CONFIG_RSP_FIFO_PUT) and (r_config_cmd_fsm.read() != CONFIG_CMD_FIFO_PUT_RSP) ) r_alloc_fifo_config_rsp_local = false; } else { if ( (r_config_cmd_fsm.read() == CONFIG_CMD_FIFO_PUT_RSP) and (r_config_rsp_fsm.read() != CONFIG_RSP_FIFO_PUT) ) r_alloc_fifo_config_rsp_local = true; } ///////////////////////////////////////////////////////////////////////// // This flip-flop allocates the access to the DMA_RSP fifo // with a round robin priority between 2 clients FSMs : // - DMA_CMD : to put a error response in case of bad address translation // - DMA_RSP : to put a normal response to a DMA transaction. // The ressource is always allocated. // A new allocation occurs when the owner FSM is not using it, // and the other FSM is requiring it. ///////////////////////////////////////////////////////////////////////// if ( r_alloc_fifo_dma_rsp_local.read() ) { if ( (r_dma_rsp_fsm.read() == DMA_RSP_FIFO_PUT) and (r_dma_cmd_fsm.read() != DMA_CMD_FIFO_PUT_RSP) ) r_alloc_fifo_dma_rsp_local = false; } else { if ( (r_dma_cmd_fsm.read() == DMA_CMD_FIFO_PUT_RSP) and (r_dma_rsp_fsm.read() != DMA_RSP_FIFO_PUT) ) r_alloc_fifo_dma_rsp_local = true; } // Define GET signals for all output FIFOs dma_cmd_fifo_get = p_vci_ini_ram.cmdack.read(); dma_rsp_fifo_get = p_vci_tgt_iox.rspack.read(); config_cmd_fifo_get = p_vci_ini_iox.cmdack.read(); config_rsp_fifo_get = p_vci_tgt_int.rspack.read(); /////////////////////////////////////////////////////////// // DMA_CMD fifo update // One writer : DMA_CMD FSM /////////////////////////////////////////////////////////// m_dma_cmd_addr_fifo.update( dma_cmd_fifo_get, dma_cmd_fifo_put, r_dma_cmd_paddr.read() ); // address translation m_dma_cmd_cmd_fifo.update( dma_cmd_fifo_get, dma_cmd_fifo_put, p_vci_tgt_iox.cmd.read() ); m_dma_cmd_contig_fifo.update( dma_cmd_fifo_get, dma_cmd_fifo_put, p_vci_tgt_iox.contig.read() ); m_dma_cmd_cons_fifo.update( dma_cmd_fifo_get, dma_cmd_fifo_put, p_vci_tgt_iox.cons.read() ); m_dma_cmd_plen_fifo.update( dma_cmd_fifo_get, dma_cmd_fifo_put, p_vci_tgt_iox.plen.read() ); m_dma_cmd_wrap_fifo.update( dma_cmd_fifo_get, dma_cmd_fifo_put, p_vci_tgt_iox.wrap.read() ); m_dma_cmd_cfixed_fifo.update( dma_cmd_fifo_get, dma_cmd_fifo_put, p_vci_tgt_iox.cfixed.read() ); m_dma_cmd_clen_fifo.update( dma_cmd_fifo_get, dma_cmd_fifo_put, p_vci_tgt_iox.clen.read() ); m_dma_cmd_srcid_fifo.update( dma_cmd_fifo_get, dma_cmd_fifo_put, p_vci_tgt_iox.srcid.read() ); m_dma_cmd_trdid_fifo.update( dma_cmd_fifo_get, dma_cmd_fifo_put, p_vci_tgt_iox.trdid.read() ); m_dma_cmd_pktid_fifo.update( dma_cmd_fifo_get, dma_cmd_fifo_put, p_vci_tgt_iox.pktid.read() ); m_dma_cmd_data_fifo.update( dma_cmd_fifo_get, dma_cmd_fifo_put, p_vci_tgt_iox.wdata.read() ); m_dma_cmd_be_fifo.update( dma_cmd_fifo_get, dma_cmd_fifo_put, p_vci_tgt_iox.be.read() ); m_dma_cmd_eop_fifo.update( dma_cmd_fifo_get, dma_cmd_fifo_put, p_vci_tgt_iox.eop.read() ); ////////////////////////////////////////////////////////////// // DMA_RSP fifo update // Two writers : DMA_CMD FSM & DMA_RSP FSM ////////////////////////////////////////////////////////////// if (r_alloc_fifo_dma_rsp_local.read() ) // owner is DMA_CMD FSM // local response for a translation error { m_dma_rsp_data_fifo.update( dma_rsp_fifo_get, dma_rsp_fifo_put, 0 ); // no data if error m_dma_rsp_rsrcid_fifo.update( dma_rsp_fifo_get, dma_rsp_fifo_put, p_vci_tgt_iox.rsrcid.read() ); m_dma_rsp_rtrdid_fifo.update( dma_rsp_fifo_get, dma_rsp_fifo_put, p_vci_tgt_iox.rtrdid.read() ); m_dma_rsp_rpktid_fifo.update( dma_rsp_fifo_get, dma_rsp_fifo_put, p_vci_tgt_iox.rpktid.read() ); m_dma_rsp_reop_fifo.update( dma_rsp_fifo_get, dma_rsp_fifo_put, true ); // single flit response m_dma_rsp_rerror_fifo.update( dma_rsp_fifo_get, dma_rsp_fifo_put, 1 ); // error } else // owner is DMA_RSP FSM // normal response to a DMA transaction { m_dma_rsp_data_fifo.update( dma_rsp_fifo_get, dma_rsp_fifo_put, p_vci_ini_ram.rdata.read() ); m_dma_rsp_rsrcid_fifo.update( dma_rsp_fifo_get, dma_rsp_fifo_put, p_vci_ini_ram.rsrcid.read() ); m_dma_rsp_rtrdid_fifo.update( dma_rsp_fifo_get, dma_rsp_fifo_put, p_vci_ini_ram.rtrdid.read() ); m_dma_rsp_rpktid_fifo.update( dma_rsp_fifo_get, dma_rsp_fifo_put, p_vci_ini_ram.rpktid.read() ); m_dma_rsp_reop_fifo.update( dma_rsp_fifo_get, dma_rsp_fifo_put, p_vci_ini_ram.reop.read() ); m_dma_rsp_rerror_fifo.update( dma_rsp_fifo_get, dma_rsp_fifo_put, p_vci_ini_ram.rerror.read() ); } //////////////////////////////////////////////////////////////// // CONFIG_CMD fifo update // One writer : CONFIG_CMD FSM //////////////////////////////////////////////////////////////// m_config_cmd_addr_fifo.update( config_cmd_fifo_get, config_cmd_fifo_put, p_vci_tgt_int.address.read() ); m_config_cmd_cmd_fifo.update( config_cmd_fifo_get, config_cmd_fifo_put, p_vci_tgt_int.cmd.read() ); m_config_cmd_contig_fifo.update( config_cmd_fifo_get, config_cmd_fifo_put, p_vci_tgt_int.contig.read() ); m_config_cmd_cons_fifo.update( config_cmd_fifo_get, config_cmd_fifo_put, p_vci_tgt_int.cons.read() ); m_config_cmd_plen_fifo.update( config_cmd_fifo_get, config_cmd_fifo_put, p_vci_tgt_int.plen.read() ); m_config_cmd_wrap_fifo.update( config_cmd_fifo_get, config_cmd_fifo_put, p_vci_tgt_int.wrap.read() ); m_config_cmd_cfixed_fifo.update( config_cmd_fifo_get, config_cmd_fifo_put, p_vci_tgt_int.cfixed.read() ); m_config_cmd_clen_fifo.update( config_cmd_fifo_get, config_cmd_fifo_put, p_vci_tgt_int.clen.read() ); m_config_cmd_srcid_fifo.update( config_cmd_fifo_get, config_cmd_fifo_put, p_vci_tgt_int.srcid.read() ); m_config_cmd_trdid_fifo.update( config_cmd_fifo_get, config_cmd_fifo_put, p_vci_tgt_int.trdid.read() ); m_config_cmd_pktid_fifo.update( config_cmd_fifo_get, config_cmd_fifo_put, p_vci_tgt_int.pktid.read() ); m_config_cmd_data_fifo.update( config_cmd_fifo_get, config_cmd_fifo_put, (ext_data_t)p_vci_tgt_int.wdata.read() ); m_config_cmd_be_fifo.update( config_cmd_fifo_get, config_cmd_fifo_put, p_vci_tgt_int.be.read() ); m_config_cmd_eop_fifo.update( config_cmd_fifo_get, config_cmd_fifo_put, p_vci_tgt_int.eop.read() ); ////////////////////////////////////////////////////////////////////////// // CONFIG_RSP fifo update // There is two writers : CONFIG_CMD FSM & CONFIG_RSP FSM ////////////////////////////////////////////////////////////////////////// if ( r_alloc_fifo_config_rsp_local.read() ) // owner is CONFIG_CMD FSM // response for a local config transaction { m_config_rsp_data_fifo.update( config_rsp_fifo_get, config_rsp_fifo_put, (int_data_t)r_config_cmd_rdata.read() ); m_config_rsp_rsrcid_fifo.update( config_rsp_fifo_get, config_rsp_fifo_put, p_vci_tgt_int.srcid.read() ); m_config_rsp_rtrdid_fifo.update( config_rsp_fifo_get, config_rsp_fifo_put, p_vci_tgt_int.trdid.read() ); m_config_rsp_rpktid_fifo.update( config_rsp_fifo_get, config_rsp_fifo_put, p_vci_tgt_int.pktid.read() ); m_config_rsp_reop_fifo.update( config_rsp_fifo_get, config_rsp_fifo_put, true ); // local config are one flit m_config_rsp_rerror_fifo.update( config_rsp_fifo_get, config_rsp_fifo_put, r_config_cmd_error.read() ); } else // owner is CONFIG_RSP FSM // response for a remote transaction { m_config_rsp_data_fifo.update( config_rsp_fifo_get, config_rsp_fifo_put, (int_data_t)p_vci_ini_iox.rdata.read() ); m_config_rsp_rsrcid_fifo.update( config_rsp_fifo_get, config_rsp_fifo_put, p_vci_ini_iox.rsrcid.read() ); m_config_rsp_rtrdid_fifo.update( config_rsp_fifo_get, config_rsp_fifo_put, p_vci_ini_iox.rtrdid.read() ); m_config_rsp_rpktid_fifo.update( config_rsp_fifo_get, config_rsp_fifo_put, p_vci_ini_iox.rpktid.read() ); m_config_rsp_reop_fifo.update( config_rsp_fifo_get, config_rsp_fifo_put, p_vci_ini_iox.reop.read() ); m_config_rsp_rerror_fifo.update( config_rsp_fifo_get, config_rsp_fifo_put, p_vci_ini_iox.rerror.read() ); } } // end transition() /////////////////////// tmpl(void)::genMoore() /////////////////////// { // VCI initiator command on RAM network // directly the content of the dma_cmd FIFO p_vci_ini_ram.cmdval = m_dma_cmd_addr_fifo.rok(); p_vci_ini_ram.address = m_dma_cmd_addr_fifo.read(); p_vci_ini_ram.be = m_dma_cmd_be_fifo.read(); p_vci_ini_ram.cmd = m_dma_cmd_cmd_fifo.read(); p_vci_ini_ram.contig = m_dma_cmd_contig_fifo.read(); p_vci_ini_ram.wdata = m_dma_cmd_data_fifo.read(); p_vci_ini_ram.eop = m_dma_cmd_eop_fifo.read(); p_vci_ini_ram.cons = m_dma_cmd_cons_fifo.read(); p_vci_ini_ram.plen = m_dma_cmd_plen_fifo.read(); p_vci_ini_ram.wrap = m_dma_cmd_wrap_fifo.read(); p_vci_ini_ram.cfixed = m_dma_cmd_cfixed_fifo.read(); p_vci_ini_ram.clen = m_dma_cmd_clen_fifo.read(); p_vci_ini_ram.trdid = m_dma_cmd_trdid_fifo.read(); p_vci_ini_ram.pktid = m_dma_cmd_pktid_fifo.read(); p_vci_ini_ram.srcid = m_dma_cmd_srcid_fifo.read(); // VCI target command ack on IOX network // depends on the DMA_CMD FSM state switch ( r_dma_cmd_fsm.read() ) { case DMA_CMD_IDLE: case DMA_CMD_MISS_WAIT: p_vci_tgt_iox.cmdack = false; break; case DMA_CMD_WAIT_EOP: p_vci_tgt_iox.cmdack = true; break; case DMA_CMD_FIFO_PUT_CMD: p_vci_tgt_iox.cmdack = m_dma_cmd_addr_fifo.wok(); break; case DMA_CMD_FIFO_PUT_RSP: p_vci_tgt_iox.cmdack = m_dma_rsp_data_fifo.wok(); break; }// end switch r_dma_cmd_fsm // VCI target response on IOX network // directly the content of the DMA_RSP FIFO p_vci_tgt_iox.rspval = m_dma_rsp_data_fifo.rok(); p_vci_tgt_iox.rsrcid = m_dma_rsp_rsrcid_fifo.read(); p_vci_tgt_iox.rtrdid = m_dma_rsp_rtrdid_fifo.read(); p_vci_tgt_iox.rpktid = m_dma_rsp_rpktid_fifo.read(); p_vci_tgt_iox.rdata = m_dma_rsp_data_fifo.read(); p_vci_tgt_iox.rerror = m_dma_rsp_rerror_fifo.read(); p_vci_tgt_iox.reop = m_dma_rsp_reop_fifo.read(); // VCI initiator response on the RAM Network // depends on the DMA_RSP FSM state p_vci_ini_ram.rspack = m_dma_rsp_data_fifo.wok() and (r_dma_rsp_fsm.read() == DMA_RSP_FIFO_PUT) and not r_alloc_fifo_dma_rsp_local.read(); // VCI initiator command on IOX network // directly the content of the CONFIG_CMD FIFO p_vci_ini_iox.cmdval = m_config_cmd_addr_fifo.rok(); p_vci_ini_iox.address = m_config_cmd_addr_fifo.read(); p_vci_ini_iox.be = m_config_cmd_be_fifo.read(); p_vci_ini_iox.cmd = m_config_cmd_cmd_fifo.read(); p_vci_ini_iox.contig = m_config_cmd_contig_fifo.read(); p_vci_ini_iox.wdata = (ext_data_t)m_config_cmd_data_fifo.read(); p_vci_ini_iox.eop = m_config_cmd_eop_fifo.read(); p_vci_ini_iox.cons = m_config_cmd_cons_fifo.read(); p_vci_ini_iox.plen = m_config_cmd_plen_fifo.read(); p_vci_ini_iox.wrap = m_config_cmd_wrap_fifo.read(); p_vci_ini_iox.cfixed = m_config_cmd_cfixed_fifo.read(); p_vci_ini_iox.clen = m_config_cmd_clen_fifo.read(); p_vci_ini_iox.trdid = m_config_cmd_trdid_fifo.read(); p_vci_ini_iox.pktid = m_config_cmd_pktid_fifo.read(); p_vci_ini_iox.srcid = m_config_cmd_srcid_fifo.read(); // VCI target command ack on INT network // it depends on the CONFIG_CMD FSM state switch ( r_config_cmd_fsm.read() ) { case CONFIG_CMD_IDLE: p_vci_tgt_int.cmdack = false; break; case CONFIG_CMD_FIFO_PUT_CMD: p_vci_tgt_int.cmdack = m_config_cmd_addr_fifo.wok(); break; case CONFIG_CMD_FIFO_PUT_RSP: p_vci_tgt_int.cmdack = m_config_rsp_data_fifo.wok() and r_alloc_fifo_config_rsp_local.read(); break; }// end switch r_config_cmd_fsm // VCI target response on INT network // directly the content of the CONFIG_RSP FIFO p_vci_tgt_int.rspval = m_config_rsp_data_fifo.rok(); p_vci_tgt_int.rsrcid = m_config_rsp_rsrcid_fifo.read(); p_vci_tgt_int.rtrdid = m_config_rsp_rtrdid_fifo.read(); p_vci_tgt_int.rpktid = m_config_rsp_rpktid_fifo.read(); p_vci_tgt_int.rdata = m_config_rsp_data_fifo.read(); p_vci_tgt_int.rerror = m_config_rsp_rerror_fifo.read(); p_vci_tgt_int.reop = m_config_rsp_reop_fifo.read(); // VCI initiator response on IOX Network // it depends on the CONFIG_RSP FSM state p_vci_ini_iox.rspack = m_config_rsp_data_fifo.wok() and (r_config_rsp_fsm.read() == CONFIG_RSP_FIFO_PUT) and not r_alloc_fifo_config_rsp_local.read(); // VCI initiator command on INT network // it depends on the MISS_WTI_CMD FSM state // default values p_vci_ini_int.srcid = m_int_srcid; p_vci_ini_int.trdid = 0; p_vci_ini_int.cfixed = false; p_vci_ini_int.eop = true; p_vci_ini_int.wrap = false; p_vci_ini_int.clen = 0; p_vci_ini_int.contig = false; p_vci_ini_int.cons = true; p_vci_ini_int.be = 0xFF; switch ( r_miss_wti_cmd_fsm.read() ) { case MISS_WTI_CMD_IDLE: p_vci_ini_int.cmdval = false; p_vci_ini_int.address = 0; p_vci_ini_int.cmd = vci_param_int::CMD_NOP; p_vci_ini_int.pktid = PKTID_READ; p_vci_ini_int.wdata = 0; p_vci_ini_int.plen = 0; break; case MISS_WTI_CMD_WTI: p_vci_ini_int.cmdval = true; p_vci_ini_int.address = r_iommu_peri_wti[r_miss_wti_cmd_index.read()].read(); p_vci_ini_int.cmd = vci_param_int::CMD_WRITE; p_vci_ini_int.pktid = PKTID_WRITE; p_vci_ini_int.wdata = (int_data_t)r_irq_pending[r_miss_wti_cmd_index.read()].read(); p_vci_ini_int.plen = vci_param_int::B; break; case MISS_WTI_CMD_MISS: p_vci_ini_int.cmdval = true; p_vci_ini_int.address = r_tlb_paddr.read() & CACHE_LINE_MASK; p_vci_ini_int.cmd = vci_param_int::CMD_READ; p_vci_ini_int.pktid = PKTID_READ; p_vci_ini_int.wdata = 0; p_vci_ini_int.plen = m_words*(vci_param_int::B); break; } // VCI initiator response on INT network // It depends on the MISS_WTI_RSP FSM state if ( r_miss_wti_rsp_fsm.read() == MISS_WTI_RSP_IDLE ) p_vci_ini_int.rspack = false; else p_vci_ini_int.rspack = true; } // end genMoore }} // 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