1 // Copyright 2022 The Pigweed Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not 4 // use this file except in compliance with the License. You may obtain a copy of 5 // the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 // License for the specific language governing permissions and limitations under 13 // the License. 14 15 #include <cstring> 16 17 #include "pw_bloat/bloat_this_binary.h" 18 #include "pw_log/log.h" 19 #include "pw_preprocessor/compiler.h" 20 #include "pw_span/span.h" 21 22 #ifdef USE_CRC16_CHECKSUM 23 #include "pw_checksum/crc16_ccitt.h" 24 using TheChecksum = pw::checksum::Crc16Ccitt; 25 #endif 26 27 #ifdef USE_CRC32_8BIT_CHECKSUM 28 #include "pw_checksum/crc32.h" 29 using TheChecksum = pw::checksum::Crc32EightBit; 30 #endif 31 32 #ifdef USE_CRC32_4BIT_CHECKSUM 33 #include "pw_checksum/crc32.h" 34 using TheChecksum = pw::checksum::Crc32FourBit; 35 #endif 36 37 #ifdef USE_CRC32_1BIT_CHECKSUM 38 #include "pw_checksum/crc32.h" 39 using TheChecksum = pw::checksum::Crc32OneBit; 40 #endif 41 42 namespace pw::checksum { 43 44 #ifdef USE_NOOP_CHECKSUM 45 class NoOpChecksum { 46 public: Calculate(span<const std::byte>)47 static uint32_t Calculate(span<const std::byte>) { return arbitrary_value; } 48 49 // Don't inline to prevent the compiler from optimizing out the checksum. Update(span<const std::byte>)50 PW_NO_INLINE void Update(span<const std::byte>) {} 51 Update(std::byte)52 PW_NO_INLINE void Update(std::byte) {} 53 value() const54 PW_NO_INLINE uint32_t value() const { return arbitrary_value; } clear()55 void clear() {} 56 57 private: 58 // static volatile uint32_t arbitrary_value; 59 const static uint32_t arbitrary_value = 10; 60 }; 61 using TheChecksum = NoOpChecksum; 62 #endif 63 64 // Fletcher16 is a simple checksum that shouldn't be used in production, but is 65 // interesting from a size comparison perspective. 66 #ifdef USE_FLETCHER16_CHECKSUM 67 class Fletcher16 { 68 public: Fletcher16()69 Fletcher16() : sum1_(0), sum2_(0) {} 70 71 // Don't inline to prevent the compiler from optimizing out the checksum. Calculate(span<const std::byte> data)72 PW_NO_INLINE static uint32_t Calculate(span<const std::byte> data) { 73 Fletcher16 checksum; 74 checksum.Update(data); 75 return checksum.value(); 76 } 77 Update(span<const std::byte> data)78 PW_NO_INLINE void Update(span<const std::byte> data) { 79 for (std::byte b : data) { 80 sum1_ = static_cast<uint16_t>((sum1_ + static_cast<uint16_t>(b)) % 255u); 81 sum2_ = static_cast<uint16_t>((sum2_ + sum1_) % 255u); 82 } 83 } Update(std::byte)84 PW_NO_INLINE void Update(std::byte) {} value() const85 PW_NO_INLINE uint32_t value() const { 86 return static_cast<uint32_t>(sum2_) << 8 | sum1_; 87 }; clear()88 void clear() {} 89 90 private: 91 uint16_t sum1_ = 0; 92 uint16_t sum2_ = 0; 93 }; 94 using TheChecksum = Fletcher16; 95 #endif 96 97 char buffer[128]; 98 char* volatile get_buffer = buffer; 99 volatile unsigned get_size; 100 RunChecksum()101int RunChecksum() { 102 // Trick the optimizer and also satisfy the type checker. 103 get_size = sizeof(buffer); 104 char* local_buffer = get_buffer; 105 unsigned local_size = get_size; 106 107 // Calculate the checksum and stash it in a volatile variable so the compiler 108 // can't optimize it out. 109 TheChecksum checksum; 110 checksum.Update(pw::as_bytes(span(local_buffer, local_size))); 111 uint32_t value = static_cast<uint32_t>(checksum.value()); 112 *get_buffer = static_cast<char>(value); 113 return 0; 114 } 115 116 } // namespace pw::checksum 117 main()118int main() { 119 pw::bloat::BloatThisBinary(); 120 return pw::checksum::RunChecksum(); 121 } 122