Pavona Software APIs
crc32.c
1// Copyright lowRISC contributors (OpenTitan project).
2// Licensed under the Apache License, Version 2.0, see LICENSE for details.
3// SPDX-License-Identifier: Apache-2.0
4
5#include "sw/device/lib/base/crc32.h"
6
7#include <stdbool.h>
8
11
12#ifdef OT_PLATFORM_RV32
13/*
14 * Ibex contains `crc32` instructions from the unratified `zbr` subset of
15 * the bitmanip (`b`) RV32 extension. Support for `zbr` was removed from `clang`
16 * in September 2022, so we replace the instruction directives with `.insn`
17 * directives that specify the correct instruction format.
18 *
19 * Ibex classifies the `zbr` instructions under OP-IMM, hence the use of the
20 * "immedate" (`i`) instruction format used in the `.insn` directives below.
21 * However, `insn[31:20]` (the three-digit hex value at the end of the `.insn`
22 * directives) is not used as an immediate value. Instead, it is broken into
23 * segments of 7 and 5 bits as part of a two-stage decoding to select the
24 * specific zbr instruction.
25 *
26 * See hw/vendor/lowrisc_ibex/rtl/ibex_decoder.sv for more details.
27 */
29static uint32_t crc32_internal_add8(uint32_t ctx, uint8_t byte) {
30 ctx ^= byte;
31 asm(
32 // Implementation of `crc32.b %0, %1` :
33 // - i: Register-immediate instruction format
34 // - 0x13: OP-IMM type
35 // - 0x01: Bitmanip instruction family
36 // - 0x610: crc32.b
37 ".insn i 0x13, 0x01, %0, %1, 0x610;"
38 : "+r"(ctx));
39 return ctx;
40}
41
43static uint32_t crc32_internal_add32(uint32_t ctx, uint32_t word) {
44 ctx ^= word;
45 asm(
46 // Implementation of `crc32.w %0, %1` :
47 // - i: Register-immediate instruction format
48 // - 0x13: OP-IMM type
49 // - 0x01: Bitmanip instruction family
50 // - 0x612: crc32.w
51 ".insn i 0x13, 0x01, %0, %1, 0x612;"
52 : "+r"(ctx));
53 return ctx;
54}
55#else
56enum {
57 /**
58 * CRC32 polynomial.
59 */
60 kCrc32Poly = 0xedb88320,
61};
62
63/**
64 * Computes the CRC32 of a buffer as expected by Python's `zlib.crc32()`. The
65 * implementation below is basically a simplified, i.e. byte-by-byte and without
66 * a lookup table, version of zlib's crc32, which also matches IEEE 802.3
67 * CRC-32. See
68 * https://github.com/madler/zlib/blob/2fa463bacfff79181df1a5270fb67cc679a53e71/crc32.c,
69 * lines 111-112 and 276-279.
70 */
72static uint32_t crc32_internal_add8(uint32_t ctx, uint8_t byte) {
73 ctx ^= byte;
74 for (size_t i = 0; i < 8; ++i) {
75 bool lsb = ctx & 1;
76 ctx >>= 1;
77 if (lsb) {
78 ctx ^= kCrc32Poly;
79 }
80 }
81 return ctx;
82}
83
85static uint32_t crc32_internal_add32(uint32_t ctx, uint32_t word) {
86 char *bytes = (char *)&word;
87 for (size_t i = 0; i < sizeof(uint32_t); ++i) {
88 ctx = crc32_internal_add8(ctx, bytes[i]);
89 }
90 return ctx;
91}
92#endif
93
94void crc32_init(uint32_t *ctx) { *ctx = UINT32_MAX; }
95
96void crc32_add8(uint32_t *ctx, uint8_t byte) {
97 *ctx = crc32_internal_add8(*ctx, byte);
98}
99
100void crc32_add32(uint32_t *ctx, uint32_t word) {
101 *ctx = crc32_internal_add32(*ctx, word);
102}
103
104void crc32_add(uint32_t *ctx, const void *buf, size_t len) {
105 const char *data = buf;
106 uint32_t state = *ctx;
107 // Unaligned head.
108 for (; len > 0 && (uintptr_t)data & 0x3; --len, ++data) {
109 state = crc32_internal_add8(state, *data);
110 }
111 // Aligned body.
112 for (; len >= sizeof(uint32_t);
113 len -= sizeof(uint32_t), data += sizeof(uint32_t)) {
114 state = crc32_internal_add32(state, read_32(data));
115 }
116 // Unaligned tail.
117 for (; len > 0; --len, ++data) {
118 state = crc32_internal_add8(state, *data);
119 }
120 *ctx = state;
121}
122
123uint32_t crc32_finish(const uint32_t *ctx) { return *ctx ^ UINT32_MAX; }
124
125uint32_t crc32(const void *buf, size_t len) {
126 uint32_t ctx;
127 crc32_init(&ctx);
128 crc32_add(&ctx, buf, len);
129 return crc32_finish(&ctx);
130}