/* * This file is part of the DSView project. * DSView is based on PulseView. * * Copyright (C) 2012 Joel Holdsworth * Copyright (C) 2013 DreamSourceLab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include "logicsnapshot.h" #include "../dsvdef.h" #include "../log.h" #include "../utility/array.h" using namespace std; namespace pv { namespace data { const uint64_t LogicSnapshot::LevelMask[LogicSnapshot::ScaleLevel] = { ~(~0ULL << ScalePower) << 0 * ScalePower, ~(~0ULL << ScalePower) << 1 * ScalePower, ~(~0ULL << ScalePower) << 2 * ScalePower, ~(~0ULL << ScalePower) << 3 * ScalePower, }; const uint64_t LogicSnapshot::LevelOffset[LogicSnapshot::ScaleLevel] = { 0, (uint64_t)pow(Scale, 3), (uint64_t)pow(Scale, 3) + (uint64_t)pow(Scale, 2), (uint64_t)pow(Scale, 3) + (uint64_t)pow(Scale, 2) + (uint64_t)pow(Scale, 1), }; LogicSnapshot::LogicSnapshot() : Snapshot(1, 0, 0) { _channel_num = 0; _block_num = 0; _total_sample_count = 0; } LogicSnapshot::~LogicSnapshot() { } void LogicSnapshot::free_data() { Snapshot::free_data(); for(auto& iter : _ch_data) { for(auto& iter_rn : iter) { for (unsigned int k = 0; k < Scale; k++){ if (iter_rn.lbp[k] != NULL) free(iter_rn.lbp[k]); } } std::vector void_vector; iter.swap(void_vector); } _ch_data.clear(); _sample_count = 0; } void LogicSnapshot::init() { std::lock_guard lock(_mutex); init_all(); } void LogicSnapshot::init_all() { _sample_count = 0; _ring_sample_count = 0; _block_num = 0; _byte_fraction = 0; _ch_fraction = 0; _dest_ptr = NULL; _memory_failed = false; _last_ended = true; _mipmap_sample_count = 0; } void LogicSnapshot::clear() { std::lock_guard lock(_mutex); free_data(); init_all(); _have_data = false; } void LogicSnapshot::first_payload(const sr_datafeed_logic &logic, uint64_t total_sample_count, GSList *channels) { bool channel_changed = false; uint16_t channel_num = 0; for (const GSList *l = channels; l; l = l->next) { sr_channel *const probe = (sr_channel*)l->data; if (probe->type == SR_CHANNEL_LOGIC && probe->enabled) { channel_num++; if (!channel_changed){ channel_changed = !has_data(probe->index); } } } if (total_sample_count != _total_sample_count || channel_num != _channel_num || channel_changed) { free_data(); _ch_index.clear(); _total_sample_count = total_sample_count; _channel_num = channel_num; uint64_t rootnode_size = (_total_sample_count + RootNodeSamples - 1) / RootNodeSamples; for (const GSList *l = channels; l; l = l->next) { sr_channel *const probe = (sr_channel*)l->data; if (probe->type == SR_CHANNEL_LOGIC && probe->enabled) { std::vector root_vector; for (uint64_t j = 0; j < rootnode_size; j++) { struct RootNode rn; rn.tog = 0; rn.value = 0; memset(rn.lbp, 0, sizeof(rn.lbp)); root_vector.push_back(rn); } _ch_data.push_back(root_vector); _ch_index.push_back(probe->index); } } } else { for(auto& iter : _ch_data) { for(auto& iter_rn : iter) { iter_rn.tog = 0; iter_rn.value = 0; for (int j=0; j<64; j++){ if (iter_rn.lbp[j] != NULL) memset(iter_rn.lbp[j], 0, LeafBlockSpace); } } } } assert(_channel_num < CHANNEL_MAX_COUNT); _sample_count = 0; _ring_sample_count = 0; _mipmap_sample_count = 0; for (unsigned int i = 0; i < _channel_num; i++) { _last_sample[i] = 0; _last_calc_count[i] = 0; } append_payload(logic); _last_ended = false; } void LogicSnapshot::append_payload(const sr_datafeed_logic &logic) { std::lock_guard lock(_mutex); append_cross_payload(logic); _have_data = true; } void LogicSnapshot::append_cross_payload(const sr_datafeed_logic &logic) { assert(logic.format == LA_CROSS_DATA); assert(logic.length >= ScaleSize * _channel_num); assert(logic.data); if (_sample_count >= _total_sample_count) return; uint8_t *data_src_ptr = (uint8_t*)logic.data; uint64_t len = logic.length; uint64_t index0 = 0; uint64_t index1 = 0; uint64_t offset = 0; // samples not accurate, lead to a larger _sampole_count // _sample_count should be fixed in the last packet // so _total_sample_count must be align to LeafBlock uint64_t samples = ceil(logic.length * 8.0 / _channel_num); if (_sample_count + samples < _total_sample_count) _sample_count += samples; else _sample_count = _total_sample_count; // malloc block buffer while (_sample_count > _block_num * LeafBlockSamples) { uint8_t index0 = _block_num / RootScale; uint8_t index1 = _block_num % RootScale; for(auto& iter : _ch_data) { if (iter[index0].lbp[index1] == NULL){ void *lbp = malloc(LeafBlockSpace); if (lbp == NULL) { _memory_failed = true; dsv_err("LogicSnapshot::append_cross_payload, Malloc memory failed!"); return; } iter[index0].lbp[index1] = lbp; } memset(iter[index0].lbp[index1], 0, LeafBlockSpace); } _block_num++; } // bit align while ((_ch_fraction != 0 || _byte_fraction != 0) && len > 0) { if (_dest_ptr == NULL) assert(false); do{ *_dest_ptr++ = *data_src_ptr++; _byte_fraction = (_byte_fraction + 1) % 8; len--; } while (_byte_fraction != 0 && len > 0); if (_byte_fraction == 0) { index0 = _ring_sample_count / LeafBlockSamples / RootScale; index1 = (_ring_sample_count / LeafBlockSamples) % RootScale; offset = (_ring_sample_count % LeafBlockSamples) / 8; _ch_fraction = (_ch_fraction + 1) % _channel_num; _dest_ptr = (uint8_t*)_ch_data[_ch_fraction][index0].lbp[index1] + offset; // To the last channel. if (_ch_fraction == 0){ _ring_sample_count += Scale; if (_ring_sample_count % LeafBlockSamples == 0){ calc_mipmap(_channel_num - 1, index0, index1, LeafBlockSamples, true); _mipmap_sample_count = _ring_sample_count; } break; } } } // append data assert(_ch_fraction == 0); assert(_byte_fraction == 0); assert(_ring_sample_count % Scale == 0); uint64_t align_sample_count = _ring_sample_count; uint64_t *read_ptr = (uint64_t*)data_src_ptr; void *end_read_ptr = (uint8_t*)data_src_ptr + len; uint64_t filled_sample = align_sample_count % LeafBlockSamples; uint64_t old_filled_sample = filled_sample; uint64_t* chans_read_addr[CHANNEL_MAX_COUNT]; for (unsigned int i=0; i<_channel_num; i++){ chans_read_addr[i] = (uint64_t*)data_src_ptr + i; } uint16_t fill_chan = _ch_fraction; uint16_t last_chan = _ch_fraction; index0 = align_sample_count / LeafBlockSamples / RootScale; index1 = (align_sample_count / LeafBlockSamples) % RootScale; offset = align_sample_count % LeafBlockSamples; uint64_t *write_ptr = (uint64_t*)_ch_data[fill_chan][index0].lbp[index1] + offset / Scale; if (_ch_data[fill_chan][index0].lbp[index1] == NULL){ dsv_err("Write buffer is null."); assert(false); } while (len >= 8) { *write_ptr++ = *read_ptr; read_ptr += _channel_num; len -= 8; filled_sample += Scale; last_chan++; if (last_chan == _channel_num){ last_chan = 0; } if (filled_sample == LeafBlockSamples) { calc_mipmap(fill_chan, index0, index1, LeafBlockSamples, true); if (fill_chan + 1 == _channel_num) _mipmap_sample_count = _ring_sample_count; chans_read_addr[fill_chan] = read_ptr; fill_chan = (fill_chan + 1) % _channel_num; if (fill_chan == 0) align_sample_count += (filled_sample - old_filled_sample); index0 = align_sample_count / LeafBlockSamples / RootScale; index1 = (align_sample_count / LeafBlockSamples) % RootScale; offset = align_sample_count % LeafBlockSamples; filled_sample = align_sample_count % LeafBlockSamples; old_filled_sample = filled_sample; write_ptr = (uint64_t*)_ch_data[fill_chan][index0].lbp[index1] + offset / Scale; read_ptr = chans_read_addr[fill_chan]; if (_ch_data[fill_chan][index0].lbp[index1] == NULL){ dsv_err("Write buffer is null."); assert(false); } } else if (read_ptr >= end_read_ptr) { calc_mipmap(fill_chan, index0, index1, filled_sample, false); fill_chan = (fill_chan + 1) % _channel_num; if (fill_chan == 0) align_sample_count += (filled_sample - old_filled_sample); index0 = align_sample_count / LeafBlockSamples / RootScale; index1 = (align_sample_count / LeafBlockSamples) % RootScale; offset = align_sample_count % LeafBlockSamples; filled_sample = align_sample_count % LeafBlockSamples; old_filled_sample = filled_sample; write_ptr = (uint64_t*)_ch_data[fill_chan][index0].lbp[index1] + offset / Scale; read_ptr = chans_read_addr[fill_chan]; if (_ch_data[fill_chan][index0].lbp[index1] == NULL){ dsv_err("Write buffer is null."); assert(false); } } } _ring_sample_count = align_sample_count; _ch_fraction = last_chan; _dest_ptr = (uint8_t*)_ch_data[_ch_fraction][index0].lbp[index1] + offset / 8; if (_ch_data[_ch_fraction][index0].lbp[index1] == NULL){ dsv_err("Write buffer is null."); assert(false); } if (len > 0) { uint8_t *src_ptr = (uint8_t*)end_read_ptr - len; _byte_fraction += len; while (len > 0){ *_dest_ptr++ = *src_ptr++; len--; } } } void LogicSnapshot::capture_ended() { std::lock_guard lock(_mutex); Snapshot::capture_ended(); uint64_t index0 = _ring_sample_count / LeafBlockSamples / RootScale; uint64_t index1 = (_ring_sample_count / LeafBlockSamples) % RootScale; uint64_t offset = (_ring_sample_count % LeafBlockSamples) / 8; _sample_count = _ring_sample_count; if (offset == 0) return; for (int chan=0; chan<_channel_num; chan++) { const uint64_t *end_ptr = (uint64_t*)_ch_data[chan][index0].lbp[index1] + (LeafBlockSamples / Scale); uint64_t *ptr = (uint64_t*)((uint8_t*)_ch_data[chan][index0].lbp[index1] + offset); while (ptr < end_ptr){ *ptr++ = 0; } calc_mipmap(chan, index0, index1, offset * 8, true); } _mipmap_sample_count = _ring_sample_count; } void LogicSnapshot::calc_mipmap(unsigned int order, uint8_t index0, uint8_t index1, uint64_t samples, bool isEnd) { const uint64_t mask = 1ULL << (Scale - 1); void *lbp = _ch_data[order][index0].lbp[index1]; void *level1_ptr = (uint8_t*)lbp + LeafBlockSamples / 8; void *level2_ptr = (uint8_t*)level1_ptr + LeafBlockSamples / Scale / 8; void *level3_ptr = (uint8_t*)level2_ptr + LeafBlockSamples / Scale / Scale / 8; // level 1 uint64_t *src_ptr = (uint64_t*)lbp; uint64_t *dest_ptr = (uint64_t*)level1_ptr; uint8_t offset = 0; uint64_t i = 0; uint64_t last_count = _last_calc_count[order]; if (last_count > 0){ i = last_count / Scale; offset = i % Scale; src_ptr += i; dest_ptr += i / Scale; } for(; i < samples / Scale; i++) { if (_last_sample[order] ^ *src_ptr) *dest_ptr |= (1ULL << offset); _last_sample[order] = *src_ptr & mask ? ~0ULL : 0ULL; src_ptr++; offset++; if (offset == Scale){ offset = 0; dest_ptr++; } } // level 2 src_ptr = (uint64_t*)level1_ptr; dest_ptr = (uint64_t*)level2_ptr; offset = 0; i = 0; if (last_count > 0){ i = last_count / Scale / Scale; offset = i % Scale; src_ptr += i; dest_ptr += i / Scale; } for(; i < LeafBlockSamples / Scale / Scale; i++) { if (*src_ptr) *dest_ptr |= (1ULL << offset); src_ptr++; offset++; if (offset == Scale){ offset = 0; dest_ptr++; } } // level 3 src_ptr = (uint64_t*)level2_ptr; dest_ptr = (uint64_t*)level3_ptr; for (i=0; i < Scale; i++) { if (*src_ptr) *dest_ptr |= (1ULL << i); src_ptr++; } if (*((uint64_t*)lbp) != 0) _ch_data[order][index0].value |= 1ULL << index1; if (*((uint64_t*)level3_ptr) != 0){ _ch_data[order][index0].tog |= 1ULL << index1; } else if (isEnd){ free(_ch_data[order][index0].lbp[index1]); _ch_data[order][index0].lbp[index1] = NULL; } if (isEnd) _last_calc_count[order] = 0; else _last_calc_count[order] = samples; } const uint8_t *LogicSnapshot::get_samples(uint64_t start_sample, uint64_t &end_sample, int sig_index) { std::lock_guard lock(_mutex); uint64_t sample_count = _ring_sample_count; assert(start_sample < sample_count); if (end_sample >= sample_count) end_sample = sample_count - 1; assert(end_sample <= sample_count); assert(start_sample <= end_sample); int order = get_ch_order(sig_index); uint64_t index0 = start_sample >> (LeafBlockPower + RootScalePower); uint64_t index1 = (start_sample & RootMask) >> LeafBlockPower; uint64_t offset = (start_sample & LeafMask) / 8; end_sample = (index0 << (LeafBlockPower + RootScalePower)) + (index1 << LeafBlockPower) + ~(~0ULL << LeafBlockPower); end_sample = min(end_sample + 1, sample_count); if (order == -1 || _ch_data[order][index0].lbp[index1] == NULL) return NULL; else return (uint8_t*)_ch_data[order][index0].lbp[index1] + offset; } const uint8_t *LogicSnapshot::get_decode_samples(uint64_t start_sample, uint64_t &end_sample, int sig_index) { std::lock_guard lock(_mutex); uint64_t sample_count = _mipmap_sample_count; assert(start_sample < sample_count); if (end_sample >= sample_count) end_sample = sample_count - 1; assert(end_sample <= sample_count); assert(start_sample <= end_sample); int order = get_ch_order(sig_index); uint64_t index0 = start_sample >> (LeafBlockPower + RootScalePower); uint64_t index1 = (start_sample & RootMask) >> LeafBlockPower; uint64_t offset = (start_sample & LeafMask) / 8; end_sample = (index0 << (LeafBlockPower + RootScalePower)) + (index1 << LeafBlockPower) + ~(~0ULL << LeafBlockPower); end_sample = min(end_sample + 1, sample_count); if (order == -1 || _ch_data[order][index0].lbp[index1] == NULL) return NULL; else return (uint8_t*)_ch_data[order][index0].lbp[index1] + offset; } bool LogicSnapshot::get_sample(uint64_t index, int sig_index) { int order = get_ch_order(sig_index); assert(order != -1); assert(_ch_data[order].size() != 0); if (index < _ring_sample_count) { uint64_t index_mask = 1ULL << (index & LevelMask[0]); uint64_t index0 = index >> (LeafBlockPower + RootScalePower); uint64_t index1 = (index & RootMask) >> LeafBlockPower; uint64_t root_pos_mask = 1ULL << index1; if ((_ch_data[order][index0].tog & root_pos_mask) == 0) { return (_ch_data[order][index0].value & root_pos_mask) != 0; } else { uint64_t *lbp = (uint64_t*)_ch_data[order][index0].lbp[index1]; return *(lbp + ((index & LeafMask) >> ScalePower)) & index_mask; } } return false; } bool LogicSnapshot::get_display_edges(std::vector > &edges, std::vector > &togs, uint64_t start, uint64_t end, uint16_t width, uint16_t max_togs, double pixels_offset, double min_length, uint16_t sig_index) { if (!edges.empty()) edges.clear(); if (!togs.empty()) togs.clear(); std::lock_guard lock(_mutex); if (_ring_sample_count == 0) return false; assert(end < _ring_sample_count); assert(start <= end); assert(min_length > 0); uint64_t index = start; bool last_sample; bool start_sample; // Get the initial state start_sample = last_sample = get_sample(index++, sig_index); togs.push_back(pair(0, last_sample)); while(edges.size() < width) { // search next edge bool has_edge = get_nxt_edge(index, last_sample, end, 0, sig_index); // calc the edge position int64_t gap = (index / min_length) - pixels_offset; index = max((uint64_t)ceil((floor(index/min_length) + 1) * min_length), index + 1); while(gap > (int64_t)edges.size() && edges.size() < width){ edges.push_back(pair(false, last_sample)); } if (index > end) last_sample = get_sample(end, sig_index); else last_sample = get_sample(index - 1, sig_index); if (has_edge) { edges.push_back(pair(true, last_sample)); if (togs.size() < max_togs) togs.push_back(pair(edges.size() - 1, last_sample)); } while(index > end && edges.size() < width) edges.push_back(pair(false, last_sample)); } if (togs.size() < max_togs) { last_sample = get_sample(end, sig_index); togs.push_back(pair(edges.size() - 1, last_sample)); } return start_sample; } bool LogicSnapshot::get_nxt_edge(uint64_t &index, bool last_sample, uint64_t end, double min_length, int sig_index) { if (index > end) return false; int order = get_ch_order(sig_index); if (order == -1) return false; //const unsigned int min_level = max((int)floorf(logf(min_length) / logf(Scale)) - 1, 0); const unsigned int min_level = max((int)(log2f(min_length) - 1) / (int)ScalePower, 0); uint64_t root_index = index >> (LeafBlockPower + RootScalePower); uint8_t root_pos = (index & RootMask) >> LeafBlockPower; bool edge_hit = false; // linear search for the next transition on the root level for (int64_t i = root_index; !edge_hit && (index <= end) && i < (int64_t)_ch_data[order].size(); i++) { uint64_t cur_mask = (~0ULL << root_pos); do { uint64_t cur_tog = _ch_data[order][i].tog & cur_mask; if (cur_tog != 0) { uint64_t first_edge_pos = bsf_folded(cur_tog); uint64_t *lbp = (uint64_t*)_ch_data[order][i].lbp[first_edge_pos]; uint64_t blk_start = (i << (LeafBlockPower + RootScalePower)) + (first_edge_pos << LeafBlockPower); index = max(blk_start, index); if (min_level < ScaleLevel) { uint64_t block_end = min(index | LeafMask, end); edge_hit = block_nxt_edge(lbp, index, block_end, last_sample, min_level); } else { edge_hit = true; } if (first_edge_pos == RootScale - 1) break; cur_mask = (~0ULL << (first_edge_pos + 1)); } else { index = (index + (1 << (LeafBlockPower + RootScalePower))) & (~0ULL << (LeafBlockPower + RootScalePower)); break; } } while (!edge_hit && index < end); root_pos = 0; } return edge_hit; } bool LogicSnapshot::get_pre_edge(uint64_t &index, bool last_sample, double min_length, int sig_index) { assert(index < _ring_sample_count); int order = get_ch_order(sig_index); if (order == -1) return false; //const unsigned int min_level = max((int)floorf(logf(min_length) / logf(Scale)) - 1, 1); const unsigned int min_level = max((int)(log2f(min_length) - 1) / (int)ScalePower, 0); int root_index = index >> (LeafBlockPower + RootScalePower); uint8_t root_pos = (index & RootMask) >> LeafBlockPower; bool edge_hit = false; // linear search for the previous transition on the root level for (int64_t i = root_index; !edge_hit && i >= 0; i--) { uint64_t cur_mask = (~0ULL >> (RootScale - root_pos - 1)); do { uint64_t cur_tog = _ch_data[order][i].tog & cur_mask; if (cur_tog != 0) { uint64_t first_edge_pos = bsr64(cur_tog); uint64_t *lbp = (uint64_t*)_ch_data[order][i].lbp[first_edge_pos]; uint64_t blk_end = ((i << (LeafBlockPower + RootScalePower)) + (first_edge_pos << LeafBlockPower)) | LeafMask; index = min(blk_end, index); if (min_level < ScaleLevel) { edge_hit = block_pre_edge(lbp, index, last_sample, min_level, sig_index); } else { edge_hit = true; } if (first_edge_pos == 0) break; cur_mask = (~0ULL >> (RootScale - first_edge_pos)); } else { break; } } while (!edge_hit); root_pos = RootScale - 1; } return edge_hit; } bool LogicSnapshot::block_nxt_edge(uint64_t *lbp, uint64_t &index, uint64_t block_end, bool last_sample, unsigned int min_level) { unsigned int level = min_level; bool fast_forward = true; const uint64_t last = last_sample ? ~0ULL : 0ULL; //----- Search Next Edge Within Current LeafBlock -----// if (level == 0) { // Search individual samples up to the beginning of // the next first level mip map block const uint64_t offset = (index & ~(~0ULL << LeafBlockPower)) >> ScalePower; const uint64_t mask = last_sample ? ~(~0ULL << (index & LevelMask[0])) : ~0ULL << (index & LevelMask[0]); uint64_t sample = last_sample ? *(lbp + offset) | mask : *(lbp + offset) & mask; if (sample ^ last) { index = (index & ~LevelMask[0]) + bsf_folded(last_sample ? ~sample : sample); fast_forward = false; } else { index = ((index >> ScalePower) + 1) << ScalePower; } } else { index = ((index >> level*ScalePower) + 1) << level*ScalePower; } if (fast_forward) { // Fast forward: This involves zooming out to higher // levels of the mip map searching for changes, then // zooming in on them to find the point where the edge // begins. // Zoom out at the beginnings of mip-map // blocks until we encounter a change while (index <= block_end) { // continue only within current block if (level == 0) level++; const int level_scale_power = (level + 1) * ScalePower; const uint64_t offset = (index & ~(~0ULL << LeafBlockPower)) >> level_scale_power; const uint64_t mask = ~0ULL << ((index & LevelMask[level]) >> (level*ScalePower)); uint64_t sample = *(lbp + LevelOffset[level] + offset) & mask; // Check if there was a change in this block if (sample) { index = (index & (~0ULL << (level + 1)*ScalePower)) + (bsf_folded(sample) << level*ScalePower); break; } else { index = ((index >> (level + 1)*ScalePower) + 1) << (level + 1)*ScalePower; ++level; } } // Zoom in until we encounter a change, // and repeat until we reach min_level while ((index <= block_end) && (level > min_level)) { // continue only within current block level--; const int level_scale_power = (level + 1) * ScalePower; const uint64_t offset = (index & ~(~0ULL << LeafBlockPower)) >> level_scale_power; const uint64_t mask = (level == 0 && last_sample) ? ~(~0ULL << ((index & LevelMask[level]) >> (level*ScalePower))) : ~0ULL << ((index & LevelMask[level]) >> (level*ScalePower)); uint64_t sample = (level == 0 && last_sample) ? *(lbp + LevelOffset[level] + offset) | mask : *(lbp + LevelOffset[level] + offset) & mask; // Update the low level position of the change in this block if (level == 0 ? sample ^ last : sample) { index = (index & (~0ULL << (level + 1)*ScalePower)) + (bsf_folded(level == 0 ? sample ^ last : sample) << level*ScalePower); if (level == min_level) break; } } } return (index <= block_end); } bool LogicSnapshot::block_pre_edge(uint64_t *lbp, uint64_t &index, bool last_sample, unsigned int min_level, int sig_index) { assert(min_level == 0); unsigned int level = min_level; bool fast_forward = true; const uint64_t last = last_sample ? ~0ULL : 0ULL; uint64_t block_start = index & ~LeafMask; //----- Search Next Edge Within Current LeafBlock -----// if (level == 0) { // Search individual samples down to the beginning of // the previous first level mip map block const uint64_t offset = (index & ~(~0ULL << LeafBlockPower)) >> ScalePower; const uint64_t mask = last_sample ? ~(~0ULL >> (Scale - (index & LevelMask[0]) - 1)) : ~0ULL >> (Scale - (index & LevelMask[0]) - 1); uint64_t sample = last_sample ? *(lbp + offset) | mask : *(lbp + offset) & mask; if (sample ^ last) { index = (index & ~LevelMask[0]) + bsr64(last_sample ? ~sample : sample) + 1; return true; } else { index &= ~LevelMask[0]; if (index == 0) return false; else index--; // using get_sample() to avoid out of block case bool sample = get_sample(index, sig_index); if (sample ^ last_sample) { index++; return true; } else if (index < block_start) { return false; } } } if (fast_forward) { // Fast forward: This involves zooming out to higher // levels of the mip map searching for changes, then // zooming in on them to find the point where the edge // begins. // Zoom out at the beginnings of mip-map // blocks until we encounter a change while (index > block_start) { // continue only within current block if (level == 0) level++; const int level_scale_power = (level + 1) * ScalePower; const uint64_t offset = (index & ~(~0ULL << LeafBlockPower)) >> level_scale_power; const uint64_t mask = ~0ULL >> (Scale - ((index & LevelMask[level]) >> (level*ScalePower)) - 1); uint64_t sample = *(lbp + LevelOffset[level] + offset) & mask; // Check if there was a change in this block if (sample) { index = (index & (~0ULL << (level + 1)*ScalePower)) + (bsr64(sample) << level*ScalePower) + ~(~0ULL << level*ScalePower); break; } else { index = (index >> (level + 1)*ScalePower) << (level + 1)*ScalePower; if (index == 0) return false; else index--; } } // Zoom in until we encounter a change, // and repeat until we reach min_level while ((index >= block_start) && (level > min_level)) { // continue only within current block level--; const int level_scale_power = (level + 1) * ScalePower; const uint64_t offset = (index & ~(~0ULL << LeafBlockPower)) >> level_scale_power; const uint64_t mask = (level == 0 && last_sample) ? ~(~0ULL >> (Scale - ((index & LevelMask[level]) >> (level*ScalePower)) - 1)) : ~0ULL >> (Scale - ((index & LevelMask[level]) >> (level*ScalePower)) - 1); uint64_t sample = (level == 0 && last_sample) ? *(lbp + LevelOffset[level] + offset) | mask : *(lbp + LevelOffset[level] + offset) & mask; // Update the low level position of the change in this block if (level == 0 ? sample ^ last : sample) { index = (index & (~0ULL << (level + 1)*ScalePower)) + (bsr64(level == 0 ? sample ^ last : sample) << level*ScalePower) + ~(~0ULL << level*ScalePower); if (level == min_level) { index++; break; } } else { index = (index & (~0ULL << (level + 1)*ScalePower)); } } } return (index >= block_start) && (index != 0); } bool LogicSnapshot::pattern_search(int64_t start, int64_t end, int64_t &index, std::map pattern, bool isNext) { if (pattern.empty()) { return true; } char flagList[CHANNEL_MAX_COUNT]; char lstValues[CHANNEL_MAX_COUNT]; int chanIndexs[CHANNEL_MAX_COUNT]; int count = 0; bool bEdgeFlag = false; int64_t to = isNext ? end + 1 : start - 1; int64_t step = isNext ? 1 : -1; for (auto it = pattern.begin(); it != pattern.end(); it++){ char flag = *(it->second.toStdString().c_str()); int channel = it->first; if (flag != 'X' && has_data(channel)){ flagList[count] = flag; chanIndexs[count] = channel; count++; if (flag == 'R' || flag == 'F' || flag == 'C'){ bEdgeFlag = true; } } } if (count == 0){ return true; } //find bool ret = false; char val = 0; int macthed = 0; //get first edge values if (bEdgeFlag){ for (int i=0; i < count; i++){ lstValues[i] = (char)get_sample(index, chanIndexs[i]); } index += step; } while (index != to) { macthed = 0; for (int i = 0; i < count; i++) { val = (char)get_sample(index, chanIndexs[i]); if (flagList[i] == '0') { macthed += !val; } else if (flagList[i] == '1') { macthed += val; } else if (flagList[i] == 'R') { if (isNext) macthed += (lstValues[i] == 0 && val == 1); else macthed += (lstValues[i] == 1 && val == 0); } else if (flagList[i] == 'F') { if (isNext) macthed += (lstValues[i] == 1 && val == 0); else macthed += (lstValues[i] == 0 && val == 1); } else if (flagList[i] == 'C') { if (isNext) macthed += (lstValues[i] == 0 && val == 1) || (lstValues[i] == 1 && val == 0); else macthed += (lstValues[i] == 1 && val == 0) || (lstValues[i] == 0 && val == 1); } lstValues[i] = val; } // matched all if (macthed == count) { ret = true; if (!isNext){ index++; //move to prev position } break; } index += step; } return ret; } bool LogicSnapshot::has_data(int sig_index) { return get_ch_order(sig_index) != -1; } int LogicSnapshot::get_block_num() { return (_ring_sample_count >> LeafBlockPower) + ((_ring_sample_count & LeafMask) != 0); } uint64_t LogicSnapshot::get_block_size(int block_index) { assert(block_index < get_block_num()); if (block_index < get_block_num() - 1) { return LeafBlockSamples / 8; } else { if (_ring_sample_count % LeafBlockSamples == 0) return LeafBlockSamples / 8; else return (_ring_sample_count % LeafBlockSamples) / 8; } } uint8_t *LogicSnapshot::get_block_buf(int block_index, int sig_index, bool &sample) { assert(block_index < get_block_num()); int order = get_ch_order(sig_index); if (order == -1) { sample = 0; return NULL; } uint64_t index = block_index / RootScale; uint8_t pos = block_index % RootScale; uint8_t *lbp = (uint8_t*)_ch_data[order][index].lbp[pos]; if (lbp == NULL) sample = (_ch_data[order][index].value & 1ULL << pos) != 0; return lbp; } int LogicSnapshot::get_ch_order(int sig_index) { uint16_t order = 0; for (uint16_t i : _ch_index) { if (i == sig_index) return order; else order++; } return -1; } uint64_t LogicSnapshot::get_mipmap_sample_count() { // std::lock_guard lock(_mutex); return _mipmap_sample_count; } } // namespace data } // namespace pv