// Copyright 2022 The Pigweed Authors // // Licensed under the Apache License, Version 2.0 (the "License"); you may not // use this file except in compliance with the License. You may obtain a copy of // the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations under // the License. #include #include "pw_bloat/bloat_this_binary.h" #include "pw_log/log.h" #include "pw_preprocessor/compiler.h" #include "pw_span/span.h" #ifdef USE_CRC16_CHECKSUM #include "pw_checksum/crc16_ccitt.h" using TheChecksum = pw::checksum::Crc16Ccitt; #endif #ifdef USE_CRC32_8BIT_CHECKSUM #include "pw_checksum/crc32.h" using TheChecksum = pw::checksum::Crc32EightBit; #endif #ifdef USE_CRC32_4BIT_CHECKSUM #include "pw_checksum/crc32.h" using TheChecksum = pw::checksum::Crc32FourBit; #endif #ifdef USE_CRC32_1BIT_CHECKSUM #include "pw_checksum/crc32.h" using TheChecksum = pw::checksum::Crc32OneBit; #endif namespace pw::checksum { #ifdef USE_NOOP_CHECKSUM class NoOpChecksum { public: static uint32_t Calculate(span) { return arbitrary_value; } // Don't inline to prevent the compiler from optimizing out the checksum. PW_NO_INLINE void Update(span) {} PW_NO_INLINE void Update(std::byte) {} PW_NO_INLINE uint32_t value() const { return arbitrary_value; } void clear() {} private: // static volatile uint32_t arbitrary_value; const static uint32_t arbitrary_value = 10; }; using TheChecksum = NoOpChecksum; #endif // Fletcher16 is a simple checksum that shouldn't be used in production, but is // interesting from a size comparison perspective. #ifdef USE_FLETCHER16_CHECKSUM class Fletcher16 { public: Fletcher16() : sum1_(0), sum2_(0) {} // Don't inline to prevent the compiler from optimizing out the checksum. PW_NO_INLINE static uint32_t Calculate(span data) { Fletcher16 checksum; checksum.Update(data); return checksum.value(); } PW_NO_INLINE void Update(span data) { for (std::byte b : data) { sum1_ = static_cast((sum1_ + static_cast(b)) % 255u); sum2_ = static_cast((sum2_ + sum1_) % 255u); } } PW_NO_INLINE void Update(std::byte) {} PW_NO_INLINE uint32_t value() const { return static_cast(sum2_) << 8 | sum1_; }; void clear() {} private: uint16_t sum1_ = 0; uint16_t sum2_ = 0; }; using TheChecksum = Fletcher16; #endif char buffer[128]; char* volatile get_buffer = buffer; volatile unsigned get_size; int RunChecksum() { // Trick the optimizer and also satisfy the type checker. get_size = sizeof(buffer); char* local_buffer = get_buffer; unsigned local_size = get_size; // Calculate the checksum and stash it in a volatile variable so the compiler // can't optimize it out. TheChecksum checksum; checksum.Update(pw::as_bytes(span(local_buffer, local_size))); uint32_t value = static_cast(checksum.value()); *get_buffer = static_cast(value); return 0; } } // namespace pw::checksum int main() { pw::bloat::BloatThisBinary(); return pw::checksum::RunChecksum(); }