LCOV - code coverage report
Current view: top level - src - decoder.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 128 157 81.5 %
Date: 2025-09-09 12:09:29 Functions: 8 8 100.0 %

          Line data    Source code
       1             : #include "decoder.hpp"
       2             : #include "log.hpp"
       3             : #include "publisher.hpp"
       4             : #include "device.hpp"
       5             : #include "tohost_monitor.hpp"
       6             : #include <cstdint>
       7             : #include <functional>
       8             : 
       9             : 
      10          40 : Decoder::Decoder(const Elink &elink, Publisher &publisher, flx_tohost_format fmt,
      11          40 :     int l0id_decoder_fmt, unsigned int block_size, uint64_t buf_vaddr) :
      12          40 :         m_stats(elink.fid), m_elink(elink), m_publisher(publisher),
      13          40 :         m_buffer_vaddr(buf_vaddr), m_block_size(block_size)
      14             : {
      15          40 :     switch (fmt) {
      16          37 :         case flx_tohost_format::TOHOST_SUBCHUNK_TRAILER:
      17   611956462 :             m_decode = [this](Block& b){return decode_subchunk_trailers(b);};
      18          37 :             break;
      19           3 :         case flx_tohost_format::TOHOST_SUBCHUNK_HEADER:
      20         664 :             m_decode = [this](Block& b){return decode_subchunk_headers(b);};
      21           3 :             break;
      22           0 :         default:
      23           0 :             LOG_ERR("ToHost data format %d not recognised. Assuming TOHOST_SUBCHUNK_TRAILER");
      24           0 :             m_decode = [this](Block& b){return decode_subchunk_trailers(b);};
      25             :     }
      26             : 
      27          40 :     if ( l0id_decoder_fmt > 0 ){
      28           0 :         if (elink.type  == elink_type_t::TTC) {
      29           0 :             m_l0id_checker = std::make_unique<L0Decoder>(L0Decoder(elink.fid, 1)); 
      30             :         }
      31           0 :         else if (elink.type  == elink_type_t::DAQ) {
      32           0 :             m_l0id_checker = std::make_unique<L0Decoder>(L0Decoder(elink.fid, l0id_decoder_fmt)); 
      33             :         }
      34             :     }
      35          40 : }
      36             : 
      37             : 
      38   605362571 : Publisher::Result Decoder::check_block_integrity(Block & block)
      39             : {
      40             : #if REGMAP_VERSION < 0x0500
      41             :     uint16_t* marker_word = (uint16_t*)(&block);
      42             :     if (block.marker != 0xABCD and marker_word[0] != marker_word[1])
      43             :     {
      44             :         LOG_ERR("Received invalid block header 0x%x. Block discarded.", block.marker);
      45             :         m_stats.increment_dropped_blocks();
      46             :         return Publisher::DECODING_ERROR;
      47             :     }
      48             : #else
      49   605362571 :     unsigned bsize = (block.marker == 0xABCD) ? 1024 : ((block.marker >> 8) - 0xC0 + 1) * 1024;
      50   605362571 :     if (bsize != m_block_size) {
      51           0 :         LOG_ERR("received block header 0x%x with irregular block size %d, expected %d. Block discarded.",
      52             :             block.marker, bsize, m_block_size);
      53           0 :             m_stats.increment_dropped_blocks();
      54           0 :             return Publisher::DECODING_ERROR;
      55             :         }
      56             : #endif
      57             :     //Sequence number check
      58   605362571 :     uint8_t expected_seqnr = (m_last_seqnr + 1) % 32;
      59   605362571 :     if(block.sequence_number != expected_seqnr)
      60             :     {
      61     3850666 :         if(!(m_seqnr_err++ % 100)){
      62       45138 :             LOG_DBG("received wrong sequence number: %d instead of %d (E-link: %d)",
      63             :             block.sequence_number, expected_seqnr, block.elink);
      64             :         }
      65             :     }
      66   605362571 :     m_last_seqnr = block.sequence_number;
      67   605362571 :     m_last_block = (reinterpret_cast<uint64_t>(&block) - m_buffer_vaddr) & 0xffffffff;
      68   605362571 :     return Publisher::Result::OK;
      69             : }
      70             : 
      71   612002670 : Publisher::Result Decoder::decode(Block & block)
      72             : {
      73   612002670 :     return m_decode(block);
      74             : }
      75             : 
      76             : 
      77         661 : Publisher::Result Decoder::decode_subchunk_headers(Block & block)
      78             : {
      79         661 :     using subchunk_header_t = subchunk_trailer_t;
      80             : 
      81         661 :     const bool first_time_decoding = (m_chunk_position == 0);
      82             : 
      83         661 :     if (first_time_decoding) {
      84         661 :         auto ret = check_block_integrity(block);
      85         661 :         if (ret == Publisher::Result::DECODING_ERROR) {
      86             :             return ret;
      87             :         }
      88             :     }
      89             : 
      90        1596 :     Publisher::Result r = Publisher::OK;
      91        2531 :     while (true) {
      92        1596 :         const auto chunk_header = *reinterpret_cast<subchunk_header_t*>(block.data + m_chunk_position);
      93             : 
      94        1596 :         uint16_t subchk_size = chunk_header.data.length;
      95        1596 :         uint16_t length = subchk_size + sizeof(subchunk_header_t) + (-subchk_size % sizeof(subchunk_header_t));
      96        1596 :         uint16_t next = m_chunk_position + length;
      97             : 
      98        1596 :         if (next > sizeof(block.data)) {
      99           0 :             LOG_ERR("Block 0x%lx of fid 0x%lx (elink 0x%x) discarded due to broken chunk length %u. Next position %u, header value 0x%x",
     100             :                         &block, m_elink.fid, m_elink.lid, length, next, chunk_header.value);
     101           0 :             m_chunk_position = 0;
     102           0 :             m_stats.increment_processed_blocks();
     103           0 :             return Publisher::DECODING_ERROR;
     104             :         }
     105        1596 :         uint8_t fw_flags = (chunk_header.data.trunc) | (chunk_header.data.err << 2) | (chunk_header.data.crcerr << 3);
     106        3192 :         r = post_subchunk(block.data + m_chunk_position + sizeof(subchunk_header_t),
     107             :             subchk_size,
     108        1596 :             static_cast<Decoder::SubchunkType>(chunk_header.data.type),
     109             :             fw_flags);
     110             : 
     111        1596 :         if (r == Publisher::AGAIN or r == Publisher::PARTIAL) {
     112             :             return r;
     113             :         }
     114             : 
     115        1596 :         if (r == Publisher::DECODING_ERROR) {
     116           0 :             m_scratch.clear();
     117           0 :             break;
     118             :         }
     119             : 
     120        1596 :         if (r == Publisher::ERROR) {
     121           0 :             m_scratch.clear();
     122             :         }
     123             : 
     124        1596 :         if (next == sizeof(block.data)) {
     125         661 :             if(m_elink.type == elink_type_t::TTC){
     126         658 :                 m_publisher.flush(m_elink.fid);
     127             :             }
     128             :             break;
     129             :         }
     130             : 
     131         935 :         m_chunk_position = next;
     132         935 :     }
     133             : 
     134         661 :     m_stats.increment_processed_blocks();
     135         661 :     m_chunk_position = 0;
     136         661 :     return r;
     137             : }
     138             : 
     139             : 
     140   611936227 : Publisher::Result Decoder::decode_subchunk_trailers(Block & block)
     141             : {
     142             :     //No chunks already decoded waiting to be sent
     143   611936227 :     if (m_subchunks.empty()) {
     144             :         
     145   605374576 :         auto ret = check_block_integrity(block);
     146   605307455 :         if (ret != Publisher::Result::OK){
     147             :             return ret;
     148             :         }
     149             : 
     150             :         //Starting from the end of the block, save location of all subchunk trailers
     151   605307455 :         int pos = m_block_size - BLOCK_HEADER_SIZE;
     152   605307455 :         unsigned int trailer_size = sizeof(subchunk_trailer_t);
     153  2401775859 :         while (pos > 0) {
     154  1796605029 :             subchunk_trailer_t trailer = *(reinterpret_cast<subchunk_trailer_t*>(block.data + pos - trailer_size));
     155             : 
     156             : #if REGMAP_VERSION < 0x0500
     157             :             // Check for FE BUSY
     158             :             if (trailer.value == 0xE05C) {
     159             :                 pos -= sizeof(subchunk_trailer_t);
     160             :                 trailer = *(reinterpret_cast<subchunk_trailer_t*>(block.data + pos - trailer_size));
     161             :             }
     162             : #endif
     163  1796605029 :             uint32_t length = trailer.data.length;
     164             :             //padding: (-length % trailer_size)
     165  1796605029 :             pos -= length + trailer_size + (-length % trailer_size);
     166  1796605029 :             if (pos < 0) {
     167           0 :                 LOG_ERR("Block 0x%lx of fid 0x%lx (elink 0x%x) discarded due to broken chunk length %u. Decoding position %u, trailer value 0x%x",
     168             :                         block.data, m_elink.fid, m_elink.lid, length, pos, trailer.value);
     169           0 :                 return Publisher::DECODING_ERROR;
     170             :             }
     171             : 
     172  1796605029 :             SubchunkType t = (SubchunkType)trailer.data.type;
     173             : 
     174  1796605029 :             if ((t == TIMEOUT and !trailer.data.trunc) or t == NIL or t == OOB) {
     175   773113001 :                 continue;
     176             :             }
     177             : 
     178  1023492028 :             uint16_t p = static_cast<uint16_t>(pos);
     179  1023492028 :             m_subchunks.emplace_back(p, trailer.value);
     180             :         }
     181             :     }
     182             : 
     183             :     //Process and publish subchunks
     184  1635345680 :     while (not m_subchunks.empty()) {
     185  1029950467 :         const auto & sc = m_subchunks[m_subchunks.size() - 1];
     186  1029950467 :         subchunk_trailer_t tr;
     187  1029950467 :         tr.value = sc.second;
     188  1029950467 :         uint8_t fw_flags = (tr.data.trunc) | (tr.data.err << 2) | (tr.data.crcerr << 3);
     189  1029950467 :         auto r = post_subchunk(block.data + sc.first, tr.data.length, (Decoder::SubchunkType)tr.data.type, fw_flags);
     190  1030199783 :         if (r == Publisher::AGAIN) {
     191     6598607 :             return r;
     192             :         }
     193  1023601176 :         if (r == Publisher::ERROR) {
     194           0 :             m_stats.increment_dropped_blocks();
     195           0 :             m_subchunks.clear();
     196           0 :             m_scratch.clear();
     197           0 :             return r;
     198             :         }
     199  1023601176 :         m_subchunks.resize(m_subchunks.size() - 1);
     200  1023613199 :         if(m_elink.type == elink_type_t::TTC && m_subchunks.empty()){
     201    12463992 :             m_publisher.flush(m_elink.fid);
     202             :         }
     203             :     }
     204             : 
     205   605395213 :     m_stats.increment_processed_blocks();
     206   605395213 :     return Publisher::OK;
     207             : }
     208             : 
     209             : 
     210   775714178 : void Decoder::on_successful_send()
     211             : {
     212   775714178 :     m_stats.update_processed_chunk(m_scratch.get_status_byte(), m_scratch.byte_size());
     213   775711068 :     if (m_l0id_checker) {
     214           0 :         if ( m_l0id_checker->check_tohost_chunk(m_scratch.iov) ) {
     215           0 :             m_stats.increment_oosequence_l0id();
     216             :         }
     217             :     }
     218   775711068 :     if ( m_elink.has_streams ){ m_elink.fid &= 0xFFFFFFFFFFFFFF00; }
     219   775711068 :     m_scratch.clear();
     220   775705090 : }
     221             : 
     222             : 
     223             : /**
     224             :  * If this function returns AGAIN then it is guaranteed that
     225             :  * the current subchunk was not processed and must be submitted again
     226             :  */
     227  1030477695 : Publisher::Result Decoder::post_subchunk(
     228             :     uint8_t* data, uint32_t length, SubchunkType type, uint8_t fw_flags)
     229             : {
     230             :     //First switch case mostly addresses error conditions
     231  1030477695 :     switch(type) {
     232   807977197 :         case FIRST:
     233   807977197 :         case WHOLE:
     234   807977197 :         if (not m_scratch.empty()) {
     235             :             //If scratch space not empty mark trucantion and publish leftover
     236    33193528 :             m_scratch.update_status_byte(SW_TRUNC);
     237    33193528 :             auto r = m_publisher.publish(m_elink.fid, m_scratch.iov_addr(), m_scratch.iov_len(), m_scratch.byte_size(), m_last_block, m_scratch.get_status_byte());
     238    33193528 :             if (Publisher::OK != r) {
     239             :                 return r;
     240             :             } else {
     241     1371089 :                 on_successful_send();
     242             :             }
     243             :         }
     244             :         break;
     245             : 
     246             : 
     247   222499838 :         case LAST:
     248   222499838 :         case MIDDLE:
     249   222499838 :             if (m_scratch.empty()) {
     250             :                 //If the scratch empty mark truncation and add subschunk
     251           7 :                 m_scratch.update_status_byte(SW_TRUNC);
     252             :             }
     253   222499838 :             m_scratch.push_back(iovec{data, length});
     254   222620289 :             break;
     255             : 
     256         658 :         case TIMEOUT:
     257         658 :             if (fw_flags & FW_TRUNC) {
     258           0 :                 return post_subchunk(data, length, m_scratch.empty() ? WHOLE : LAST, fw_flags);
     259             :             } else {
     260             :                 //Discarded if no truncation flagged by firmware
     261             :                 return Publisher::OK;
     262             :             }
     263             : 
     264             :         case NIL:
     265             :         case OOB:
     266             :             return Publisher::OK;
     267             : 
     268           0 :         default:
     269           0 :             LOG_ERR("invalid subchunk type=%d", type);
     270           0 :             return Publisher::DECODING_ERROR;
     271             :     }
     272             : 
     273             :     //Second switch case, no error conditions
     274   998775047 :     switch(type) {
     275             : 
     276    66901777 :         case FIRST:
     277    66901777 :         {
     278    66901777 :             m_scratch.update_status_byte(fw_flags);
     279    66901777 :             m_scratch.push_back(iovec{data, length});
     280    66901777 :             if ( m_elink.has_streams ){ m_elink.fid |= data[0]; }
     281             :             break;
     282             :         }
     283             : 
     284   709373432 :         case WHOLE:
     285   709373432 :         {
     286   709373432 :             m_scratch.update_status_byte(fw_flags);
     287   709373432 :             m_scratch.push_back(iovec{data, length});
     288   709433404 :             if ( m_elink.has_streams ){ m_elink.fid |= data[0]; }
     289   709433404 :             auto r =  m_publisher.publish(m_elink.fid, m_scratch.iov_addr(), m_scratch.iov_len(), m_scratch.byte_size(), m_last_block, m_scratch.get_status_byte());
     290   709449359 :             if (Publisher::AGAIN == r) {
     291      506919 :                 m_scratch.remove_last_entry();
     292             :             } else {
     293   708942440 :                 on_successful_send();
     294             :             }
     295             :             return r;            
     296             :         }
     297             :         
     298    71620624 :         case LAST:
     299    71620624 :         {
     300    71620624 :             auto r = m_publisher.publish(m_elink.fid, m_scratch.iov_addr(), m_scratch.iov_len(), m_scratch.byte_size(), m_last_block, m_scratch.get_status_byte());
     301    71620624 :             if (Publisher::AGAIN == r) {
     302     6089942 :                 m_scratch.remove_last_entry();
     303             :             } else {
     304    65530682 :                 on_successful_send();
     305             :             }
     306             :             return r;
     307             :         }
     308             : 
     309             :         default:
     310             :             break;
     311             :     }
     312             : 
     313             :     return Publisher::OK;
     314             : }
     315             : 
     316             : 
     317         301 : ToHostElinkStats Decoder::get_decoder_stats_increment(ToHostElinkStats & previous)
     318             : {
     319         301 :     return m_stats.get_increment(previous);
     320             : }

Generated by: LCOV version 1.0