From: Marian Buschsieweke Date: Thu, 22 Dec 2022 12:20:07 +0000 (+0100) Subject: helper: Add generic little endian CRC32 function X-Git-Url: https://review.openocd.org/gitweb?p=openocd.git;a=commitdiff_plain;h=6e67f1473af15adc7c4052cee27ad84883b286d4 helper: Add generic little endian CRC32 function This generalizes the little endian CRC32 function used in the OR1K target and moves it to a common helper, so that other places do not need to reinvent the wheel. It is directly used in the OR1K target. Change-Id: I0e55340281a5bfd80669bb1994f3a96fecc1248a Signed-off-by: Marian Buschsieweke Reviewed-on: https://review.openocd.org/c/openocd/+/7415 Tested-by: jenkins Reviewed-by: Antonio Borneo --- diff --git a/src/helper/Makefile.am b/src/helper/Makefile.am index 7354f5422b..c4c60d96b4 100644 --- a/src/helper/Makefile.am +++ b/src/helper/Makefile.am @@ -9,6 +9,7 @@ noinst_LTLIBRARIES += %D%/libhelper.la %D%/configuration.c \ %D%/log.c \ %D%/command.c \ + %D%/crc32.c \ %D%/time_support.c \ %D%/replacements.c \ %D%/fileio.c \ @@ -24,6 +25,7 @@ noinst_LTLIBRARIES += %D%/libhelper.la %D%/types.h \ %D%/log.h \ %D%/command.h \ + %D%/crc32.h \ %D%/time_support.h \ %D%/replacements.h \ %D%/fileio.h \ diff --git a/src/helper/crc32.c b/src/helper/crc32.c new file mode 100644 index 0000000000..441a46c57f --- /dev/null +++ b/src/helper/crc32.c @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/*************************************************************************** + * Copyright (C) 2013-2014 by Franck Jullien * + * elec4fun@gmail.com * + * * + * Copyright (C) 2022 Otto-von-Guericke-Universität Magdeburg * + * marian.buschsieweke@ovgu.de * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "crc32.h" +#include +#include + +static uint32_t crc_le_step(uint32_t poly, uint32_t crc, uint32_t data_in, + unsigned int data_bits) +{ + for (unsigned int i = 0; i < data_bits; i++) { + uint32_t d, c; + d = ((data_in >> i) & 0x1) ? 0xffffffff : 0; + c = (crc & 0x1) ? 0xffffffff : 0; + crc = crc >> 1; + crc = crc ^ ((d ^ c) & poly); + } + + return crc; +} + +uint32_t crc32_le(uint32_t poly, uint32_t seed, const void *_data, + size_t data_len) +{ + if (((uintptr_t)_data & 0x3) || (data_len & 0x3)) { + /* data is unaligned, processing data one byte at a time */ + const uint8_t *data = _data; + for (size_t i = 0; i < data_len; i++) + seed = crc_le_step(poly, seed, data[i], 8); + } else { + /* data is aligned, processing 32 bit at a time */ + data_len >>= 2; + const uint32_t *data = _data; + for (size_t i = 0; i < data_len; i++) + seed = crc_le_step(poly, seed, data[i], 32); + } + + return seed; +} diff --git a/src/helper/crc32.h b/src/helper/crc32.h new file mode 100644 index 0000000000..8f077863a3 --- /dev/null +++ b/src/helper/crc32.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/*************************************************************************** + * Copyright (C) 2022 Otto-von-Guericke-Universität Magdeburg * + * marian.buschsieweke@ovgu.de * + ***************************************************************************/ + +#ifndef OPENOCD_HELPER_CRC32_H +#define OPENOCD_HELPER_CRC32_H + +#include +#include + +/** @file + * A generic CRC32 implementation + */ + +/** + * CRC32 polynomial commonly used for little endian CRC32 + */ +#define CRC32_POLY_LE 0xedb88320 + +/** + * Calculate the CRC32 value of the given data + * @param poly The polynomial of the CRC + * @param seed The seed to use (mostly either `0` or `0xffffffff`) + * @param data The data to calculate the CRC32 of + * @param data_len The length of the data in @p data in bytes + * @return The CRC value of the first @p data_len bytes at @p data + * @note This function can be used to incrementally compute the CRC one + * chunk of data at a time by using the CRC32 of the previous chunk + * as @p seed for the next chunk. + */ +uint32_t crc32_le(uint32_t poly, uint32_t seed, const void *data, + size_t data_len); + +#endif /* OPENOCD_HELPER_CRC32_H */ diff --git a/src/target/openrisc/or1k_du_adv.c b/src/target/openrisc/or1k_du_adv.c index e4c89e5b52..e4003a213d 100644 --- a/src/target/openrisc/or1k_du_adv.c +++ b/src/target/openrisc/or1k_du_adv.c @@ -22,8 +22,9 @@ #include "or1k_du.h" #include "jsp_server.h" -#include +#include #include +#include #define JSP_BANNER "\n\r" \ "******************************\n\r" \ @@ -67,13 +68,6 @@ #define DBG_CPU_CR_STALL 0x01 #define DBG_CPU_CR_RESET 0x02 -/* Polynomial for the CRC calculation - * Yes, it's backwards. Yes, this is on purpose. - * The hardware is designed this way to save on logic and routing, - * and it's really all the same to us here. - */ -#define ADBG_CRC_POLY 0xedb88320 - /* These are for the internal registers in the Wishbone module * The first is the length of the index register, * the indexes of the various registers are defined after that. @@ -133,20 +127,6 @@ static struct or1k_du or1k_du_adv; static const char * const chain_name[] = {"WISHBONE", "CPU0", "CPU1", "JSP"}; -static uint32_t adbg_compute_crc(uint32_t crc, uint32_t data_in, - int length_bits) -{ - for (int i = 0; i < length_bits; i++) { - uint32_t d, c; - d = ((data_in >> i) & 0x1) ? 0xffffffff : 0; - c = (crc & 0x1) ? 0xffffffff : 0; - crc = crc >> 1; - crc = crc ^ ((d ^ c) & ADBG_CRC_POLY); - } - - return crc; -} - static int find_status_bit(void *_buf, int len) { int i = 0; @@ -522,9 +502,8 @@ retry_read_full: memcpy(data, in_buffer, total_size_bytes); memcpy(&crc_read, &in_buffer[total_size_bytes], 4); - uint32_t crc_calc = 0xffffffff; - for (int i = 0; i < total_size_bytes; i++) - crc_calc = adbg_compute_crc(crc_calc, data[i], 8); + uint32_t crc_calc = crc32_le(CRC32_POLY_LE, 0xffffffff, data, + total_size_bytes); if (crc_calc != crc_read) { LOG_WARNING("CRC ERROR! Computed 0x%08" PRIx32 ", read CRC 0x%08" PRIx32, crc_calc, crc_read); @@ -650,9 +629,8 @@ retry_full_write: field[0].out_value = &value; field[0].in_value = NULL; - uint32_t crc_calc = 0xffffffff; - for (int i = 0; i < (count * size); i++) - crc_calc = adbg_compute_crc(crc_calc, data[i], 8); + uint32_t crc_calc = crc32_le(CRC32_POLY_LE, 0xffffffff, data, + count * size); field[1].num_bits = count * size * 8; field[1].out_value = data;