From 9cff66449a6f0bc32b1229fee455c4363acc15ed Mon Sep 17 00:00:00 2001 From: Patrick Date: Mon, 4 Nov 2024 16:53:35 +0100 Subject: [PATCH] =?UTF-8?q?=C2=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- benchies/embench/CMakeLists.txt | 2 +- .../embench/benchemarks/aha-mont64/mont64.c | 342 ++ benchies/embench/benchemarks/crc32/crc_32.c | 221 + .../benchemarks/cubic/basicmath_small.c | 108 + benchies/embench/benchemarks/cubic/libcubic.c | 66 + benchies/embench/benchemarks/cubic/pi.h | 37 + benchies/embench/benchemarks/cubic/snipmath.h | 57 + benchies/embench/benchemarks/cubic/sniptype.h | 39 + benchies/embench/benchemarks/edn/libedn.c | 421 ++ .../embench/benchemarks/huffbench/.gitignore | 1 + .../benchemarks/huffbench/libhuffbench.c | 501 ++ .../benchemarks/matmult-int/matmult-int.c | 270 + benchies/embench/benchemarks/md5sum/md5.c | 245 + .../embench/benchemarks/minver/libminver.c | 292 ++ benchies/embench/benchemarks/nbody/nbody.c | 288 ++ .../benchemarks/nettle-aes/nettle-aes.c | 1181 +++++ .../benchemarks/nettle-sha256/nettle-sha256.c | 490 ++ .../benchemarks/nsichneu/libnsichneu.c | 4594 +++++++++++++++++ .../benchemarks/picojpeg/libpicojpeg.c | 2528 +++++++++ .../embench/benchemarks/picojpeg/picojpeg.h | 150 + .../benchemarks/picojpeg/picojpeg_test.c | 214 + .../benchemarks/primecount/primecount.c | 181 + .../embench/benchemarks/qrduino/ecctable.h | 65 + benchies/embench/benchemarks/qrduino/qrbits.h | 26 + .../embench/benchemarks/qrduino/qrencode.c | 645 +++ .../embench/benchemarks/qrduino/qrencode.h | 46 + .../embench/benchemarks/qrduino/qrframe.c | 325 ++ benchies/embench/benchemarks/qrduino/qrtest.c | 99 + .../benchemarks/sglib-combined/combined.c | 313 ++ .../benchemarks/sglib-combined/sglib.h | 1968 +++++++ benchies/embench/benchemarks/slre/libslre.c | 625 +++ benchies/embench/benchemarks/slre/slre.h | 58 + benchies/embench/benchemarks/st/libst.c | 220 + .../benchemarks/statemate/libstatemate.c | 1501 ++++++ .../embench/benchemarks/tarfind/tarfind.c | 122 + benchies/embench/benchemarks/ud/libud.c | 236 + .../benchemarks/wikisort/libwikisort.c | 1117 ++++ .../embench embench-iot master src.zip | Bin 0 -> 544774 bytes benchies/embench/prj.conf | 8 +- benchies/embench/src/beebsc.c | 189 + benchies/embench/src/beebsc.h | 65 + benchies/embench/src/support.h | 1 + benchies/linpack/prj.conf | 3 +- 43 files changed, 19853 insertions(+), 7 deletions(-) create mode 100644 benchies/embench/benchemarks/aha-mont64/mont64.c create mode 100644 benchies/embench/benchemarks/crc32/crc_32.c create mode 100644 benchies/embench/benchemarks/cubic/basicmath_small.c create mode 100644 benchies/embench/benchemarks/cubic/libcubic.c create mode 100644 benchies/embench/benchemarks/cubic/pi.h create mode 100644 benchies/embench/benchemarks/cubic/snipmath.h create mode 100644 benchies/embench/benchemarks/cubic/sniptype.h create mode 100644 benchies/embench/benchemarks/edn/libedn.c create mode 100644 benchies/embench/benchemarks/huffbench/.gitignore create mode 100644 benchies/embench/benchemarks/huffbench/libhuffbench.c create mode 100644 benchies/embench/benchemarks/matmult-int/matmult-int.c create mode 100644 benchies/embench/benchemarks/md5sum/md5.c create mode 100644 benchies/embench/benchemarks/minver/libminver.c create mode 100644 benchies/embench/benchemarks/nbody/nbody.c create mode 100644 benchies/embench/benchemarks/nettle-aes/nettle-aes.c create mode 100644 benchies/embench/benchemarks/nettle-sha256/nettle-sha256.c create mode 100644 benchies/embench/benchemarks/nsichneu/libnsichneu.c create mode 100644 benchies/embench/benchemarks/picojpeg/libpicojpeg.c create mode 100644 benchies/embench/benchemarks/picojpeg/picojpeg.h create mode 100644 benchies/embench/benchemarks/picojpeg/picojpeg_test.c create mode 100644 benchies/embench/benchemarks/primecount/primecount.c create mode 100644 benchies/embench/benchemarks/qrduino/ecctable.h create mode 100644 benchies/embench/benchemarks/qrduino/qrbits.h create mode 100644 benchies/embench/benchemarks/qrduino/qrencode.c create mode 100644 benchies/embench/benchemarks/qrduino/qrencode.h create mode 100644 benchies/embench/benchemarks/qrduino/qrframe.c create mode 100644 benchies/embench/benchemarks/qrduino/qrtest.c create mode 100644 benchies/embench/benchemarks/sglib-combined/combined.c create mode 100644 benchies/embench/benchemarks/sglib-combined/sglib.h create mode 100644 benchies/embench/benchemarks/slre/libslre.c create mode 100644 benchies/embench/benchemarks/slre/slre.h create mode 100644 benchies/embench/benchemarks/st/libst.c create mode 100644 benchies/embench/benchemarks/statemate/libstatemate.c create mode 100644 benchies/embench/benchemarks/tarfind/tarfind.c create mode 100644 benchies/embench/benchemarks/ud/libud.c create mode 100644 benchies/embench/benchemarks/wikisort/libwikisort.c create mode 100644 benchies/embench/embench embench-iot master src.zip create mode 100644 benchies/embench/src/beebsc.c create mode 100644 benchies/embench/src/beebsc.h diff --git a/benchies/embench/CMakeLists.txt b/benchies/embench/CMakeLists.txt index 7bc2f18540..d466583ca5 100644 --- a/benchies/embench/CMakeLists.txt +++ b/benchies/embench/CMakeLists.txt @@ -5,4 +5,4 @@ find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) project(blinky) #add_compile_definitions(DEBUG) -target_sources(app PRIVATE src/main.c src/bench.c) +target_sources(app PRIVATE src/main.c src/beebsc.c benchemarks/huffbench/libhuffbench.c) diff --git a/benchies/embench/benchemarks/aha-mont64/mont64.c b/benchies/embench/benchemarks/aha-mont64/mont64.c new file mode 100644 index 0000000000..106557c9cd --- /dev/null +++ b/benchies/embench/benchemarks/aha-mont64/mont64.c @@ -0,0 +1,342 @@ +/* BEEBS aha-mont64 benchmark + + This version, copyright (C) 2013-2019 Embecosm Limited and University of + Bristol + + Contributor James Pallister + Contributor Jeremy Bennett + + This file is part of Embench and was formerly part of the Bristol/Embecosm + Embedded Benchmark Suite. + + SPDX-License-Identifier: GPL-3.0-or-later + + Some of this code is referenced by the book the Hacker's Delight (which + placed it in the public domain). See http://www.hackersdelight.org/ */ + +#include "../../src/support.h" + +/* This scale factor will be changed to equalise the runtime of the + benchmarks. */ +#define LOCAL_SCALE_FACTOR 423 + +/* Computes a*b mod m using Montgomery multiplication (MM). a, b, and m +are unsigned numbers with a, b < m < 2**64, and m odd. The code does +some 128-bit arithmetic. + The variable r is fixed at 2**64, and its log base 2 at 64. + Works with gcc on Windows and Linux. */ + +#include +#include +#include + +typedef uint64_t uint64; +typedef int64_t int64; + +/* ---------------------------- mulul64 ----------------------------- */ + +/* Multiply unsigned long 64-bit routine, i.e., 64 * 64 ==> 128. +Parameters u and v are multiplied and the 128-bit product is placed in +(*whi, *wlo). If __int128 is not defined by the compiler, we fall back +to Knuth's Algorithm M from [Knu2] section 4.3.1. Derived from muldwu.c +in the Hacker's Delight collection. */ + +#ifdef __SIZEOF_INT128__ +void +mulul64 (uint64 u, uint64 v, uint64 * whi, uint64 * wlo) +{ + unsigned __int128 result; + + result = (unsigned __int128)u * v; + + *wlo = result; + *whi = result >> 64; +} +#else +void +mulul64 (uint64 u, uint64 v, uint64 * whi, uint64 * wlo) +{ + uint64 u0, u1, v0, v1, k, t; + uint64 w0, w1, w2; + + u1 = u >> 32; + u0 = u & 0xFFFFFFFF; + v1 = v >> 32; + v0 = v & 0xFFFFFFFF; + + t = u0 * v0; + w0 = t & 0xFFFFFFFF; + k = t >> 32; + + t = u1 * v0 + k; + w1 = t & 0xFFFFFFFF; + w2 = t >> 32; + + t = u0 * v1 + w1; + k = t >> 32; + + *wlo = (t << 32) + w0; + *whi = u1 * v1 + w2 + k; + + return; +} +#endif + +/* ---------------------------- modul64 ----------------------------- */ + +uint64 +modul64 (uint64 x, uint64 y, uint64 z) +{ + + /* Divides (x || y) by z, for 64-bit integers x, y, + and z, giving the remainder (modulus) as the result. + Must have x < z (to get a 64-bit result). This is + checked for. */ + + int64 i, t; + + for (i = 1; i <= 64; i++) + { // Do 64 times. + t = (int64) x >> 63; // All 1's if x(63) = 1. + x = (x << 1) | (y >> 63); // Shift x || y left + y = y << 1; // one bit. + if ((x | t) >= z) + { + x = x - z; + y = y + 1; + } + } + return x; // Quotient is y. +} + +/* ---------------------------- montmul ----------------------------- */ + +uint64 +montmul (uint64 abar, uint64 bbar, uint64 m, uint64 mprime) +{ + + uint64 thi, tlo, tm, tmmhi, tmmlo, uhi, ulo, ov; + + /* t = abar*bbar. */ + + mulul64 (abar, bbar, &thi, &tlo); // t = abar*bbar. + + /* Now compute u = (t + ((t*mprime) & mask)*m) >> 64. + The mask is fixed at 2**64-1. Because it is a 64-bit + quantity, it suffices to compute the low-order 64 + bits of t*mprime, which means we can ignore thi. */ + + tm = tlo * mprime; + + mulul64 (tm, m, &tmmhi, &tmmlo); // tmm = tm*m. + + ulo = tlo + tmmlo; // Add t to tmm + uhi = thi + tmmhi; // (128-bit add). + if (ulo < tlo) + uhi = uhi + 1; // Allow for a carry. + + // The above addition can overflow. Detect that here. + + ov = (uhi < thi) | ((uhi == thi) & (ulo < tlo)); + + ulo = uhi; // Shift u right + uhi = 0; // 64 bit positions. + +// if (ov > 0 || ulo >= m) // If u >= m, +// ulo = ulo - m; // subtract m from u. + ulo = ulo - (m & -(ov | (ulo >= m))); // Alternative + // with no branching. + + return ulo; +} + +/* ---------------------------- xbinGCD ----------------------------- */ + +/* C program implementing the extended binary GCD algorithm. C.f. +http://www.ucl.ac.uk/~ucahcjm/combopt/ext_gcd_python_programs.pdf. This +is a modification of that routine in that we find s and t s.t. + gcd(a, b) = s*a - t*b, +rather than the same expression except with a + sign. + This routine has been greatly simplified to take advantage of the +facts that in the MM use, argument a is a power of 2, and b is odd. Thus +there are no common powers of 2 to eliminate in the beginning. The +parent routine has two loops. The first drives down argument a until it +is 1, modifying u and v in the process. The second loop modifies s and +t, but because a = 1 on entry to the second loop, it can be easily seen +that the second loop doesn't alter u or v. Hence the result we want is u +and v from the end of the first loop, and we can delete the second loop. + The intermediate and final results are always > 0, so there is no +trouble with negative quantities. Must have a either 0 or a power of 2 +<= 2**63. A value of 0 for a is treated as 2**64. b can be any 64-bit +value. + Parameter a is half what it "should" be. In other words, this function +does not find u and v st. u*a - v*b = 1, but rather u*(2a) - v*b = 1. */ + +void +xbinGCD (uint64 a, uint64 b, volatile uint64 * pu, volatile uint64 * pv) +{ + uint64 alpha, beta, u, v; + + u = 1; + v = 0; + alpha = a; + beta = b; // Note that alpha is + // even and beta is odd. + + /* The invariant maintained from here on is: + a = u*2*alpha - v*beta. */ + +// printf("Before, a u v = %016llx %016llx %016llx\n", a, u, v); + while (a > 0) + { + a = a >> 1; + if ((u & 1) == 0) + { // Delete a common + u = u >> 1; + v = v >> 1; // factor of 2 in + } // u and v. + else + { + /* We want to set u = (u + beta) >> 1, but + that can overflow, so we use Dietz's method. */ + u = ((u ^ beta) >> 1) + (u & beta); + v = (v >> 1) + alpha; + } +// printf("After, a u v = %016llx %016llx %016llx\n", a, u, v); + } + +// printf("At end, a u v = %016llx %016llx %016llx\n", a, u, v); + *pu = u; + *pv = v; + return; +} + +/* ------------------------------ main ------------------------------ */ +static uint64 in_a, in_b, in_m; + +static int benchmark_body (int rpt); + +void +warm_caches (int heat) +{ + int res = benchmark_body (heat); + + return; +} + + +int +benchmark (void) +{ + return benchmark_body (LOCAL_SCALE_FACTOR * CPU_MHZ); +} + + +static int __attribute__ ((noinline)) +benchmark_body (int rpt) +{ + int i; + int errors; + + for (i = 0; i < rpt; i++) + { + uint64 a, b, m, hr, p1hi, p1lo, p1, p, abar, bbar; + uint64 phi, plo; + volatile uint64 rinv, mprime; + errors = 0; + + m = in_m; // Must be odd. + b = in_b; // Must be smaller than m. + a = in_a; // Must be smaller than m. + + /* The simple calculation: This computes (a*b)**4 (mod m) correctly for all a, + b, m < 2**64. */ + + mulul64 (a, b, &p1hi, &p1lo); // Compute a*b (mod m). + p1 = modul64 (p1hi, p1lo, m); + mulul64 (p1, p1, &p1hi, &p1lo); // Compute (a*b)**2 (mod m). + p1 = modul64 (p1hi, p1lo, m); + mulul64 (p1, p1, &p1hi, &p1lo); // Compute (a*b)**4 (mod m). + p1 = modul64 (p1hi, p1lo, m); + + /* The MM method uses a quantity r that is the smallest power of 2 + that is larger than m, and hence also larger than a and b. Here we + deal with a variable hr that is just half of r. This is because r can + be as large as 2**64, which doesn't fit in one 64-bit word. So we + deal with hr, where 2**63 <= hr <= 1, and make the appropriate + adjustments wherever it is used. + We fix r at 2**64, and its log base 2 at 64. It doesn't hurt if + they are too big, it's just that some quantities (e.g., mprime) come + out larger than they would otherwise be. */ + + hr = 0x8000000000000000LL; + + /* Now, for the MM method, first compute the quantities that are + functions of only r and m, and hence are relatively constant. These + quantities can be used repeatedly, without change, when raising a + number to a large power modulo m. + First use the extended GCD algorithm to compute two numbers rinv + and mprime, such that + + r*rinv - m*mprime = 1 + + Reading this nodulo m, clearly r*rinv = 1 (mod m), i.e., rinv is the + multiplicative inverse of r modulo m. It is needed to convert the + result of MM back to a normal number. The other calculated number, + mprime, is used in the MM algorithm. */ + + xbinGCD (hr, m, &rinv, &mprime); // xbinGCD, in effect, doubles hr. + + /* Do a partial check of the results. It is partial because the + multiplications here give only the low-order half (64 bits) of the + products. */ + + if (2 * hr * rinv - m * mprime != 1) + { + errors = 1; + } + + /* Compute abar = a*r(mod m) and bbar = b*r(mod m). That is, abar = + (a << 64)%m, and bbar = (b << 64)%m. */ + + abar = modul64 (a, 0, m); + bbar = modul64 (b, 0, m); + + p = montmul (abar, bbar, m, mprime); /* Compute a*b (mod m). */ + p = montmul (p, p, m, mprime); /* Compute (a*b)**2 (mod m). */ + p = montmul (p, p, m, mprime); /* Compute (a*b)**4 (mod m). */ + + /* Convert p back to a normal number by p = (p*rinv)%m. */ + + mulul64 (p, rinv, &phi, &plo); + p = modul64 (phi, plo, m); + if (p != p1) + errors = 1; + } + + return errors; +} + +void +initialise_benchmark (void) +{ + in_m = 0xfae849273928f89fLL; // Must be odd. + in_b = 0x14736defb9330573LL; // Must be smaller than m. + in_a = 0x0549372187237fefLL; // Must be smaller than m. +} + +// r is the number of errors therefore if r = 0 then output a 1 for correct + +int +verify_benchmark (int r) +{ + return 0 == r; +} + + +/* + Local Variables: + mode: C + c-file-style: "gnu" + End: +*/ diff --git a/benchies/embench/benchemarks/crc32/crc_32.c b/benchies/embench/benchemarks/crc32/crc_32.c new file mode 100644 index 0000000000..73d37442ff --- /dev/null +++ b/benchies/embench/benchemarks/crc32/crc_32.c @@ -0,0 +1,221 @@ +/* This file is part of the Bristol/Embecosm Embedded Benchmark Suite. + + This version, copyright (C) 2013-2019 Embecosm Limited and University of + Bristol + + Contributor James Pallister + Contributor Jeremy Bennett + + This file is part of Embench and was formerly part of the Bristol/Embecosm + Embedded Benchmark Suite. + + SPDX-License-Identifier: GPL-3.0-or-later + + Code originally from: From http://www.snippets.org/. This original code is + FREE with no restrictions. */ + +/* CRC - 32 BIT ANSI X3.66 CRC checksum files */ + +#include "../../src/support.h" + +/* This scale factor will be changed to equalise the runtime of the + benchmarks. */ +#define LOCAL_SCALE_FACTOR 170 + +#include + +#ifdef __TURBOC__ +#pragma warn -cln +#endif + +/**********************************************************************\ + |* Demonstration program to compute the 32-bit CRC used as the frame *| + |* check sequence in ADCCP (ANSI X3.66, also known as FIPS PUB 71 *| + |* and FED-STD-1003, the U.S. versions of CCITT's X.25 link-level *| + |* protocol). The 32-bit FCS was added via the Federal Register, *| + |* 1 June 1982, p.23798. I presume but don't know for certain that *| + |* this polynomial is or will be included in CCITT V.41, which *| + |* defines the 16-bit CRC (often called CRC-CCITT) polynomial. FIPS *| + |* PUB 78 says that the 32-bit FCS reduces otherwise undetected *| + |* errors by a factor of 10^-5 over 16-bit FCS. *| + \**********************************************************************/ + +/* Some basic types. */ +typedef unsigned char BYTE; +typedef unsigned long DWORD; +typedef unsigned short WORD; + +#define UPDC32(octet,crc) (crc_32_tab[((crc)^((BYTE)octet)) & 0xff] ^ ((crc) >> 8)) + +/* Need an unsigned type capable of holding 32 bits; */ + +typedef DWORD UNS_32_BITS; + +/* Copyright (C) 1986 Gary S. Brown. You may use this program, or + code or tables extracted from it, as desired without restriction.*/ + +/* First, the polynomial itself and its table of feedback terms. The */ +/* polynomial is */ +/* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */ +/* Note that we take it "backwards" and put the highest-order term in */ +/* the lowest-order bit. The X^32 term is "implied"; the LSB is the */ +/* X^31 term, etc. The X^0 term (usually shown as "+1") results in */ +/* the MSB being 1. */ + +/* Note that the usual hardware shift register implementation, which */ +/* is what we're using (we're merely optimizing it by doing eight-bit */ +/* chunks at a time) shifts bits into the lowest-order term. In our */ +/* implementation, that means shifting towards the right. Why do we */ +/* do it this way? Because the calculated CRC must be transmitted in */ +/* order from highest-order term to lowest-order term. UARTs transmit */ +/* characters in order from LSB to MSB. By storing the CRC this way, */ +/* we hand it to the UART in the order low-byte to high-byte; the UART */ +/* sends each low-bit to hight-bit; and the result is transmission bit */ +/* by bit from highest- to lowest-order term without requiring any bit */ +/* shuffling on our part. Reception works similarly. */ + +/* The feedback terms table consists of 256, 32-bit entries. Notes: */ +/* */ +/* 1. The table can be generated at runtime if desired; code to do so */ +/* is shown later. It might not be obvious, but the feedback */ +/* terms simply represent the results of eight shift/xor opera- */ +/* tions for all combinations of data and CRC register values. */ +/* */ +/* 2. The CRC accumulation logic is the same for all CRC polynomials, */ +/* be they sixteen or thirty-two bits wide. You simply choose the */ +/* appropriate table. Alternatively, because the table can be */ +/* generated at runtime, you can start by generating the table for */ +/* the polynomial in question and use exactly the same "updcrc", */ +/* if your application needn't simultaneously handle two CRC */ +/* polynomials. (Note, however, that XMODEM is strange.) */ +/* */ +/* 3. For 16-bit CRCs, the table entries need be only 16 bits wide; */ +/* of course, 32-bit entries work OK if the high 16 bits are zero. */ +/* */ +/* 4. The values must be right-shifted by eight bits by the "updcrc" */ +/* logic; the shift must be unsigned (bring in zeroes). On some */ +/* hardware you could probably optimize the shift in assembler by */ +/* using byte-swap instructions. */ + +/* The BEEBS version of this code uses its own version of rand, to + avoid library/architecture variation. */ + +static const UNS_32_BITS crc_32_tab[] = { /* CRC polynomial 0xedb88320 */ + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, + 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, + 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, + 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, + 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, + 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, + 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, + 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, + 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, + 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, + 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, + 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, + 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, + 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, + 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, + 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, + 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, + 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d +}; + + +DWORD +crc32pseudo () +{ + int i; + register DWORD oldcrc32; + + oldcrc32 = 0xFFFFFFFF; + + for (i = 0; i < 1024; ++i) + { + oldcrc32 = UPDC32 (rand_beebs (), oldcrc32); + } + + return ~oldcrc32; +} + +void +initialise_benchmark (void) +{ +} + + +static int benchmark_body (int rpt); + +void +warm_caches (int heat) +{ + int res = benchmark_body (heat); + + return; +} + + +int +benchmark (void) +{ + return benchmark_body (LOCAL_SCALE_FACTOR * CPU_MHZ); +} + + +static int __attribute__ ((noinline)) +benchmark_body (int rpt) +{ + int i; + DWORD r; + + for (i = 0; i < rpt; i++) + { + srand_beebs (0); + r = crc32pseudo (); + } + + return (int) (r % 32768); +} + + +int +verify_benchmark (int r) +{ + return 11433 == r; +} + + +/* vim: set ts=3 sw=3 et: */ + + +/* + Local Variables: + mode: C + c-file-style: "gnu" + End: +*/ diff --git a/benchies/embench/benchemarks/cubic/basicmath_small.c b/benchies/embench/benchemarks/cubic/basicmath_small.c new file mode 100644 index 0000000000..90f364fc5b --- /dev/null +++ b/benchies/embench/benchemarks/cubic/basicmath_small.c @@ -0,0 +1,108 @@ +/* BEEBS cubic benchmark + + Contributor: James Pallister + + This file is part of Embench and was formerly part of the Bristol/Embecosm + Embedded Benchmark Suite. + + SPDX-License-Identifier: GPL-3.0-or-later */ + +#include +#include "../../src/support.h" +#include "snipmath.h" + +/* This scale factor will be changed to equalise the runtime of the + benchmarks. */ +#define LOCAL_SCALE_FACTOR 10 + + + + +static int soln_cnt0; +static int soln_cnt1; +static double res0[3]; +static double res1; + + +int +verify_benchmark (int res __attribute ((unused)) ) +{ + static const double exp_res0[3] = {2.0, 6.0, 2.5}; + const double exp_res1 = 2.5; + return (3 == soln_cnt0) + && double_eq_beebs(exp_res0[0], res0[0]) + && double_eq_beebs(exp_res0[1], res0[1]) + && double_eq_beebs(exp_res0[2], res0[2]) + && (1 == soln_cnt1) + && double_eq_beebs(exp_res1, res1); +} + + +void +initialise_benchmark (void) +{ +} + + +static int benchmark_body (int rpt); + +void +warm_caches (int heat) +{ + int res = benchmark_body (heat); + + return; +} + + +int +benchmark (void) +{ + return benchmark_body (LOCAL_SCALE_FACTOR * CPU_MHZ); +} + + +static int +benchmark_body (int rpt) +{ + int i; + + for (i = 0; i < rpt; i++) + { + double a1 = 1.0, b1 = -10.5, c1 = 32.0, d1 = -30.0; + double a2 = 1.0, b2 = -4.5, c2 = 17.0, d2 = -30.0; + double a3 = 1.0, b3 = -3.5, c3 = 22.0, d3 = -31.0; + double a4 = 1.0, b4 = -13.7, c4 = 1.0, d4 = -35.0; + int solutions; + + double output[48] = {0}; + double *output_pos = &(output[0]); + + /* solve some cubic functions */ + /* should get 3 solutions: 2, 6 & 2.5 */ + SolveCubic(a1, b1, c1, d1, &solutions, output); + soln_cnt0 = solutions; + memcpy(res0,output,3*sizeof(res0[0])); + /* should get 1 solution: 2.5 */ + SolveCubic(a2, b2, c2, d2, &solutions, output); + soln_cnt1 = solutions; + res1 = output[0]; + SolveCubic(a3, b3, c3, d3, &solutions, output); + SolveCubic(a4, b4, c4, d4, &solutions, output); + /* Now solve some random equations */ + for(a1=1;a1<3;a1++) { + for(b1=10;b1>8;b1--) { + for(c1=5;c1<6;c1+=0.5) { + for(d1=-1;d1>-3;d1--) { + SolveCubic(a1, b1, c1, d1, &solutions, output_pos); + } + } + } + } + } + + return 0; +} + + +/* vim: set ts=3 sw=3 et: */ diff --git a/benchies/embench/benchemarks/cubic/libcubic.c b/benchies/embench/benchemarks/cubic/libcubic.c new file mode 100644 index 0000000000..9dac098d79 --- /dev/null +++ b/benchies/embench/benchemarks/cubic/libcubic.c @@ -0,0 +1,66 @@ +/* BEEBS cubic benchmark + + This version, copyright (C) 2013-2019 Embecosm Limited and University of + Bristol + + Contributor: James Pallister + Contributor Jeremy Bennett + + This file is part of Embench and was formerly part of the Bristol/Embecosm + Embedded Benchmark Suite. + + SPDX-License-Identifier: GPL-3.0-or-later + + The original code is from http://www.snippets.org/. */ + +/* +++Date last modified: 05-Jul-1997 */ + +/* + ** CUBIC.C - Solve a cubic polynomial + ** public domain by Ross Cottrell + */ + +#include +#include "snipmath.h" + +void +SolveCubic (double a, double b, double c, double d, int *solutions, double *x) +{ + long double a1 = (long double) (b / a); + long double a2 = (long double) (c / a); + long double a3 = (long double) (d / a); + long double Q = (a1 * a1 - 3.0L * a2) / 9.0L; + long double R = (2.0L * a1 * a1 * a1 - 9.0L * a1 * a2 + 27.0L * a3) / 54.0L; + double R2_Q3 = (double) (R * R - Q * Q * Q); + + double theta; + + if (R2_Q3 <= 0) + { + *solutions = 3; + theta = acos (((double) R) / sqrt ((double) (Q * Q * Q))); + x[0] = -2.0 * sqrt ((double) Q) * cos (theta / 3.0) - a1 / 3.0; + x[1] = + -2.0 * sqrt ((double) Q) * cos ((theta + 2.0 * PI) / 3.0) - a1 / 3.0; + x[2] = + -2.0 * sqrt ((double) Q) * cos ((theta + 4.0 * PI) / 3.0) - a1 / 3.0; + } + else + { + *solutions = 1; + x[0] = pow (sqrt (R2_Q3) + fabs ((double) R), 1 / 3.0); + x[0] += ((double) Q) / x[0]; + x[0] *= (R < 0.0L) ? 1 : -1; + x[0] -= (double) (a1 / 3.0L); + } +} + +/* vim: set ts=3 sw=3 et: */ + + +/* + Local Variables: + mode: C + c-file-style: "gnu" + End: +*/ diff --git a/benchies/embench/benchemarks/cubic/pi.h b/benchies/embench/benchemarks/cubic/pi.h new file mode 100644 index 0000000000..baeb591369 --- /dev/null +++ b/benchies/embench/benchemarks/cubic/pi.h @@ -0,0 +1,37 @@ +/* BEEBS cubic benchmark + + This version, copyright (C) 2013-2019 Embecosm Limited and University of + Bristol + + Contributor: James Pallister + Contributor Jeremy Bennett + + This file is part of Embench and was formerly part of the Bristol/Embecosm + Embedded Benchmark Suite. + + SPDX-License-Identifier: GPL-3.0-or-later + + The original code is from http://www.snippets.org/. */ + +/* +++Date last modified: 05-Jul-1997 */ + +#ifndef PI__H +#define PI__H + +#include + +#ifndef PI +#define PI (4*atan(1)) +#endif + +#endif /* PI__H */ + +/* vim: set ts=3 sw=3 et: */ + + +/* + Local Variables: + mode: C + c-file-style: "gnu" + End: +*/ diff --git a/benchies/embench/benchemarks/cubic/snipmath.h b/benchies/embench/benchemarks/cubic/snipmath.h new file mode 100644 index 0000000000..ec14182f5f --- /dev/null +++ b/benchies/embench/benchemarks/cubic/snipmath.h @@ -0,0 +1,57 @@ +/* BEEBS cubic benchmark + + This version, copyright (C) 2013-2019 Embecosm Limited and University of + Bristol + + Contributor: James Pallister + Contributor Jeremy Bennett + + This file is part of Embench and was formerly part of the Bristol/Embecosm + Embedded Benchmark Suite. + + SPDX-License-Identifier: GPL-3.0-or-later + + The original code is from http://www.snippets.org/. */ + +/* +++Date last modified: 05-Jul-1997 */ + +/* + ** SNIPMATH.H - Header file for SNIPPETS math functions and macros + */ + +#ifndef SNIPMATH__H +#define SNIPMATH__H + +#include + +#include "pi.h" +#include "sniptype.h" + +/* + ** Callable library functions begin here + */ + +void SolveCubic (double a, double b, double c, /* Cubic.C */ + double d, int *solutions, double *x); + + +/* + ** File: ISQRT.C + */ + +struct int_sqrt +{ + unsigned sqrt, frac; +}; + +#endif /* SNIPMATH__H */ + +/* vim: set ts=3 sw=3 et: */ + + +/* + Local Variables: + mode: C + c-file-style: "gnu" + End: +*/ diff --git a/benchies/embench/benchemarks/cubic/sniptype.h b/benchies/embench/benchemarks/cubic/sniptype.h new file mode 100644 index 0000000000..681e0092a5 --- /dev/null +++ b/benchies/embench/benchemarks/cubic/sniptype.h @@ -0,0 +1,39 @@ +/* BEEBS cubic benchmark + + This version, copyright (C) 2013-2019 Embecosm Limited and University of + Bristol + + Contributor: James Pallister + Contributor Jeremy Bennett + + This file is part of Embench and was formerly part of the Bristol/Embecosm + Embedded Benchmark Suite. + + SPDX-License-Identifier: GPL-3.0-or-later + + The original code is from http://www.snippets.org/. */ + +/* +++Date last modified: 05-Jul-1997 */ + +/* + ** SNIPTYPE.H - Include file for SNIPPETS data types and commonly used macros + */ + +#ifndef SNIPTYPE__H +#define SNIPTYPE__H + +typedef unsigned char BYTE; +typedef unsigned long DWORD; +typedef unsigned short WORD; + +#endif /* SNIPTYPE__H */ + +/* vim: set ts=3 sw=3 et: */ + + +/* + Local Variables: + mode: C + c-file-style: "gnu" + End: +*/ diff --git a/benchies/embench/benchemarks/edn/libedn.c b/benchies/embench/benchemarks/edn/libedn.c new file mode 100644 index 0000000000..c26991b72f --- /dev/null +++ b/benchies/embench/benchemarks/edn/libedn.c @@ -0,0 +1,421 @@ +/* BEEBS edn benchmark + + This version, copyright (C) 2014-2019 Embecosm Limited and University of + Bristol + + Contributor James Pallister + Contributor Jeremy Bennett + + This file is part of Embench and was formerly part of the Bristol/Embecosm + Embedded Benchmark Suite. + + SPDX-License-Identifier: GPL-3.0-or-later + + Original code from: WCET Benchmarks, + http://www.mrtc.mdh.se/projects/wcet/benchmarks.html + + Permission to license under GPL obtained by email from Björn Lisper */ + +/* + * MDH WCET BENCHMARK SUITE. + */ + +/************************************************************************ +* Simple vector multiply * +************************************************************************/ + +/* + * Changes: JG 2005/12/22: Inserted prototypes, changed type of main to int + * etc. Added parenthesis in expressions in jpegdct. Removed unused variable + * dx. Changed int to long to avoid problems when compiling to 16 bit target + * Indented program. + * JG 2006-01-27: Removed code in codebook + */ + +#include +#include "../../src/support.h" + +/* This scale factor will be changed to equalise the runtime of the + benchmarks. */ +#define LOCAL_SCALE_FACTOR 87 + + +#define N 100 +#define ORDER 50 + +void vec_mpy1 (short y[], const short x[], short scaler); +long int mac (const short *a, const short *b, long int sqr, long int *sum); +void fir (const short array1[], const short coeff[], long int output[]); +void fir_no_red_ld (const short x[], const short h[], long int y[]); +long int latsynth (short b[], const short k[], long int n, long int f); +void iir1 (const short *coefs, const short *input, long int *optr, + long int *state); +long int codebook (long int mask, long int bitchanged, long int numbasis, + long int codeword, long int g, const short *d, short ddim, + short theta); +void jpegdct (short *d, short *r); + +void +vec_mpy1 (short y[], const short x[], short scaler) +{ + long int i; + + for (i = 0; i < 150; i++) + y[i] += ((scaler * x[i]) >> 15); +} + + +/***************************************************** +* Dot Product * +*****************************************************/ +long int +mac (const short *a, const short *b, long int sqr, long int *sum) +{ + long int i; + long int dotp = *sum; + + for (i = 0; i < 150; i++) + { + dotp += b[i] * a[i]; + sqr += b[i] * b[i]; + } + + *sum = dotp; + return sqr; +} + + +/***************************************************** +* FIR Filter * +*****************************************************/ +void +fir (const short array1[], const short coeff[], long int output[]) +{ + long int i, j, sum; + + for (i = 0; i < N - ORDER; i++) + { + sum = 0; + for (j = 0; j < ORDER; j++) + { + sum += array1[i + j] * coeff[j]; + } + output[i] = sum >> 15; + } +} + +/**************************************************** +* FIR Filter with Redundant Load Elimination + +By doing two outer loops simultaneously, you can potentially reuse data (depending on the DSP architecture). +x and h only need to be loaded once, therefore reducing redundant loads. +This reduces memory bandwidth and power. +*****************************************************/ +void +fir_no_red_ld (const short x[], const short h[], long int y[]) +{ + long int i, j; + long int sum0, sum1; + short x0, x1, h0, h1; + for (j = 0; j < 100; j += 2) + { + sum0 = 0; + sum1 = 0; + x0 = x[j]; + for (i = 0; i < 32; i += 2) + { + x1 = x[j + i + 1]; + h0 = h[i]; + sum0 += x0 * h0; + sum1 += x1 * h0; + x0 = x[j + i + 2]; + h1 = h[i + 1]; + sum0 += x1 * h1; + sum1 += x0 * h1; + } + y[j] = sum0 >> 15; + y[j + 1] = sum1 >> 15; + } +} + +/******************************************************* +* Lattice Synthesis * +* This function doesn't follow the typical DSP multiply two vector operation, but it will point out the compiler's flexibility ********************************************************/ +long int +latsynth (short b[], const short k[], long int n, long int f) +{ + long int i; + + f -= b[n - 1] * k[n - 1]; + for (i = n - 2; i >= 0; i--) + { + f -= b[i] * k[i]; + b[i + 1] = b[i] + ((k[i] * (f >> 16)) >> 16); + } + b[0] = f >> 16; + return f; +} + +/***************************************************** +* IIR Filter * +*****************************************************/ +void +iir1 (const short *coefs, const short *input, long int *optr, long int *state) +{ + long int x; + long int t; + long int n; + + x = input[0]; + for (n = 0; n < 50; n++) + { + t = x + ((coefs[2] * state[0] + coefs[3] * state[1]) >> 15); + x = t + ((coefs[0] * state[0] + coefs[1] * state[1]) >> 15); + state[1] = state[0]; + state[0] = t; + coefs += 4; /* point to next filter coefs */ + state += 2; /* point to next filter states */ + } + *optr++ = x; +} + +/***************************************************** +* Vocoder Codebook Search * +*****************************************************/ +long int +codebook (long int mask, long int bitchanged, long int numbasis, + long int codeword, long int g, const short *d, short ddim, + short theta) +/* + * dfm (mask=d bitchanged=1 numbasis=17 codeword=e[0] , g=d, d=a, ddim=c, + * theta =1 + */ +{ + long int j; + + + /* + * Remove along with the code below. + * + long int tmpMask; + + tmpMask = mask << 1; + */ + for (j = bitchanged + 1; j <= numbasis; j++) + { + + + +/* + * The following code is removed since it gave a memory access exception. + * It is OK since the return value does not control the flow. + * The loop always iterates a fixed number of times independent of the loop body. + + if (theta == !(!(codeword & tmpMask))) + g += *(d + bitchanged * ddim + j); + else + g -= *(d + bitchanged * ddim + j); + tmpMask <<= 1; +*/ + } + return g; +} + + +/***************************************************** +* JPEG Discrete Cosine Transform * +*****************************************************/ +void +jpegdct (short *d, short *r) +{ + long int t[12]; + short i, j, k, m, n, p; + for (k = 1, m = 0, n = 13, p = 8; k <= 8; + k += 7, m += 3, n += 3, p -= 7, d -= 64) + { + for (i = 0; i < 8; i++, d += p) + { + for (j = 0; j < 4; j++) + { + t[j] = d[k * j] + d[k * (7 - j)]; + t[7 - j] = d[k * j] - d[k * (7 - j)]; + } + t[8] = t[0] + t[3]; + t[9] = t[0] - t[3]; + t[10] = t[1] + t[2]; + t[11] = t[1] - t[2]; + d[0] = (t[8] + t[10]) >> m; + d[4 * k] = (t[8] - t[10]) >> m; + t[8] = (short) (t[11] + t[9]) * r[10]; + d[2 * k] = t[8] + (short) ((t[9] * r[9]) >> n); + d[6 * k] = t[8] + (short) ((t[11] * r[11]) >> n); + t[0] = (short) (t[4] + t[7]) * r[2]; + t[1] = (short) (t[5] + t[6]) * r[0]; + t[2] = t[4] + t[6]; + t[3] = t[5] + t[7]; + t[8] = (short) (t[2] + t[3]) * r[8]; + t[2] = (short) t[2] * r[1] + t[8]; + t[3] = (short) t[3] * r[3] + t[8]; + d[7 * k] = (short) (t[4] * r[4] + t[0] + t[2]) >> n; + d[5 * k] = (short) (t[5] * r[6] + t[1] + t[3]) >> n; + d[3 * k] = (short) (t[6] * r[5] + t[1] + t[2]) >> n; + d[1 * k] = (short) (t[7] * r[7] + t[0] + t[3]) >> n; + } + } +} + +static short a[200]; +static short b[200]; +static short c; +static long int d; +static int e; +static long int output[200]; + + +void +initialise_benchmark (void) +{ +} + + +static int benchmark_body (int rpt); + +void +warm_caches (int heat) +{ + int res = benchmark_body (heat); + + return; +} + + +int +benchmark (void) +{ + return benchmark_body (LOCAL_SCALE_FACTOR * CPU_MHZ); +} + + +static int __attribute__ ((noinline)) +benchmark_body (int rpt) +{ + int j; + + for (j = 0; j < rpt; j++) + { + short unsigned int in_a[200] = { + 0x0000, 0x07ff, 0x0c00, 0x0800, 0x0200, 0xf800, 0xf300, 0x0400, + 0x0000, 0x07ff, 0x0c00, 0x0800, 0x0200, 0xf800, 0xf300, 0x0400, + 0x0000, 0x07ff, 0x0c00, 0x0800, 0x0200, 0xf800, 0xf300, 0x0400, + 0x0000, 0x07ff, 0x0c00, 0x0800, 0x0200, 0xf800, 0xf300, 0x0400, + 0x0000, 0x07ff, 0x0c00, 0x0800, 0x0200, 0xf800, 0xf300, 0x0400, + 0x0000, 0x07ff, 0x0c00, 0x0800, 0x0200, 0xf800, 0xf300, 0x0400, + 0x0000, 0x07ff, 0x0c00, 0x0800, 0x0200, 0xf800, 0xf300, 0x0400, + 0x0000, 0x07ff, 0x0c00, 0x0800, 0x0200, 0xf800, 0xf300, 0x0400, + 0x0000, 0x07ff, 0x0c00, 0x0800, 0x0200, 0xf800, 0xf300, 0x0400, + 0x0000, 0x07ff, 0x0c00, 0x0800, 0x0200, 0xf800, 0xf300, 0x0400, + 0x0000, 0x07ff, 0x0c00, 0x0800, 0x0200, 0xf800, 0xf300, 0x0400, + 0x0000, 0x07ff, 0x0c00, 0x0800, 0x0200, 0xf800, 0xf300, 0x0400, + 0x0000, 0x07ff, 0x0c00, 0x0800, 0x0200, 0xf800, 0xf300, 0x0400, + 0x0000, 0x07ff, 0x0c00, 0x0800, 0x0200, 0xf800, 0xf300, 0x0400, + 0x0000, 0x07ff, 0x0c00, 0x0800, 0x0200, 0xf800, 0xf300, 0x0400, + 0x0000, 0x07ff, 0x0c00, 0x0800, 0x0200, 0xf800, 0xf300, 0x0400, + 0x0000, 0x07ff, 0x0c00, 0x0800, 0x0200, 0xf800, 0xf300, 0x0400, + 0x0000, 0x07ff, 0x0c00, 0x0800, 0x0200, 0xf800, 0xf300, 0x0400, + 0x0000, 0x07ff, 0x0c00, 0x0800, 0x0200, 0xf800, 0xf300, 0x0400, + 0x0000, 0x07ff, 0x0c00, 0x0800, 0x0200, 0xf800, 0xf300, 0x0400, + 0x0000, 0x07ff, 0x0c00, 0x0800, 0x0200, 0xf800, 0xf300, 0x0400, + 0x0000, 0x07ff, 0x0c00, 0x0800, 0x0200, 0xf800, 0xf300, 0x0400, + 0x0000, 0x07ff, 0x0c00, 0x0800, 0x0200, 0xf800, 0xf300, 0x0400, + 0x0000, 0x07ff, 0x0c00, 0x0800, 0x0200, 0xf800, 0xf300, 0x0400, + 0x0000, 0x07ff, 0x0c00, 0x0800, 0x0200, 0xf800, 0xf300, 0x0400 + }; + short unsigned int in_b[200] = { + 0x0c60, 0x0c40, 0x0c20, 0x0c00, 0xf600, 0xf400, 0xf200, 0xf000, + 0x0c60, 0x0c40, 0x0c20, 0x0c00, 0xf600, 0xf400, 0xf200, 0xf000, + 0x0c60, 0x0c40, 0x0c20, 0x0c00, 0xf600, 0xf400, 0xf200, 0xf000, + 0x0c60, 0x0c40, 0x0c20, 0x0c00, 0xf600, 0xf400, 0xf200, 0xf000, + 0x0c60, 0x0c40, 0x0c20, 0x0c00, 0xf600, 0xf400, 0xf200, 0xf000, + 0x0c60, 0x0c40, 0x0c20, 0x0c00, 0xf600, 0xf400, 0xf200, 0xf000, + 0x0c60, 0x0c40, 0x0c20, 0x0c00, 0xf600, 0xf400, 0xf200, 0xf000, + 0x0c60, 0x0c40, 0x0c20, 0x0c00, 0xf600, 0xf400, 0xf200, 0xf000, + 0x0c60, 0x0c40, 0x0c20, 0x0c00, 0xf600, 0xf400, 0xf200, 0xf000, + 0x0c60, 0x0c40, 0x0c20, 0x0c00, 0xf600, 0xf400, 0xf200, 0xf000, + 0x0c60, 0x0c40, 0x0c20, 0x0c00, 0xf600, 0xf400, 0xf200, 0xf000, + 0x0c60, 0x0c40, 0x0c20, 0x0c00, 0xf600, 0xf400, 0xf200, 0xf000, + 0x0c60, 0x0c40, 0x0c20, 0x0c00, 0xf600, 0xf400, 0xf200, 0xf000, + 0x0c60, 0x0c40, 0x0c20, 0x0c00, 0xf600, 0xf400, 0xf200, 0xf000, + 0x0c60, 0x0c40, 0x0c20, 0x0c00, 0xf600, 0xf400, 0xf200, 0xf000, + 0x0c60, 0x0c40, 0x0c20, 0x0c00, 0xf600, 0xf400, 0xf200, 0xf000, + 0x0c60, 0x0c40, 0x0c20, 0x0c00, 0xf600, 0xf400, 0xf200, 0xf000, + 0x0c60, 0x0c40, 0x0c20, 0x0c00, 0xf600, 0xf400, 0xf200, 0xf000, + 0x0c60, 0x0c40, 0x0c20, 0x0c00, 0xf600, 0xf400, 0xf200, 0xf000, + 0x0c60, 0x0c40, 0x0c20, 0x0c00, 0xf600, 0xf400, 0xf200, 0xf000, + 0x0c60, 0x0c40, 0x0c20, 0x0c00, 0xf600, 0xf400, 0xf200, 0xf000, + 0x0c60, 0x0c40, 0x0c20, 0x0c00, 0xf600, 0xf400, 0xf200, 0xf000, + 0x0c60, 0x0c40, 0x0c20, 0x0c00, 0xf600, 0xf400, 0xf200, 0xf000, + 0x0c60, 0x0c40, 0x0c20, 0x0c00, 0xf600, 0xf400, 0xf200, 0xf000, + 0x0c60, 0x0c40, 0x0c20, 0x0c00, 0xf600, 0xf400, 0xf200, 0xf000 + }; + c = 0x3; + d = 0xAAAA; + e = 0xEEEE; + + for (int i = 0; i < 200; i++) + { + a[i] = in_a[i]; + b[i] = in_b[i]; + } + /* + * Declared as memory variable so it doesn't get optimized out + */ + + vec_mpy1 (a, b, c); + c = mac (a, b, (long int) c, (long int *) output); + fir (a, b, output); + fir_no_red_ld (a, b, output); + d = latsynth (a, b, N, d); + iir1 (a, b, &output[100], output); + e = codebook (d, 1, 17, e, d, a, c, 1); + jpegdct (a, b); + } + return 0; +} + +int +verify_benchmark (int unused) +{ + long int exp_output[200] = + { 3760, 4269, 3126, 1030, 2453, -4601, 1981, -1056, 2621, 4269, + 3058, 1030, 2378, -4601, 1902, -1056, 2548, 4269, 2988, 1030, + 2300, -4601, 1822, -1056, 2474, 4269, 2917, 1030, 2220, -4601, + 1738, -1056, 2398, 4269, 2844, 1030, 2140, -4601, 1655, -1056, + 2321, 4269, 2770, 1030, 2058, -4601, 1569, -1056, 2242, 4269, + 2152, 1030, 1683, -4601, 1627, -1056, 2030, 4269, 2080, 1030, + 1611, -4601, 1555, -1056, 1958, 4269, 2008, 1030, 1539, -4601, + 1483, -1056, 1886, 4269, 1935, 1030, 1466, -4601, 1410, -1056, + 1813, 4269, 1862, 1030, 1393, -4601, 1337, -1056, 1740, 4269, + 1789, 1030, 1320, -4601, 1264, -1056, 1667, 4269, 1716, 1030, + 1968, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + + return (0 == memcmp (output, exp_output, 200 * sizeof (output[0]))) + && (10243 == c) && (-441886230 == d) && (-441886230 == e); +} + + +/* + Local Variables: + mode: C + c-file-style: "gnu" + End: +*/ diff --git a/benchies/embench/benchemarks/huffbench/.gitignore b/benchies/embench/benchemarks/huffbench/.gitignore new file mode 100644 index 0000000000..f6f44059ad --- /dev/null +++ b/benchies/embench/benchemarks/huffbench/.gitignore @@ -0,0 +1 @@ +huffbench diff --git a/benchies/embench/benchemarks/huffbench/libhuffbench.c b/benchies/embench/benchemarks/huffbench/libhuffbench.c new file mode 100644 index 0000000000..0dc29b4ee3 --- /dev/null +++ b/benchies/embench/benchemarks/huffbench/libhuffbench.c @@ -0,0 +1,501 @@ +/* BEEBS cover benchmark + + This version, copyright (C) 2014-2019 Embecosm Limited and University of + Bristol + + Contributor James Pallister + Contributor Jeremy Bennett + + This file is part of Embench and was formerly part of the Bristol/Embecosm + Embedded Benchmark Suite. + + SPDX-License-Identifier: GPL-3.0-or-later + + Original version by Scott Robert Ladd + + huffbench + Standard C version + 17 April 2003 + + Written by Scott Robert Ladd (scott@coyotegulch.com) + No rights reserved. This is public domain software, for use by anyone. + + A data compression benchmark that can also be used as a fitness test + for evolving optimal compiler options via genetic algorithm. + + This program implements the Huffman compression algorithm. The code + is not the tightest or fastest possible C code; rather, it is a + relatively straight-forward implementation of the algorithm, + providing opportunities for an optimizer to "do its thing." + + Note that the code herein is design for the purpose of testing + computational performance; error handling and other such "niceties" + is virtually non-existent. + + Actual benchmark results can be found at: + http://www.coyotegulch.com + + Please do not use this information or algorithm in any way that might + upset the balance of the universe or otherwise cause the creation of + singularities. + +*/ + +#include +#include +#include +#include +#include +#include + +#include "../../src/support.h" + +/* This scale factor will be changed to equalise the runtime of the + benchmarks. */ +#define LOCAL_SCALE_FACTOR 11 + +/* BEEBS heap is just an array */ + +#define HEAP_SIZE 8192 +static char heap[HEAP_SIZE] __attribute__((aligned)); + +#define TEST_SIZE 500 + +typedef unsigned long bits32; +typedef unsigned char byte; + +// compressed (encoded) data + +static const byte orig_data[TEST_SIZE] = { + 'J', '2', 'O', 'Z', 'F', '5', '0', 'F', 'Y', 'L', + 'D', '5', 'U', 'T', 'V', 'Y', 'Y', 'R', 'M', 'T', + '0', 'V', 'X', 'O', '0', '1', 'V', 'C', '5', 'F', + 'N', 'I', 'B', '1', 'C', 'G', '1', '2', 'M', 'T', + 'I', 'P', 'T', '2', 'C', 'I', 'V', '0', '0', 'B', + 'O', 'U', 'W', 'F', 'D', 'R', 'A', 'Y', 'T', 'A', + '3', 'A', 'I', '4', '2', 'K', 'F', 'X', 'H', 'R', + 'K', 'P', 'A', '3', 'L', 'C', 'G', 'A', '3', 'A', + 'B', 'L', 'U', 'Y', 'Q', 'X', 'J', 'R', 'Q', '2', + 'R', 'N', '2', 'Z', 'M', 'Y', 'E', 'R', 'P', 'L', + 'C', '0', '0', 'C', 'X', 'F', 'E', '3', 'G', 'B', + '3', 'H', 'M', 'S', '5', '3', 'J', 'I', 'O', 'Z', + 'E', '5', 'H', 'B', 'Y', 'T', 'Z', '2', 'E', 'J', + 'H', 'G', 'D', 'B', 'I', '0', 'H', 'M', 'Y', 'N', + 'O', 'V', 'U', '0', 'H', 'U', 'X', 'R', '2', 'F', + 'K', 'B', 'E', 'R', 'C', '3', 'E', '1', 'Z', 'I', + 'E', 'B', 'O', 'H', 'C', 'W', 'C', 'J', 'D', '0', + 'W', 'R', 'P', 'L', 'L', 'X', '5', 'D', 'I', '1', + 'I', 'S', '2', 'N', 'E', '4', 'K', 'I', '0', 'D', + 'R', '4', 'E', '5', 'G', 'H', 'W', 'I', 'Q', 'Z', + 'C', 'H', 'K', 'R', 'S', 'V', 'I', 'R', 'Y', 'Q', + 'M', 'B', 'D', 'J', 'O', 'H', 'H', 'Y', 'P', 'B', + '1', 'A', 'A', 'A', 'A', 'G', 'H', 'W', 'O', 'X', + 'P', 'Q', '4', 'Z', 'B', 'Q', 'O', 'K', 'B', 'H', + '0', 'O', 'I', '3', 'X', 'W', 'E', '4', 'O', 'U', + 'A', 'J', 'U', 'A', 'J', 'U', 'G', 'Q', 'K', 'U', + 'I', 'Z', 'E', 'G', 'S', 'F', 'X', 'B', 'P', 'Y', + 'I', 'K', 'G', 'Q', 'H', '3', 'G', 'M', '2', 'U', + 'A', '2', '3', 'U', '2', 'H', 'J', 'C', 'X', 'T', + 'W', '5', 'N', '0', 'G', '5', '5', '3', 'A', 'P', + 'V', 'I', 'Z', '2', 'Y', 'A', 'Z', '4', 'M', 'V', + 'S', 'M', 'R', 'Q', 'B', 'N', 'X', 'K', 'P', 'O', + '3', 'F', 'O', 'K', '5', 'U', 'K', '5', 'R', 'K', + 'O', 'G', 'T', 'H', 'C', 'L', 'H', '2', 'K', 'U', + 'R', '2', 'A', 'D', 'M', 'B', 'Q', 'D', 'L', 'A', + 'S', 'J', 'F', 'A', 'T', 'F', 'U', '3', 'E', 'F', + 'I', 'S', 'L', '1', 'Z', 'O', 'G', 'A', 'K', 'Q', + 'U', '1', 'N', 'V', '4', 'Z', 'W', 'P', '3', 'C', + 'P', 'P', 'L', 'U', 'P', '4', 'Z', 'D', '2', '3', + 'I', 'E', 'P', 'T', '5', 'I', 'B', 'F', 'J', 'L', + 'W', '3', 'H', 'D', 'S', 'F', '2', 'J', 'U', 'Z', + 'L', 'D', 'I', 'W', 'Y', 'X', 'U', 'R', '0', 'Q', + 'P', 'C', 'U', '4', 'W', 'T', 'H', 'X', 'Z', 'Q', + 'D', 'P', 'N', 'K', 'S', 'A', 'P', 'O', 'J', 'E', + 'I', 'U', 'H', 'Q', 'K', '5', 'I', '4', 'R', 'C', + 'P', 'A', 'F', 'D', '4', '1', 'X', 'F', 'S', 'Q', + 'V', 'V', '5', 'D', '5', 'R', 'D', 'P', '5', 'M', + 'T', 'H', 'A', '0', 'Y', 'K', '0', 'A', 'I', 'L', + 'C', 'X', 'L', 'H', '1', 'J', 'C', 'S', 'P', 'V', + 'C', 'E', 'K', 'B', 'H', 'K', 'S', 'K', 'Z', 'R' }; + +static byte test_data[TEST_SIZE]; + + +// utility function for processing compression trie +static void +heap_adjust (size_t * freq, size_t * heap, int n, int k) +{ + // this function compares the values in the array + // 'freq' to order the elements of 'heap' according + // in an inverse heap. See the chapter on priority + // queues and heaps for more explanation. + int j; + + --heap; + + int v = heap[k]; + + while (k <= (n / 2)) + { + j = k + k; + + if ((j < n) && (freq[heap[j]] > freq[heap[j + 1]])) + ++j; + + if (freq[v] < freq[heap[j]]) + break; + + heap[k] = heap[j]; + k = j; + } + + heap[k] = v; +} + +// Huffman compression/decompression function +void +compdecomp (byte * data, size_t data_len) +{ + size_t i, j, n, mask; + bits32 k, t; + byte c; + byte *cptr; + byte *dptr = data; + + /* + COMPRESSION + */ + + // allocate data space + byte *comp = (byte *) malloc_beebs (data_len + 1); + + size_t freq[512]; // allocate frequency table + size_t heap[256]; // allocate heap + int link[512]; // allocate link array + bits32 code[256]; // huffman codes + byte clen[256]; // bit lengths of codes + + memset (comp, 0, sizeof (byte) * (data_len + 1)); + memset (freq, 0, sizeof (size_t) * 512); + memset (heap, 0, sizeof (size_t) * 256); + memset (link, 0, sizeof (int) * 512); + memset (code, 0, sizeof (bits32) * 256); + memset (clen, 0, sizeof (byte) * 256); + + // count frequencies + for (i = 0; i < data_len; ++i) + { + ++freq[(size_t) (*dptr)]; + ++dptr; + } + + // create indirect heap based on frequencies + n = 0; + + for (i = 0; i < 256; ++i) + { + if (freq[i]) + { + heap[n] = i; + ++n; + } + } + + for (i = n; i > 0; --i) + heap_adjust (freq, heap, n, i); + + // generate a trie from heap + size_t temp; + + // at this point, n contains the number of characters + // that occur in the data array + while (n > 1) + { + // take first item from top of heap + --n; + temp = heap[0]; + heap[0] = heap[n]; + + // adjust the heap to maintain properties + heap_adjust (freq, heap, n, 1); + + // in upper half of freq array, store sums of + // the two smallest frequencies from the heap + freq[256 + n] = freq[heap[0]] + freq[temp]; + link[temp] = 256 + n; // parent + link[heap[0]] = -256 - n; // left child + heap[0] = 256 + n; // right child + + // adjust the heap again + heap_adjust (freq, heap, n, 1); + } + + link[256 + n] = 0; + + // generate codes + size_t m, x, maxx = 0, maxi = 0; + int l; + + for (m = 0; m < 256; ++m) + { + if (!freq[m]) // character does not occur + { + code[m] = 0; + clen[m] = 0; + } + else + { + i = 0; // length of current code + j = 1; // bit being set in code + x = 0; // code being built + l = link[m]; // link in trie + + while (l) // while not at end of trie + { + if (l < 0) // left link (negative) + { + x += j; // insert 1 into code + l = -l; // reverse sign + } + + l = link[l]; // move to next link + j <<= 1; // next bit to be set + ++i; // increment code length + } + + code[m] = (unsigned long) x; // save code + clen[m] = (unsigned char) i; // save code len + + // keep track of biggest key + if (x > maxx) + maxx = x; + + // keep track of longest key + if (i > maxi) + maxi = i; + } + } + + // make sure longest codes fit in unsigned long-bits + if (maxi > (sizeof (unsigned long) * 8)) + { + return; + } + + // encode data + size_t comp_len = 0; // number of data_len output + char bout = 0; // byte of encoded data + int bit = -1; // count of bits stored in bout + dptr = data; + + // watch for one-value file! + if (maxx == 0) + { + return; + } + + for (j = 0; j < data_len; ++j) + { + // start copying at first bit of code + mask = 1 << (clen[(*dptr)] - 1); + + // copy code bits + for (i = 0; i < clen[(*dptr)]; ++i) + { + if (bit == 7) + { + // store full output byte + comp[comp_len] = bout; + ++comp_len; + + // check for output longer than input! + if (comp_len == data_len) + { + return; + } + + bit = 0; + bout = 0; + } + else + { + // move to next bit + ++bit; + bout <<= 1; + } + + if (code[(*dptr)] & mask) + bout |= 1; + + mask >>= 1; + } + + ++dptr; + } + + // output any incomplete data_len and bits + bout <<= (7 - bit); + comp[comp_len] = bout; + ++comp_len; + + // printf("data len = %u\n",data_len); + // printf("comp len = %u\n",comp_len); + + /* + DECOMPRESSION + */ + + // allocate heap2 + bits32 heap2[256]; + + // allocate output character buffer + char outc[256]; + + // initialize work areas + memset (heap2, 0, 256 * sizeof (bits32)); + + // create decode table as trie heap2 + char *optr = outc; + + for (j = 0; j < 256; ++j) + { + (*optr) = (char) j; + ++optr; + + // if code exists for this byte + if (code[j] | clen[j]) + { + // begin at first code bit + k = 0; + mask = 1 << (clen[j] - 1); + + // find proper node, using bits in + // code as path. + for (i = 0; i < clen[j]; ++i) + { + k = k * 2 + 1; // right link + + if (code[j] & mask) + ++k; // go left + + mask >>= 1; // next bit + } + + heap2[j] = k; // store link in heap2 + } + } + + // sort outc based on heap2 + for (i = 1; i < 256; ++i) + { + t = heap2[i]; + c = outc[i]; + j = i; + + while ((j) && (heap2[j - 1] > t)) + { + heap2[j] = heap2[j - 1]; + outc[j] = outc[j - 1]; + --j; + } + + heap2[j] = t; + outc[j] = c; + } + + // find first character in table + for (j = 0; heap2[j] == 0; ++j); + + // decode data + k = 0; // link in trie + i = j; + mask = 0x80; + n = 0; + cptr = comp; + dptr = data; + + while (n < data_len) + { + k = k * 2 + 1; // right link + + if ((*cptr) & mask) + ++k; // left link if bit on + + // search heap2 until link >= k + while (heap2[i] < k) + ++i; + + // code matches, character found + if (k == heap2[i]) + { + (*dptr) = outc[i]; + ++dptr; + ++n; + k = 0; + i = j; + } + + // move to next bit + if (mask > 1) + mask >>= 1; + else // code extends into next byte + { + mask = 0x80; + ++cptr; + } + } + + // remove work areas + free_beebs (comp); +} + + +int +verify_benchmark (int res __attribute ((unused))) +{ + return 0 == memcmp (test_data, orig_data, TEST_SIZE * sizeof (orig_data[0])); +} + + +void +initialise_benchmark (void) +{ +} + + +static int benchmark_body (int rpt); + +void +warm_caches (int heat) +{ + int res = benchmark_body (heat); + + return; +} + + +int +benchmark (void) +{ + return benchmark_body (LOCAL_SCALE_FACTOR * CPU_MHZ); +} + + +static int __attribute__ ((noinline)) benchmark_body (int rpt) +{ + int j; + + for (j = 0; j < rpt; j++) + { + init_heap_beebs ((void *) heap, HEAP_SIZE); + + // initialization + memcpy (test_data, orig_data, TEST_SIZE * sizeof (orig_data[0])); + + // what we're timing + compdecomp (test_data, TEST_SIZE); + } + + // done + return 0; +} diff --git a/benchies/embench/benchemarks/matmult-int/matmult-int.c b/benchies/embench/benchemarks/matmult-int/matmult-int.c new file mode 100644 index 0000000000..41b387e05a --- /dev/null +++ b/benchies/embench/benchemarks/matmult-int/matmult-int.c @@ -0,0 +1,270 @@ +/* BEEBS matmult benchmark + + This version, copyright (C) 2013-2019 Embecosm Limited and University of + Bristol + + Contributor James Pallister + Contributor Jeremy Bennett + + This file is part of Embench and was formerly part of the Bristol/Embecosm + Embedded Benchmark Suite. + + SPDX-License-Identifier: GPL-3.0-or-later + + Original code from: WCET Benchmarks, + http://www.mrtc.mdh.se/projects/wcet/benchmarks.html + Permission to license under GPL obtained by email from Björn Lisper + */ + +/* matmult.c */ +/* was mm.c! */ + + +/*----------------------------------------------------------------------* + * To make this program compile under our assumed embedded environment, + * we had to make several changes: + * - Declare all functions in ANSI style, not K&R. + * this includes adding return types in all cases! + * - Declare function prototypes + * - Disable all output + * - Disable all UNIX-style includes + * + * This is a program that was developed from mm.c to matmult.c by + * Thomas Lundqvist at Chalmers. + *----------------------------------------------------------------------*/ + +#include +#include "support.h" + +/* This scale factor will be changed to equalise the runtime of the + benchmarks. */ +#define LOCAL_SCALE_FACTOR 46 +#define UPPERLIMIT 20 +#define RANDOM_VALUE (RandomInteger ()) +#define ZERO 0 +#define MOD_SIZE 8095 +typedef long matrix[UPPERLIMIT][UPPERLIMIT]; + +int +values_match (long v1, long v2) +{ + return (v1 == v2); +} + + +/* + * MATRIX MULTIPLICATION BENCHMARK PROGRAM: + * This program multiplies 2 square matrices resulting in a 3rd + * matrix. It tests a compiler's speed in handling multidimensional + * arrays and simple arithmetic. + */ + + + + +int Seed; +matrix ArrayA_ref, ArrayA, ArrayB_ref, ArrayB, ResultArray; + +void Multiply (matrix A, matrix B, matrix Res); +void InitSeed (void); +void Test (matrix A, matrix B, matrix Res); +void Initialize (matrix Array); +int RandomInteger (void); + +static int benchmark_body (int rpt); + +void +warm_caches (int heat) +{ + int res = benchmark_body (heat); + + return; +} + + +int +benchmark (void) +{ + return benchmark_body (LOCAL_SCALE_FACTOR * CPU_MHZ); +} + + +static int __attribute__ ((noinline)) +benchmark_body (int rpt) +{ + int i; + + for (i = 0; i < rpt; i++) + { + memcpy (ArrayA, ArrayA_ref, + UPPERLIMIT * UPPERLIMIT * sizeof (ArrayA[0][0])); + memcpy (ArrayB, ArrayB_ref, + UPPERLIMIT * UPPERLIMIT * sizeof (ArrayA[0][0])); + + Test (ArrayA, ArrayB, ResultArray); + } + + return 0; +} + + +/* + * Initializes the seed used in the random number generator. + */ +void +InitSeed (void) +{ + Seed = 0; +} + +/* + * Runs a multiplication test on an array. Calculates and prints the + * time it takes to multiply the matrices. + */ +void +Test (matrix A, matrix B, matrix Res) +{ + Multiply (A, B, Res); +} + +/* + * Generates random integers between 0 and 8095 + */ +int +RandomInteger (void) +{ + Seed = ((Seed * 133) + 81) % MOD_SIZE; + return (Seed); +} + +/* + * Multiplies arrays A and B and stores the result in ResultArray. + */ +void +Multiply (matrix A, matrix B, matrix Res) +{ + register int Outer, Inner, Index; + + for (Outer = 0; Outer < UPPERLIMIT; Outer++) + for (Inner = 0; Inner < UPPERLIMIT; Inner++) + { + Res[Outer][Inner] = ZERO; + for (Index = 0; Index < UPPERLIMIT; Index++) + Res[Outer][Inner] += A[Outer][Index] * B[Index][Inner]; + } +} + +void +initialise_benchmark () +{ + InitSeed (); + int OuterIndex, InnerIndex; + + for (OuterIndex = 0; OuterIndex < UPPERLIMIT; OuterIndex++) + for (InnerIndex = 0; InnerIndex < UPPERLIMIT; InnerIndex++) + ArrayA_ref[OuterIndex][InnerIndex] = RANDOM_VALUE; + for (OuterIndex = 0; OuterIndex < UPPERLIMIT; OuterIndex++) + for (InnerIndex = 0; InnerIndex < UPPERLIMIT; InnerIndex++) + ArrayB_ref[OuterIndex][InnerIndex] = RANDOM_VALUE; +} + +int +verify_benchmark (int unused) +{ + int i, j; + matrix exp = { + {291018000, 315000075, 279049970, 205074215, 382719905, + 302595865, 348060915, 308986330, 343160760, 307099935, + 292564810, 240954510, 232755815, 246511665, 328466830, + 263664375, 324016395, 334656070, 285978755, 345370360}, + {252241835, 333432715, 299220275, 247745815, 422508990, + 316728505, 359662270, 277775280, 323336795, 320656600, + 249903690, 251499360, 242195700, 263484280, 348207635, + 289485100, 328607555, 300799835, 269351410, 305703460}, + {304901010, 316252815, 263230275, 208939015, 421993740, + 335002930, 348571170, 280992155, 289749970, 259701175, + 295249990, 310900035, 250896625, 250154105, 315096035, + 236364800, 312879355, 312580685, 275998435, 344137885}, + {286700525, 325985600, 253054970, 224361490, 353502130, + 306544290, 323492140, 259123905, 307731610, 282414410, + 281127810, 246936935, 207890815, 233789540, 339836730, + 277296350, 319925620, 307470895, 290537580, 292297535}, + {272571255, 377663320, 304545985, 263001340, 375034885, + 325423710, 410620380, 313191730, 356989815, 308508355, + 218003850, 272487135, 266000220, 264734710, 367539620, + 304146675, 355295500, 276019740, 251415695, 301225235}, + {272547900, 321522300, 288294345, 247748015, 389912855, + 331874890, 370798315, 315467255, 367554485, 311947660, + 258809685, 270536510, 256730515, 287143040, 363087030, + 285672775, 353670120, 304219695, 274897255, 324684660}, + {233123995, 227142480, 212655155, 198592290, 345335250, + 302661845, 253374925, 233243305, 233750030, 224590040, + 200404820, 250791135, 234405760, 211723645, 280630165, + 185245875, 296423665, 276278575, 252368265, 278726535}, + {277690535, 339615440, 320921550, 307114315, 400187215, + 334374655, 376286920, 295993530, 362988020, 356272700, + 293965465, 261574710, 259690975, 263037705, 416748985, + 274683275, 385571030, 402782385, 323927010, 362778710}, + {267168970, 323401680, 279474330, 201934365, 362624300, + 330736145, 371793675, 299650280, 333646005, 264791490, + 215918320, 277512760, 264068435, 234555295, 321772515, + 217507025, 310372440, 317544750, 245525965, 343183435}, + {281293570, 326519505, 233494705, 238516065, 297038200, + 266273420, 349521550, 259343530, 306032255, 266397915, + 210274920, 263743085, 231689610, 251949545, 293562740, + 226822900, 309225440, 286212000, 206108715, 236678985}, + {288404350, 310319375, 282695670, 244150740, 426489380, + 387525790, 342018190, 326086505, 352250260, 319997735, + 300645835, 284822660, 271837440, 274000415, 361826730, + 252399600, 348582320, 375813820, 316588255, 322499110}, + {273368780, 329706295, 288668335, 234501665, 381962610, + 343186285, 337520205, 259637405, 295755465, 284778105, + 205310525, 249598310, 256662470, 251533535, 336159770, + 249342150, 333559450, 329296590, 278254845, 300673860}, + {318589575, 315522800, 260632295, 250009765, 337127730, + 312810490, 346698590, 260810030, 388289910, 337081285, + 283635410, 208148610, 234123865, 259653165, 370115255, + 243311450, 377808245, 358786770, 286839730, 321912835}, + {229541925, 253967450, 223002545, 202302515, 303446955, + 268472740, 285580065, 211013405, 287677960, 279773910, + 227377310, 197461135, 222469715, 179536615, 306957380, + 178407075, 281051570, 279718120, 234868230, 288991535}, + {290692955, 317729070, 297868235, 213450065, 469270935, + 375344910, 326987580, 334565680, 325300040, 290325655, + 254703825, 284914960, 245773820, 276641510, 323510795, + 271034400, 337424250, 360011440, 281515520, 331261535}, + {287075125, 313194850, 269889345, 208109115, 420653930, + 331900290, 355440665, 318065155, 343785360, 302163035, + 308959360, 312666110, 268997740, 288557415, 370158305, + 205012650, 318198795, 384484520, 316450105, 378714460}, + {278680580, 356815220, 307597060, 216073365, 390879235, + 358775185, 358895230, 306434180, 315569040, 272688130, + 249424325, 274584610, 273530970, 265450585, 325127920, + 312802050, 317134900, 298518590, 269975470, 332586535}, + {245629780, 267021570, 234689035, 208808065, 366356035, + 267059560, 349348005, 270158755, 348048340, 291550930, + 272717800, 259714410, 236033845, 280627610, 335089770, + 176610475, 259339950, 322752840, 236218295, 329687310}, + {226517370, 272306005, 271484080, 216145515, 400972075, + 288475645, 332969550, 338410905, 329052205, 330392265, + 306488095, 271979085, 232795960, 257593945, 339558165, + 202700275, 320622065, 386350450, 315344865, 329233410}, + {224852610, 231292540, 236945875, 243273740, 336327040, + 305144680, 248261920, 191671605, 241699245, 263085200, + 198883715, 175742885, 202517850, 172427630, 296304160, + 209188850, 326546955, 252990460, 238844535, 289753485} + }; + + return 0 == memcmp (ResultArray, exp, + UPPERLIMIT * UPPERLIMIT * sizeof (exp[0][0])); +} + +/* vim: set ts=3 sw=3 et: */ + + +/* + Local Variables: + mode: C + c-file-style: "gnu" + End: +*/ diff --git a/benchies/embench/benchemarks/md5sum/md5.c b/benchies/embench/benchemarks/md5sum/md5.c new file mode 100644 index 0000000000..7ac115c3ec --- /dev/null +++ b/benchies/embench/benchemarks/md5sum/md5.c @@ -0,0 +1,245 @@ +/* + * Simple MD5 implementation + * by Creationix + * https://gist.github.com/creationix/4710780 + * Licensed under MIT + * + * modified by Julian Kunkel for Embench-iot + * Compile with: gcc -o md5 -O3 -lm md5.c + */ +#include +#include +#include +#include + +#include "../../src/support.h" + +#define LOCAL_SCALE_FACTOR 51 + +/* BEEBS heap is just an array */ +/* MSG_SIZE * 2 + ((((MSG_SIZE+8)/64 + 1) * 64) - 8) + 64 */ +#define HEAP_SIZE (2000 + 1016 + 64) +#define MSG_SIZE 1000 +/* Result obtained with a single run on the native target on x86 with a MSG_SIZE + * of 1000 and a msg initiated incrementally from 0 to 999 as in benchmark_body. + * If MSG_SIZE or the initialization mechanism of the array change the RESULT + * value needs to be updated accordingly. */ +#define RESULT 0x33f673b4 + +static char heap[HEAP_SIZE]; + +// leftrotate function definition +#define LEFTROTATE(x, c) (((x) << (c)) | ((x) >> (32 - (c)))) + +// These vars will contain the hash +static uint32_t h0, h1, h2, h3; + +void md5(uint8_t *initial_msg, size_t initial_len) { + + // Message (to prepare) + uint8_t *msg = NULL; + + // Note: All variables are unsigned 32 bit and wrap modulo 2^32 when calculating + + // r specifies the per-round shift amounts + + uint32_t r[] = {7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, + 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, + 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, + 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21}; + + // Use binary integer part of the sines of integers (in radians) as constants// Initialize variables: + uint32_t k[] = { + 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, + 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, + 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, + 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, + 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, + 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, + 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, + 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, + 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, + 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, + 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, + 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, + 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, + 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, + 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, + 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391}; + + h0 = 0x67452301; + h1 = 0xefcdab89; + h2 = 0x98badcfe; + h3 = 0x10325476; + + // Pre-processing: adding a single 1 bit + //append "1" bit to message + /* Notice: the input bytes are considered as bits strings, + where the first bit is the most significant bit of the byte.[37] */ + + // Pre-processing: padding with zeros + //append "0" bit until message length in bit ≡ 448 (mod 512) + //append length mod (2 pow 64) to message + + int new_len = ((((initial_len + 8) / 64) + 1) * 64) - 8; + + msg = calloc_beebs(new_len + 64, 1); // also appends "0" bits + // (we alloc also 64 extra bytes...) + memcpy(msg, initial_msg, initial_len); + msg[initial_len] = 128; // write the "1" bit + + uint32_t bits_len = 8*initial_len; // note, we append the len + memcpy(msg + new_len, &bits_len, 4); // in bits at the end of the buffer + + // Process the message in successive 512-bit chunks: + //for each 512-bit chunk of message: + int offset; + for(offset=0; offset + Contributor Jeremy Bennett + + This file is part of Embench and was formerly part of the Bristol/Embecosm + Embedded Benchmark Suite. + + SPDX-License-Identifier: GPL-3.0-or-later + + ************************************************************************* + * * + * SNU-RT Benchmark Suite for Worst Case Timing Analysis * + * ===================================================== * + * Collected and Modified by S.-S. Lim * + * sslim@archi.snu.ac.kr * + * Real-Time Research Group * + * Seoul National University * + * * + * * + * < Features > - restrictions for our experimental environment * + * * + * 1. Completely structured. * + * - There are no unconditional jumps. * + * - There are no exit from loop bodies. * + * (There are no 'break' or 'return' in loop bodies) * + * 2. No 'switch' statements. * + * 3. No 'do..while' statements. * + * 4. Expressions are restricted. * + * - There are no multiple expressions joined by 'or', * + * 'and' operations. * + * 5. No library calls. * + * - All the functions needed are implemented in the * + * source file. * + * * + * * + ************************************************************************* + * * + * FILE: minver.c * + * SOURCE : Turbo C Programming for Engineering by Hyun Soo Ahn * + * * + * DESCRIPTION : * + * * + * Matrix inversion for 3x3 floating point matrix. * + * * + * REMARK : * + * * + * EXECUTION TIME : * + * * + * * + ************************************************************************* + +*/ + +#include +#include +#include "../../src/support.h" + +/* This scale factor will be changed to equalise the runtime of the + benchmarks. */ +#define LOCAL_SCALE_FACTOR 555 + +int minver (int row, int col, float eps); +int mmul (int row_a, int col_a, int row_b, int col_b); + +static float a_ref[3][3] = { + {3.0, -6.0, 7.0}, + {9.0, 0.0, -5.0}, + {5.0, -8.0, 6.0}, +}; + +static float b[3][3] = { + {-3.0, 0.0, 2.0}, + {3.0, -2.0, 0.0}, + {0.0, 2.0, -3.0}, +}; + +static float a[3][3], c[3][3], d[3][3], det; + +static float +minver_fabs (float n) +{ + float f; + + if (n >= 0) + f = n; + else + f = -n; + return f; +} + +int +mmul (int row_a, int col_a, int row_b, int col_b) +{ + int i, j, k, row_c, col_c; + float w; + + row_c = row_a; + col_c = col_b; + + if (row_c < 1 || row_b < 1 || col_c < 1 || col_a != row_b) + return (999); + for (i = 0; i < row_c; i++) + { + for (j = 0; j < col_c; j++) + { + w = 0.0; + for (k = 0; k < row_b; k++) + w += a[i][k] * b[k][j]; + c[i][j] = w; + } + } + + return (0); +} + + +int +minver (int row, int col, float eps) +{ + int work[500], i, j, k, r, iw, u, v; + float w, wmax, pivot, api, w1; + + r = w = 0; + if (row < 2 || row > 500 || eps <= 0.0) + return (999); + w1 = 1.0; + for (i = 0; i < row; i++) + work[i] = i; + for (k = 0; k < row; k++) + { + wmax = 0.0; + for (i = k; i < row; i++) + { + w = minver_fabs (a[i][k]); + if (w > wmax) + { + wmax = w; + r = i; + } + } + pivot = a[r][k]; + api = minver_fabs (pivot); + if (api <= eps) + { + det = w1; + return (1); + } + w1 *= pivot; + u = k * col; + v = r * col; + if (r != k) + { + w1 = -w; + iw = work[k]; + work[k] = work[r]; + work[r] = iw; + for (j = 0; j < row; j++) + { + w = a[k][j]; + a[k][j] = a[r][j]; + a[r][j] = w; + } + } + for (i = 0; i < row; i++) + a[k][i] /= pivot; + for (i = 0; i < row; i++) + { + if (i != k) + { + v = i * col; + w = a[i][k]; + if (w != 0.0) + { + for (j = 0; j < row; j++) + if (j != k) + a[i][j] -= w * a[k][j]; + a[i][k] = -w / pivot; + } + } + } + a[k][k] = 1.0 / pivot; + } + + for (i = 0; i < row; i++) + { + while (1) + { + k = work[i]; + if (k == i) + break; + iw = work[k]; + work[k] = work[i]; + work[i] = iw; + for (j = 0; j < row; j++) + { + u = j * col; + w = a[k][i]; + a[k][i] = a[k][k]; + a[k][k] = w; + } + } + } + + det = w1; + + return (0); +} + + +int +verify_benchmark (int res __attribute ((unused))) +{ + int i, j; + float eps = 1.0e-6; + + static float c_exp[3][3] = { + {-27.0, 26.0, -15.0}, + {-27.0, -10.0, 33.0}, + {-39.0, 28.0, -8.0} + }; + + static float d_exp[3][3] = { + {0.133333325, -0.199999958, 0.2666665910}, + {-0.519999862, 0.113333330, 0.5266665220}, + {0.479999840, -0.359999895, 0.0399999917} + }; + + /* Allow small errors in floating point */ + + for (i = 0; i < 3; i++) + for (j = 0; j < 3; j++) + if (float_neq_beebs(c[i][j], c_exp[i][j]) || float_neq_beebs(d[i][j], d_exp[i][j])) + return 0; + + return float_eq_beebs(det, -16.6666718); +} + + +void +initialise_benchmark (void) +{ +} + + +static int benchmark_body (int rpt); + +void +warm_caches (int heat) +{ + int res = benchmark_body (heat); + + return; +} + + +int +benchmark (void) +{ + return benchmark_body (LOCAL_SCALE_FACTOR * CPU_MHZ); +} + + +static int __attribute__ ((noinline)) +benchmark_body (int rpt) +{ + int i; + + for (i = 0; i < rpt; i++) + { + float eps = 1.0e-6; + + memcpy (a, a_ref, 3 * 3 * sizeof (a[0][0])); + minver (3, 3, eps); + memcpy (d, a, 3 * 3 * sizeof (a[0][0])); + memcpy (a, a_ref, 3 * 3 * sizeof (a[0][0])); + mmul (3, 3, 3, 3); + } + + return 0; +} + + +/* + Local Variables: + mode: C + c-file-style: "gnu" + End: +*/ diff --git a/benchies/embench/benchemarks/nbody/nbody.c b/benchies/embench/benchemarks/nbody/nbody.c new file mode 100644 index 0000000000..3569028327 --- /dev/null +++ b/benchies/embench/benchemarks/nbody/nbody.c @@ -0,0 +1,288 @@ +/* BEEBS nbody benchmark + + This version, copyright (C) 2014-2019 Embecosm Limited and University of + Bristol + + Contributor Jeremy Bennett + + This file is part of Embench and was formerly part of the Bristol/Embecosm + Embedded Benchmark Suite. + + SPDX-License-Identifier: GPL-3.0-or-later + + The original source code for this benchmark can be found here: + + http://benchmarksgame.alioth.debian.org/ + + and was released under the following licence, disclaimers, and + copyright: + + Revised BSD license + + This is a specific instance of the Open Source Initiative (OSI) BSD + license template http://www.opensource.org/licenses/bsd-license.php + + Copyright 2004-2009 Brent Fulgham + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the + distribution. + + Neither the name of "The Computer Language Benchmarks Game" nor the + name of "The Computer Language Shootout Benchmarks" nor the names + of its contributors may be used to endorse or promote products + derived from this software without specific prior written + permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + OF THE POSSIBILITY OF SUCH DAMAGE. */ + +#include +#include + +#include "../../src/support.h" + +#define LOCAL_SCALE_FACTOR 1 + +#define PI 3.141592653589793 +#define SOLAR_MASS ( 4 * PI * PI ) +#define DAYS_PER_YEAR 365.24 + +struct body +{ + double x[3], fill, v[3], mass; +}; + +static struct body solar_bodies[] = { + /* sun */ + { + .x = {0., 0., 0.}, + .v = {0., 0., 0.}, + .mass = SOLAR_MASS}, + /* jupiter */ + { + .x = {4.84143144246472090e+00, + -1.16032004402742839e+00, + -1.03622044471123109e-01}, + .v = {1.66007664274403694e-03 * DAYS_PER_YEAR, + 7.69901118419740425e-03 * DAYS_PER_YEAR, + -6.90460016972063023e-05 * DAYS_PER_YEAR}, + .mass = 9.54791938424326609e-04 * SOLAR_MASS}, + /* saturn */ + { + .x = {8.34336671824457987e+00, + 4.12479856412430479e+00, + -4.03523417114321381e-01}, + .v = {-2.76742510726862411e-03 * DAYS_PER_YEAR, + 4.99852801234917238e-03 * DAYS_PER_YEAR, + 2.30417297573763929e-05 * DAYS_PER_YEAR}, + .mass = 2.85885980666130812e-04 * SOLAR_MASS}, + /* uranus */ + { + .x = {1.28943695621391310e+01, + -1.51111514016986312e+01, + -2.23307578892655734e-01}, + .v = {2.96460137564761618e-03 * DAYS_PER_YEAR, + 2.37847173959480950e-03 * DAYS_PER_YEAR, + -2.96589568540237556e-05 * DAYS_PER_YEAR}, + .mass = 4.36624404335156298e-05 * SOLAR_MASS}, + /* neptune */ + { + .x = {1.53796971148509165e+01, + -2.59193146099879641e+01, + 1.79258772950371181e-01}, + .v = {2.68067772490389322e-03 * DAYS_PER_YEAR, + 1.62824170038242295e-03 * DAYS_PER_YEAR, + -9.51592254519715870e-05 * DAYS_PER_YEAR}, + .mass = 5.15138902046611451e-05 * SOLAR_MASS} +}; + +static const int BODIES_SIZE = + sizeof (solar_bodies) / sizeof (solar_bodies[0]); + +void +offset_momentum (struct body *bodies, unsigned int nbodies) +{ + unsigned int i, k; + for (i = 0; i < nbodies; ++i) + for (k = 0; k < 3; ++k) + bodies[0].v[k] -= bodies[i].v[k] * bodies[i].mass / SOLAR_MASS; +} + + +double +bodies_energy (struct body *bodies, unsigned int nbodies) +{ + double dx[3], distance, e = 0.0; + unsigned int i, j, k; + + for (i = 0; i < nbodies; ++i) + { + e += bodies[i].mass * (bodies[i].v[0] * bodies[i].v[0] + + bodies[i].v[1] * bodies[i].v[1] + + bodies[i].v[2] * bodies[i].v[2]) / 2.; + + for (j = i + 1; j < nbodies; ++j) + { + for (k = 0; k < 3; ++k) + dx[k] = bodies[i].x[k] - bodies[j].x[k]; + + distance = sqrt (dx[0] * dx[0] + dx[1] * dx[1] + dx[2] * dx[2]); + e -= (bodies[i].mass * bodies[j].mass) / distance; + } + } + return e; +} + +void +initialise_benchmark (void) +{ +} + + + +static int benchmark_body (int rpt); + +void +warm_caches (int heat) +{ + int res = benchmark_body (heat); + + return; +} + + +int +benchmark (void) +{ + return benchmark_body (LOCAL_SCALE_FACTOR * CPU_MHZ); +} + + +static int __attribute__ ((noinline)) +benchmark_body (int rpt) +{ + int j; + double tot_e = 0.0; + + for (j = 0; j < rpt; j++) + { + int i; + offset_momentum (solar_bodies, BODIES_SIZE); + /*printf("%.9f\n", bodies_energy(solar_bodies, BODIES_SIZE)); */ + tot_e = 0.0; + for (i = 0; i < 100; ++i) + tot_e += bodies_energy (solar_bodies, BODIES_SIZE); + /*printf("%.9f\n", bodies_energy(solar_bodies, BODIES_SIZE)); */ + } + /* Result is known good value for total energy. */ + return double_eq_beebs(tot_e, -16.907516382852478); +} + + +int +verify_benchmark (int tot_e_ok) +{ + int i, j; + /* print expected values */ + // printf("static struct body solar_bodies[] = {\n"); + // for (i=0; i + + This file is part of Embench and was formerly part of the Bristol/Embecosm + Embedded Benchmark Suite. + + SPDX-License-Identifier: GPL-3.0-or-later */ + +#include "../../src/support.h" +#include +#include +#include +#include +#include + +/* This scale factor will be changed to equalise the runtime of the + benchmarks. */ +#define LOCAL_SCALE_FACTOR 78 + +// From nettle/macros.h + +#define LE_READ_UINT32(p) \ +( (((uint32_t) (p)[3]) << 24) \ + | (((uint32_t) (p)[2]) << 16) \ + | (((uint32_t) (p)[1]) << 8) \ + | ((uint32_t) (p)[0])) + +#define LE_WRITE_UINT32(p, i) \ +do { \ + (p)[3] = ((i) >> 24) & 0xff; \ + (p)[2] = ((i) >> 16) & 0xff; \ + (p)[1] = ((i) >> 8) & 0xff; \ + (p)[0] = (i) & 0xff; \ +} while(0) + +#define ROTL32(n,x) (((x)<<(n)) | ((x)>>((-(n)&31)))) + +#define FOR_BLOCKS(length, dst, src, blocksize) \ + assert_beebs( !((length) % (blocksize))); \ + for (; (length); ((length) -= (blocksize), \ + (dst) += (blocksize), \ + (src) += (blocksize)) ) + + +// From nettle/aes-internal.h + +#define AES_TABLE_SIZE 4 + +struct aes_table +{ + uint8_t sbox[0x100]; + uint32_t table[AES_TABLE_SIZE][0x100]; +}; + +#define aes_sbox (_aes_encrypt_table.sbox) + +/* Get the byte with index 0, 1, 2 and 3 */ +#define B0(x) ((x) & 0xff) +#define B1(x) (((x) >> 8) & 0xff) +#define B2(x) (((x) >> 16) & 0xff) +#define B3(x) (((x) >> 24) & 0xff) + +#define SUBBYTE(x, box) ((uint32_t)(box)[B0(x)] \ + | ((uint32_t)(box)[B1(x)] << 8) \ + | ((uint32_t)(box)[B2(x)] << 16) \ + | ((uint32_t)(box)[B3(x)] << 24)) + +#define AES_ROUND(T, w0, w1, w2, w3, k) \ +(( T->table[0][ B0(w0) ] \ + ^ T->table[1][ B1(w1) ] \ + ^ T->table[2][ B2(w2) ] \ + ^ T->table[3][ B3(w3) ]) ^ (k)) + +#define AES_FINAL_ROUND(T, w0, w1, w2, w3, k) \ +(( (uint32_t) T->sbox[ B0(w0) ] \ + | ((uint32_t) T->sbox[ B1(w1) ] << 8) \ + | ((uint32_t) T->sbox[ B2(w2) ] << 16) \ + | ((uint32_t) T->sbox[ B3(w3) ] << 24)) ^ (k)) + + +// From nettle/aes-encrypt-table.c + +const struct aes_table _aes_encrypt_table = { /* sbox */ + { + 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, + 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, + 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, + 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, + 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, + 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, + 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, + 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, + 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, + 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, + 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, + 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, + 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, + 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, + 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, + 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, + 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, + 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, + 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, + 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, + 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, + 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, + 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, + 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, + 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, + 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, + 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, + 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, + 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, + 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, + 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, + 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16, + }, + { /* dtable */ + { + 0xa56363c6, 0x847c7cf8, 0x997777ee, 0x8d7b7bf6, + 0x0df2f2ff, 0xbd6b6bd6, 0xb16f6fde, 0x54c5c591, + 0x50303060, 0x03010102, 0xa96767ce, 0x7d2b2b56, + 0x19fefee7, 0x62d7d7b5, 0xe6abab4d, 0x9a7676ec, + 0x45caca8f, 0x9d82821f, 0x40c9c989, 0x877d7dfa, + 0x15fafaef, 0xeb5959b2, 0xc947478e, 0x0bf0f0fb, + 0xecadad41, 0x67d4d4b3, 0xfda2a25f, 0xeaafaf45, + 0xbf9c9c23, 0xf7a4a453, 0x967272e4, 0x5bc0c09b, + 0xc2b7b775, 0x1cfdfde1, 0xae93933d, 0x6a26264c, + 0x5a36366c, 0x413f3f7e, 0x02f7f7f5, 0x4fcccc83, + 0x5c343468, 0xf4a5a551, 0x34e5e5d1, 0x08f1f1f9, + 0x937171e2, 0x73d8d8ab, 0x53313162, 0x3f15152a, + 0x0c040408, 0x52c7c795, 0x65232346, 0x5ec3c39d, + 0x28181830, 0xa1969637, 0x0f05050a, 0xb59a9a2f, + 0x0907070e, 0x36121224, 0x9b80801b, 0x3de2e2df, + 0x26ebebcd, 0x6927274e, 0xcdb2b27f, 0x9f7575ea, + 0x1b090912, 0x9e83831d, 0x742c2c58, 0x2e1a1a34, + 0x2d1b1b36, 0xb26e6edc, 0xee5a5ab4, 0xfba0a05b, + 0xf65252a4, 0x4d3b3b76, 0x61d6d6b7, 0xceb3b37d, + 0x7b292952, 0x3ee3e3dd, 0x712f2f5e, 0x97848413, + 0xf55353a6, 0x68d1d1b9, 0x00000000, 0x2cededc1, + 0x60202040, 0x1ffcfce3, 0xc8b1b179, 0xed5b5bb6, + 0xbe6a6ad4, 0x46cbcb8d, 0xd9bebe67, 0x4b393972, + 0xde4a4a94, 0xd44c4c98, 0xe85858b0, 0x4acfcf85, + 0x6bd0d0bb, 0x2aefefc5, 0xe5aaaa4f, 0x16fbfbed, + 0xc5434386, 0xd74d4d9a, 0x55333366, 0x94858511, + 0xcf45458a, 0x10f9f9e9, 0x06020204, 0x817f7ffe, + 0xf05050a0, 0x443c3c78, 0xba9f9f25, 0xe3a8a84b, + 0xf35151a2, 0xfea3a35d, 0xc0404080, 0x8a8f8f05, + 0xad92923f, 0xbc9d9d21, 0x48383870, 0x04f5f5f1, + 0xdfbcbc63, 0xc1b6b677, 0x75dadaaf, 0x63212142, + 0x30101020, 0x1affffe5, 0x0ef3f3fd, 0x6dd2d2bf, + 0x4ccdcd81, 0x140c0c18, 0x35131326, 0x2fececc3, + 0xe15f5fbe, 0xa2979735, 0xcc444488, 0x3917172e, + 0x57c4c493, 0xf2a7a755, 0x827e7efc, 0x473d3d7a, + 0xac6464c8, 0xe75d5dba, 0x2b191932, 0x957373e6, + 0xa06060c0, 0x98818119, 0xd14f4f9e, 0x7fdcdca3, + 0x66222244, 0x7e2a2a54, 0xab90903b, 0x8388880b, + 0xca46468c, 0x29eeeec7, 0xd3b8b86b, 0x3c141428, + 0x79dedea7, 0xe25e5ebc, 0x1d0b0b16, 0x76dbdbad, + 0x3be0e0db, 0x56323264, 0x4e3a3a74, 0x1e0a0a14, + 0xdb494992, 0x0a06060c, 0x6c242448, 0xe45c5cb8, + 0x5dc2c29f, 0x6ed3d3bd, 0xefacac43, 0xa66262c4, + 0xa8919139, 0xa4959531, 0x37e4e4d3, 0x8b7979f2, + 0x32e7e7d5, 0x43c8c88b, 0x5937376e, 0xb76d6dda, + 0x8c8d8d01, 0x64d5d5b1, 0xd24e4e9c, 0xe0a9a949, + 0xb46c6cd8, 0xfa5656ac, 0x07f4f4f3, 0x25eaeacf, + 0xaf6565ca, 0x8e7a7af4, 0xe9aeae47, 0x18080810, + 0xd5baba6f, 0x887878f0, 0x6f25254a, 0x722e2e5c, + 0x241c1c38, 0xf1a6a657, 0xc7b4b473, 0x51c6c697, + 0x23e8e8cb, 0x7cdddda1, 0x9c7474e8, 0x211f1f3e, + 0xdd4b4b96, 0xdcbdbd61, 0x868b8b0d, 0x858a8a0f, + 0x907070e0, 0x423e3e7c, 0xc4b5b571, 0xaa6666cc, + 0xd8484890, 0x05030306, 0x01f6f6f7, 0x120e0e1c, + 0xa36161c2, 0x5f35356a, 0xf95757ae, 0xd0b9b969, + 0x91868617, 0x58c1c199, 0x271d1d3a, 0xb99e9e27, + 0x38e1e1d9, 0x13f8f8eb, 0xb398982b, 0x33111122, + 0xbb6969d2, 0x70d9d9a9, 0x898e8e07, 0xa7949433, + 0xb69b9b2d, 0x221e1e3c, 0x92878715, 0x20e9e9c9, + 0x49cece87, 0xff5555aa, 0x78282850, 0x7adfdfa5, + 0x8f8c8c03, 0xf8a1a159, 0x80898909, 0x170d0d1a, + 0xdabfbf65, 0x31e6e6d7, 0xc6424284, 0xb86868d0, + 0xc3414182, 0xb0999929, 0x772d2d5a, 0x110f0f1e, + 0xcbb0b07b, 0xfc5454a8, 0xd6bbbb6d, 0x3a16162c, + }, +#if !AES_SMALL + { + 0x6363c6a5, 0x7c7cf884, 0x7777ee99, 0x7b7bf68d, + 0xf2f2ff0d, 0x6b6bd6bd, 0x6f6fdeb1, 0xc5c59154, + 0x30306050, 0x01010203, 0x6767cea9, 0x2b2b567d, + 0xfefee719, 0xd7d7b562, 0xabab4de6, 0x7676ec9a, + 0xcaca8f45, 0x82821f9d, 0xc9c98940, 0x7d7dfa87, + 0xfafaef15, 0x5959b2eb, 0x47478ec9, 0xf0f0fb0b, + 0xadad41ec, 0xd4d4b367, 0xa2a25ffd, 0xafaf45ea, + 0x9c9c23bf, 0xa4a453f7, 0x7272e496, 0xc0c09b5b, + 0xb7b775c2, 0xfdfde11c, 0x93933dae, 0x26264c6a, + 0x36366c5a, 0x3f3f7e41, 0xf7f7f502, 0xcccc834f, + 0x3434685c, 0xa5a551f4, 0xe5e5d134, 0xf1f1f908, + 0x7171e293, 0xd8d8ab73, 0x31316253, 0x15152a3f, + 0x0404080c, 0xc7c79552, 0x23234665, 0xc3c39d5e, + 0x18183028, 0x969637a1, 0x05050a0f, 0x9a9a2fb5, + 0x07070e09, 0x12122436, 0x80801b9b, 0xe2e2df3d, + 0xebebcd26, 0x27274e69, 0xb2b27fcd, 0x7575ea9f, + 0x0909121b, 0x83831d9e, 0x2c2c5874, 0x1a1a342e, + 0x1b1b362d, 0x6e6edcb2, 0x5a5ab4ee, 0xa0a05bfb, + 0x5252a4f6, 0x3b3b764d, 0xd6d6b761, 0xb3b37dce, + 0x2929527b, 0xe3e3dd3e, 0x2f2f5e71, 0x84841397, + 0x5353a6f5, 0xd1d1b968, 0x00000000, 0xededc12c, + 0x20204060, 0xfcfce31f, 0xb1b179c8, 0x5b5bb6ed, + 0x6a6ad4be, 0xcbcb8d46, 0xbebe67d9, 0x3939724b, + 0x4a4a94de, 0x4c4c98d4, 0x5858b0e8, 0xcfcf854a, + 0xd0d0bb6b, 0xefefc52a, 0xaaaa4fe5, 0xfbfbed16, + 0x434386c5, 0x4d4d9ad7, 0x33336655, 0x85851194, + 0x45458acf, 0xf9f9e910, 0x02020406, 0x7f7ffe81, + 0x5050a0f0, 0x3c3c7844, 0x9f9f25ba, 0xa8a84be3, + 0x5151a2f3, 0xa3a35dfe, 0x404080c0, 0x8f8f058a, + 0x92923fad, 0x9d9d21bc, 0x38387048, 0xf5f5f104, + 0xbcbc63df, 0xb6b677c1, 0xdadaaf75, 0x21214263, + 0x10102030, 0xffffe51a, 0xf3f3fd0e, 0xd2d2bf6d, + 0xcdcd814c, 0x0c0c1814, 0x13132635, 0xececc32f, + 0x5f5fbee1, 0x979735a2, 0x444488cc, 0x17172e39, + 0xc4c49357, 0xa7a755f2, 0x7e7efc82, 0x3d3d7a47, + 0x6464c8ac, 0x5d5dbae7, 0x1919322b, 0x7373e695, + 0x6060c0a0, 0x81811998, 0x4f4f9ed1, 0xdcdca37f, + 0x22224466, 0x2a2a547e, 0x90903bab, 0x88880b83, + 0x46468cca, 0xeeeec729, 0xb8b86bd3, 0x1414283c, + 0xdedea779, 0x5e5ebce2, 0x0b0b161d, 0xdbdbad76, + 0xe0e0db3b, 0x32326456, 0x3a3a744e, 0x0a0a141e, + 0x494992db, 0x06060c0a, 0x2424486c, 0x5c5cb8e4, + 0xc2c29f5d, 0xd3d3bd6e, 0xacac43ef, 0x6262c4a6, + 0x919139a8, 0x959531a4, 0xe4e4d337, 0x7979f28b, + 0xe7e7d532, 0xc8c88b43, 0x37376e59, 0x6d6ddab7, + 0x8d8d018c, 0xd5d5b164, 0x4e4e9cd2, 0xa9a949e0, + 0x6c6cd8b4, 0x5656acfa, 0xf4f4f307, 0xeaeacf25, + 0x6565caaf, 0x7a7af48e, 0xaeae47e9, 0x08081018, + 0xbaba6fd5, 0x7878f088, 0x25254a6f, 0x2e2e5c72, + 0x1c1c3824, 0xa6a657f1, 0xb4b473c7, 0xc6c69751, + 0xe8e8cb23, 0xdddda17c, 0x7474e89c, 0x1f1f3e21, + 0x4b4b96dd, 0xbdbd61dc, 0x8b8b0d86, 0x8a8a0f85, + 0x7070e090, 0x3e3e7c42, 0xb5b571c4, 0x6666ccaa, + 0x484890d8, 0x03030605, 0xf6f6f701, 0x0e0e1c12, + 0x6161c2a3, 0x35356a5f, 0x5757aef9, 0xb9b969d0, + 0x86861791, 0xc1c19958, 0x1d1d3a27, 0x9e9e27b9, + 0xe1e1d938, 0xf8f8eb13, 0x98982bb3, 0x11112233, + 0x6969d2bb, 0xd9d9a970, 0x8e8e0789, 0x949433a7, + 0x9b9b2db6, 0x1e1e3c22, 0x87871592, 0xe9e9c920, + 0xcece8749, 0x5555aaff, 0x28285078, 0xdfdfa57a, + 0x8c8c038f, 0xa1a159f8, 0x89890980, 0x0d0d1a17, + 0xbfbf65da, 0xe6e6d731, 0x424284c6, 0x6868d0b8, + 0x414182c3, 0x999929b0, 0x2d2d5a77, 0x0f0f1e11, + 0xb0b07bcb, 0x5454a8fc, 0xbbbb6dd6, 0x16162c3a, + }, { + 0x63c6a563, 0x7cf8847c, 0x77ee9977, 0x7bf68d7b, + 0xf2ff0df2, 0x6bd6bd6b, 0x6fdeb16f, 0xc59154c5, + 0x30605030, 0x01020301, 0x67cea967, 0x2b567d2b, + 0xfee719fe, 0xd7b562d7, 0xab4de6ab, 0x76ec9a76, + 0xca8f45ca, 0x821f9d82, 0xc98940c9, 0x7dfa877d, + 0xfaef15fa, 0x59b2eb59, 0x478ec947, 0xf0fb0bf0, + 0xad41ecad, 0xd4b367d4, 0xa25ffda2, 0xaf45eaaf, + 0x9c23bf9c, 0xa453f7a4, 0x72e49672, 0xc09b5bc0, + 0xb775c2b7, 0xfde11cfd, 0x933dae93, 0x264c6a26, + 0x366c5a36, 0x3f7e413f, 0xf7f502f7, 0xcc834fcc, + 0x34685c34, 0xa551f4a5, 0xe5d134e5, 0xf1f908f1, + 0x71e29371, 0xd8ab73d8, 0x31625331, 0x152a3f15, + 0x04080c04, 0xc79552c7, 0x23466523, 0xc39d5ec3, + 0x18302818, 0x9637a196, 0x050a0f05, 0x9a2fb59a, + 0x070e0907, 0x12243612, 0x801b9b80, 0xe2df3de2, + 0xebcd26eb, 0x274e6927, 0xb27fcdb2, 0x75ea9f75, + 0x09121b09, 0x831d9e83, 0x2c58742c, 0x1a342e1a, + 0x1b362d1b, 0x6edcb26e, 0x5ab4ee5a, 0xa05bfba0, + 0x52a4f652, 0x3b764d3b, 0xd6b761d6, 0xb37dceb3, + 0x29527b29, 0xe3dd3ee3, 0x2f5e712f, 0x84139784, + 0x53a6f553, 0xd1b968d1, 0x00000000, 0xedc12ced, + 0x20406020, 0xfce31ffc, 0xb179c8b1, 0x5bb6ed5b, + 0x6ad4be6a, 0xcb8d46cb, 0xbe67d9be, 0x39724b39, + 0x4a94de4a, 0x4c98d44c, 0x58b0e858, 0xcf854acf, + 0xd0bb6bd0, 0xefc52aef, 0xaa4fe5aa, 0xfbed16fb, + 0x4386c543, 0x4d9ad74d, 0x33665533, 0x85119485, + 0x458acf45, 0xf9e910f9, 0x02040602, 0x7ffe817f, + 0x50a0f050, 0x3c78443c, 0x9f25ba9f, 0xa84be3a8, + 0x51a2f351, 0xa35dfea3, 0x4080c040, 0x8f058a8f, + 0x923fad92, 0x9d21bc9d, 0x38704838, 0xf5f104f5, + 0xbc63dfbc, 0xb677c1b6, 0xdaaf75da, 0x21426321, + 0x10203010, 0xffe51aff, 0xf3fd0ef3, 0xd2bf6dd2, + 0xcd814ccd, 0x0c18140c, 0x13263513, 0xecc32fec, + 0x5fbee15f, 0x9735a297, 0x4488cc44, 0x172e3917, + 0xc49357c4, 0xa755f2a7, 0x7efc827e, 0x3d7a473d, + 0x64c8ac64, 0x5dbae75d, 0x19322b19, 0x73e69573, + 0x60c0a060, 0x81199881, 0x4f9ed14f, 0xdca37fdc, + 0x22446622, 0x2a547e2a, 0x903bab90, 0x880b8388, + 0x468cca46, 0xeec729ee, 0xb86bd3b8, 0x14283c14, + 0xdea779de, 0x5ebce25e, 0x0b161d0b, 0xdbad76db, + 0xe0db3be0, 0x32645632, 0x3a744e3a, 0x0a141e0a, + 0x4992db49, 0x060c0a06, 0x24486c24, 0x5cb8e45c, + 0xc29f5dc2, 0xd3bd6ed3, 0xac43efac, 0x62c4a662, + 0x9139a891, 0x9531a495, 0xe4d337e4, 0x79f28b79, + 0xe7d532e7, 0xc88b43c8, 0x376e5937, 0x6ddab76d, + 0x8d018c8d, 0xd5b164d5, 0x4e9cd24e, 0xa949e0a9, + 0x6cd8b46c, 0x56acfa56, 0xf4f307f4, 0xeacf25ea, + 0x65caaf65, 0x7af48e7a, 0xae47e9ae, 0x08101808, + 0xba6fd5ba, 0x78f08878, 0x254a6f25, 0x2e5c722e, + 0x1c38241c, 0xa657f1a6, 0xb473c7b4, 0xc69751c6, + 0xe8cb23e8, 0xdda17cdd, 0x74e89c74, 0x1f3e211f, + 0x4b96dd4b, 0xbd61dcbd, 0x8b0d868b, 0x8a0f858a, + 0x70e09070, 0x3e7c423e, 0xb571c4b5, 0x66ccaa66, + 0x4890d848, 0x03060503, 0xf6f701f6, 0x0e1c120e, + 0x61c2a361, 0x356a5f35, 0x57aef957, 0xb969d0b9, + 0x86179186, 0xc19958c1, 0x1d3a271d, 0x9e27b99e, + 0xe1d938e1, 0xf8eb13f8, 0x982bb398, 0x11223311, + 0x69d2bb69, 0xd9a970d9, 0x8e07898e, 0x9433a794, + 0x9b2db69b, 0x1e3c221e, 0x87159287, 0xe9c920e9, + 0xce8749ce, 0x55aaff55, 0x28507828, 0xdfa57adf, + 0x8c038f8c, 0xa159f8a1, 0x89098089, 0x0d1a170d, + 0xbf65dabf, 0xe6d731e6, 0x4284c642, 0x68d0b868, + 0x4182c341, 0x9929b099, 0x2d5a772d, 0x0f1e110f, + 0xb07bcbb0, 0x54a8fc54, 0xbb6dd6bb, 0x162c3a16, + }, { + 0xc6a56363, 0xf8847c7c, 0xee997777, 0xf68d7b7b, + 0xff0df2f2, 0xd6bd6b6b, 0xdeb16f6f, 0x9154c5c5, + 0x60503030, 0x02030101, 0xcea96767, 0x567d2b2b, + 0xe719fefe, 0xb562d7d7, 0x4de6abab, 0xec9a7676, + 0x8f45caca, 0x1f9d8282, 0x8940c9c9, 0xfa877d7d, + 0xef15fafa, 0xb2eb5959, 0x8ec94747, 0xfb0bf0f0, + 0x41ecadad, 0xb367d4d4, 0x5ffda2a2, 0x45eaafaf, + 0x23bf9c9c, 0x53f7a4a4, 0xe4967272, 0x9b5bc0c0, + 0x75c2b7b7, 0xe11cfdfd, 0x3dae9393, 0x4c6a2626, + 0x6c5a3636, 0x7e413f3f, 0xf502f7f7, 0x834fcccc, + 0x685c3434, 0x51f4a5a5, 0xd134e5e5, 0xf908f1f1, + 0xe2937171, 0xab73d8d8, 0x62533131, 0x2a3f1515, + 0x080c0404, 0x9552c7c7, 0x46652323, 0x9d5ec3c3, + 0x30281818, 0x37a19696, 0x0a0f0505, 0x2fb59a9a, + 0x0e090707, 0x24361212, 0x1b9b8080, 0xdf3de2e2, + 0xcd26ebeb, 0x4e692727, 0x7fcdb2b2, 0xea9f7575, + 0x121b0909, 0x1d9e8383, 0x58742c2c, 0x342e1a1a, + 0x362d1b1b, 0xdcb26e6e, 0xb4ee5a5a, 0x5bfba0a0, + 0xa4f65252, 0x764d3b3b, 0xb761d6d6, 0x7dceb3b3, + 0x527b2929, 0xdd3ee3e3, 0x5e712f2f, 0x13978484, + 0xa6f55353, 0xb968d1d1, 0x00000000, 0xc12ceded, + 0x40602020, 0xe31ffcfc, 0x79c8b1b1, 0xb6ed5b5b, + 0xd4be6a6a, 0x8d46cbcb, 0x67d9bebe, 0x724b3939, + 0x94de4a4a, 0x98d44c4c, 0xb0e85858, 0x854acfcf, + 0xbb6bd0d0, 0xc52aefef, 0x4fe5aaaa, 0xed16fbfb, + 0x86c54343, 0x9ad74d4d, 0x66553333, 0x11948585, + 0x8acf4545, 0xe910f9f9, 0x04060202, 0xfe817f7f, + 0xa0f05050, 0x78443c3c, 0x25ba9f9f, 0x4be3a8a8, + 0xa2f35151, 0x5dfea3a3, 0x80c04040, 0x058a8f8f, + 0x3fad9292, 0x21bc9d9d, 0x70483838, 0xf104f5f5, + 0x63dfbcbc, 0x77c1b6b6, 0xaf75dada, 0x42632121, + 0x20301010, 0xe51affff, 0xfd0ef3f3, 0xbf6dd2d2, + 0x814ccdcd, 0x18140c0c, 0x26351313, 0xc32fecec, + 0xbee15f5f, 0x35a29797, 0x88cc4444, 0x2e391717, + 0x9357c4c4, 0x55f2a7a7, 0xfc827e7e, 0x7a473d3d, + 0xc8ac6464, 0xbae75d5d, 0x322b1919, 0xe6957373, + 0xc0a06060, 0x19988181, 0x9ed14f4f, 0xa37fdcdc, + 0x44662222, 0x547e2a2a, 0x3bab9090, 0x0b838888, + 0x8cca4646, 0xc729eeee, 0x6bd3b8b8, 0x283c1414, + 0xa779dede, 0xbce25e5e, 0x161d0b0b, 0xad76dbdb, + 0xdb3be0e0, 0x64563232, 0x744e3a3a, 0x141e0a0a, + 0x92db4949, 0x0c0a0606, 0x486c2424, 0xb8e45c5c, + 0x9f5dc2c2, 0xbd6ed3d3, 0x43efacac, 0xc4a66262, + 0x39a89191, 0x31a49595, 0xd337e4e4, 0xf28b7979, + 0xd532e7e7, 0x8b43c8c8, 0x6e593737, 0xdab76d6d, + 0x018c8d8d, 0xb164d5d5, 0x9cd24e4e, 0x49e0a9a9, + 0xd8b46c6c, 0xacfa5656, 0xf307f4f4, 0xcf25eaea, + 0xcaaf6565, 0xf48e7a7a, 0x47e9aeae, 0x10180808, + 0x6fd5baba, 0xf0887878, 0x4a6f2525, 0x5c722e2e, + 0x38241c1c, 0x57f1a6a6, 0x73c7b4b4, 0x9751c6c6, + 0xcb23e8e8, 0xa17cdddd, 0xe89c7474, 0x3e211f1f, + 0x96dd4b4b, 0x61dcbdbd, 0x0d868b8b, 0x0f858a8a, + 0xe0907070, 0x7c423e3e, 0x71c4b5b5, 0xccaa6666, + 0x90d84848, 0x06050303, 0xf701f6f6, 0x1c120e0e, + 0xc2a36161, 0x6a5f3535, 0xaef95757, 0x69d0b9b9, + 0x17918686, 0x9958c1c1, 0x3a271d1d, 0x27b99e9e, + 0xd938e1e1, 0xeb13f8f8, 0x2bb39898, 0x22331111, + 0xd2bb6969, 0xa970d9d9, 0x07898e8e, 0x33a79494, + 0x2db69b9b, 0x3c221e1e, 0x15928787, 0xc920e9e9, + 0x8749cece, 0xaaff5555, 0x50782828, 0xa57adfdf, + 0x038f8c8c, 0x59f8a1a1, 0x09808989, 0x1a170d0d, + 0x65dabfbf, 0xd731e6e6, 0x84c64242, 0xd0b86868, + 0x82c34141, 0x29b09999, 0x5a772d2d, 0x1e110f0f, + 0x7bcbb0b0, 0xa8fc5454, 0x6dd6bbbb, 0x2c3a1616, + }, +#endif /* !AES_SMALL */ + } +}; + + +// From nettle/aes-decrypt.c + +static const struct aes_table _aes_decrypt_table = { /* isbox */ + { + 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, + 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, + 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, + 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, + 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, + 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, + 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, + 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, + 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, + 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, + 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, + 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, + 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, + 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, + 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, + 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, + 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, + 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, + 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, + 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, + 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, + 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, + 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, + 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, + 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, + 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, + 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, + 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, + 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, + 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, + 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, + 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d, + }, + { /* itable */ + { + 0x50a7f451, 0x5365417e, 0xc3a4171a, 0x965e273a, + 0xcb6bab3b, 0xf1459d1f, 0xab58faac, 0x9303e34b, + 0x55fa3020, 0xf66d76ad, 0x9176cc88, 0x254c02f5, + 0xfcd7e54f, 0xd7cb2ac5, 0x80443526, 0x8fa362b5, + 0x495ab1de, 0x671bba25, 0x980eea45, 0xe1c0fe5d, + 0x02752fc3, 0x12f04c81, 0xa397468d, 0xc6f9d36b, + 0xe75f8f03, 0x959c9215, 0xeb7a6dbf, 0xda595295, + 0x2d83bed4, 0xd3217458, 0x2969e049, 0x44c8c98e, + 0x6a89c275, 0x78798ef4, 0x6b3e5899, 0xdd71b927, + 0xb64fe1be, 0x17ad88f0, 0x66ac20c9, 0xb43ace7d, + 0x184adf63, 0x82311ae5, 0x60335197, 0x457f5362, + 0xe07764b1, 0x84ae6bbb, 0x1ca081fe, 0x942b08f9, + 0x58684870, 0x19fd458f, 0x876cde94, 0xb7f87b52, + 0x23d373ab, 0xe2024b72, 0x578f1fe3, 0x2aab5566, + 0x0728ebb2, 0x03c2b52f, 0x9a7bc586, 0xa50837d3, + 0xf2872830, 0xb2a5bf23, 0xba6a0302, 0x5c8216ed, + 0x2b1ccf8a, 0x92b479a7, 0xf0f207f3, 0xa1e2694e, + 0xcdf4da65, 0xd5be0506, 0x1f6234d1, 0x8afea6c4, + 0x9d532e34, 0xa055f3a2, 0x32e18a05, 0x75ebf6a4, + 0x39ec830b, 0xaaef6040, 0x069f715e, 0x51106ebd, + 0xf98a213e, 0x3d06dd96, 0xae053edd, 0x46bde64d, + 0xb58d5491, 0x055dc471, 0x6fd40604, 0xff155060, + 0x24fb9819, 0x97e9bdd6, 0xcc434089, 0x779ed967, + 0xbd42e8b0, 0x888b8907, 0x385b19e7, 0xdbeec879, + 0x470a7ca1, 0xe90f427c, 0xc91e84f8, 0x00000000, + 0x83868009, 0x48ed2b32, 0xac70111e, 0x4e725a6c, + 0xfbff0efd, 0x5638850f, 0x1ed5ae3d, 0x27392d36, + 0x64d90f0a, 0x21a65c68, 0xd1545b9b, 0x3a2e3624, + 0xb1670a0c, 0x0fe75793, 0xd296eeb4, 0x9e919b1b, + 0x4fc5c080, 0xa220dc61, 0x694b775a, 0x161a121c, + 0x0aba93e2, 0xe52aa0c0, 0x43e0223c, 0x1d171b12, + 0x0b0d090e, 0xadc78bf2, 0xb9a8b62d, 0xc8a91e14, + 0x8519f157, 0x4c0775af, 0xbbdd99ee, 0xfd607fa3, + 0x9f2601f7, 0xbcf5725c, 0xc53b6644, 0x347efb5b, + 0x7629438b, 0xdcc623cb, 0x68fcedb6, 0x63f1e4b8, + 0xcadc31d7, 0x10856342, 0x40229713, 0x2011c684, + 0x7d244a85, 0xf83dbbd2, 0x1132f9ae, 0x6da129c7, + 0x4b2f9e1d, 0xf330b2dc, 0xec52860d, 0xd0e3c177, + 0x6c16b32b, 0x99b970a9, 0xfa489411, 0x2264e947, + 0xc48cfca8, 0x1a3ff0a0, 0xd82c7d56, 0xef903322, + 0xc74e4987, 0xc1d138d9, 0xfea2ca8c, 0x360bd498, + 0xcf81f5a6, 0x28de7aa5, 0x268eb7da, 0xa4bfad3f, + 0xe49d3a2c, 0x0d927850, 0x9bcc5f6a, 0x62467e54, + 0xc2138df6, 0xe8b8d890, 0x5ef7392e, 0xf5afc382, + 0xbe805d9f, 0x7c93d069, 0xa92dd56f, 0xb31225cf, + 0x3b99acc8, 0xa77d1810, 0x6e639ce8, 0x7bbb3bdb, + 0x097826cd, 0xf418596e, 0x01b79aec, 0xa89a4f83, + 0x656e95e6, 0x7ee6ffaa, 0x08cfbc21, 0xe6e815ef, + 0xd99be7ba, 0xce366f4a, 0xd4099fea, 0xd67cb029, + 0xafb2a431, 0x31233f2a, 0x3094a5c6, 0xc066a235, + 0x37bc4e74, 0xa6ca82fc, 0xb0d090e0, 0x15d8a733, + 0x4a9804f1, 0xf7daec41, 0x0e50cd7f, 0x2ff69117, + 0x8dd64d76, 0x4db0ef43, 0x544daacc, 0xdf0496e4, + 0xe3b5d19e, 0x1b886a4c, 0xb81f2cc1, 0x7f516546, + 0x04ea5e9d, 0x5d358c01, 0x737487fa, 0x2e410bfb, + 0x5a1d67b3, 0x52d2db92, 0x335610e9, 0x1347d66d, + 0x8c61d79a, 0x7a0ca137, 0x8e14f859, 0x893c13eb, + 0xee27a9ce, 0x35c961b7, 0xede51ce1, 0x3cb1477a, + 0x59dfd29c, 0x3f73f255, 0x79ce1418, 0xbf37c773, + 0xeacdf753, 0x5baafd5f, 0x146f3ddf, 0x86db4478, + 0x81f3afca, 0x3ec468b9, 0x2c342438, 0x5f40a3c2, + 0x72c31d16, 0x0c25e2bc, 0x8b493c28, 0x41950dff, + 0x7101a839, 0xdeb30c08, 0x9ce4b4d8, 0x90c15664, + 0x6184cb7b, 0x70b632d5, 0x745c6c48, 0x4257b8d0, + }, +#if !AES_SMALL + { /* Before: itable[1] */ + 0xa7f45150, 0x65417e53, 0xa4171ac3, 0x5e273a96, + 0x6bab3bcb, 0x459d1ff1, 0x58faacab, 0x03e34b93, + 0xfa302055, 0x6d76adf6, 0x76cc8891, 0x4c02f525, + 0xd7e54ffc, 0xcb2ac5d7, 0x44352680, 0xa362b58f, + 0x5ab1de49, 0x1bba2567, 0x0eea4598, 0xc0fe5de1, + 0x752fc302, 0xf04c8112, 0x97468da3, 0xf9d36bc6, + 0x5f8f03e7, 0x9c921595, 0x7a6dbfeb, 0x595295da, + 0x83bed42d, 0x217458d3, 0x69e04929, 0xc8c98e44, + 0x89c2756a, 0x798ef478, 0x3e58996b, 0x71b927dd, + 0x4fe1beb6, 0xad88f017, 0xac20c966, 0x3ace7db4, + 0x4adf6318, 0x311ae582, 0x33519760, 0x7f536245, + 0x7764b1e0, 0xae6bbb84, 0xa081fe1c, 0x2b08f994, + 0x68487058, 0xfd458f19, 0x6cde9487, 0xf87b52b7, + 0xd373ab23, 0x024b72e2, 0x8f1fe357, 0xab55662a, + 0x28ebb207, 0xc2b52f03, 0x7bc5869a, 0x0837d3a5, + 0x872830f2, 0xa5bf23b2, 0x6a0302ba, 0x8216ed5c, + 0x1ccf8a2b, 0xb479a792, 0xf207f3f0, 0xe2694ea1, + 0xf4da65cd, 0xbe0506d5, 0x6234d11f, 0xfea6c48a, + 0x532e349d, 0x55f3a2a0, 0xe18a0532, 0xebf6a475, + 0xec830b39, 0xef6040aa, 0x9f715e06, 0x106ebd51, + 0x8a213ef9, 0x06dd963d, 0x053eddae, 0xbde64d46, + 0x8d5491b5, 0x5dc47105, 0xd406046f, 0x155060ff, + 0xfb981924, 0xe9bdd697, 0x434089cc, 0x9ed96777, + 0x42e8b0bd, 0x8b890788, 0x5b19e738, 0xeec879db, + 0x0a7ca147, 0x0f427ce9, 0x1e84f8c9, 0x00000000, + 0x86800983, 0xed2b3248, 0x70111eac, 0x725a6c4e, + 0xff0efdfb, 0x38850f56, 0xd5ae3d1e, 0x392d3627, + 0xd90f0a64, 0xa65c6821, 0x545b9bd1, 0x2e36243a, + 0x670a0cb1, 0xe757930f, 0x96eeb4d2, 0x919b1b9e, + 0xc5c0804f, 0x20dc61a2, 0x4b775a69, 0x1a121c16, + 0xba93e20a, 0x2aa0c0e5, 0xe0223c43, 0x171b121d, + 0x0d090e0b, 0xc78bf2ad, 0xa8b62db9, 0xa91e14c8, + 0x19f15785, 0x0775af4c, 0xdd99eebb, 0x607fa3fd, + 0x2601f79f, 0xf5725cbc, 0x3b6644c5, 0x7efb5b34, + 0x29438b76, 0xc623cbdc, 0xfcedb668, 0xf1e4b863, + 0xdc31d7ca, 0x85634210, 0x22971340, 0x11c68420, + 0x244a857d, 0x3dbbd2f8, 0x32f9ae11, 0xa129c76d, + 0x2f9e1d4b, 0x30b2dcf3, 0x52860dec, 0xe3c177d0, + 0x16b32b6c, 0xb970a999, 0x489411fa, 0x64e94722, + 0x8cfca8c4, 0x3ff0a01a, 0x2c7d56d8, 0x903322ef, + 0x4e4987c7, 0xd138d9c1, 0xa2ca8cfe, 0x0bd49836, + 0x81f5a6cf, 0xde7aa528, 0x8eb7da26, 0xbfad3fa4, + 0x9d3a2ce4, 0x9278500d, 0xcc5f6a9b, 0x467e5462, + 0x138df6c2, 0xb8d890e8, 0xf7392e5e, 0xafc382f5, + 0x805d9fbe, 0x93d0697c, 0x2dd56fa9, 0x1225cfb3, + 0x99acc83b, 0x7d1810a7, 0x639ce86e, 0xbb3bdb7b, + 0x7826cd09, 0x18596ef4, 0xb79aec01, 0x9a4f83a8, + 0x6e95e665, 0xe6ffaa7e, 0xcfbc2108, 0xe815efe6, + 0x9be7bad9, 0x366f4ace, 0x099fead4, 0x7cb029d6, + 0xb2a431af, 0x233f2a31, 0x94a5c630, 0x66a235c0, + 0xbc4e7437, 0xca82fca6, 0xd090e0b0, 0xd8a73315, + 0x9804f14a, 0xdaec41f7, 0x50cd7f0e, 0xf691172f, + 0xd64d768d, 0xb0ef434d, 0x4daacc54, 0x0496e4df, + 0xb5d19ee3, 0x886a4c1b, 0x1f2cc1b8, 0x5165467f, + 0xea5e9d04, 0x358c015d, 0x7487fa73, 0x410bfb2e, + 0x1d67b35a, 0xd2db9252, 0x5610e933, 0x47d66d13, + 0x61d79a8c, 0x0ca1377a, 0x14f8598e, 0x3c13eb89, + 0x27a9ceee, 0xc961b735, 0xe51ce1ed, 0xb1477a3c, + 0xdfd29c59, 0x73f2553f, 0xce141879, 0x37c773bf, + 0xcdf753ea, 0xaafd5f5b, 0x6f3ddf14, 0xdb447886, + 0xf3afca81, 0xc468b93e, 0x3424382c, 0x40a3c25f, + 0xc31d1672, 0x25e2bc0c, 0x493c288b, 0x950dff41, + 0x01a83971, 0xb30c08de, 0xe4b4d89c, 0xc1566490, + 0x84cb7b61, 0xb632d570, 0x5c6c4874, 0x57b8d042, + }, { /* Before: itable[2] */ + 0xf45150a7, 0x417e5365, 0x171ac3a4, 0x273a965e, + 0xab3bcb6b, 0x9d1ff145, 0xfaacab58, 0xe34b9303, + 0x302055fa, 0x76adf66d, 0xcc889176, 0x02f5254c, + 0xe54ffcd7, 0x2ac5d7cb, 0x35268044, 0x62b58fa3, + 0xb1de495a, 0xba25671b, 0xea45980e, 0xfe5de1c0, + 0x2fc30275, 0x4c8112f0, 0x468da397, 0xd36bc6f9, + 0x8f03e75f, 0x9215959c, 0x6dbfeb7a, 0x5295da59, + 0xbed42d83, 0x7458d321, 0xe0492969, 0xc98e44c8, + 0xc2756a89, 0x8ef47879, 0x58996b3e, 0xb927dd71, + 0xe1beb64f, 0x88f017ad, 0x20c966ac, 0xce7db43a, + 0xdf63184a, 0x1ae58231, 0x51976033, 0x5362457f, + 0x64b1e077, 0x6bbb84ae, 0x81fe1ca0, 0x08f9942b, + 0x48705868, 0x458f19fd, 0xde94876c, 0x7b52b7f8, + 0x73ab23d3, 0x4b72e202, 0x1fe3578f, 0x55662aab, + 0xebb20728, 0xb52f03c2, 0xc5869a7b, 0x37d3a508, + 0x2830f287, 0xbf23b2a5, 0x0302ba6a, 0x16ed5c82, + 0xcf8a2b1c, 0x79a792b4, 0x07f3f0f2, 0x694ea1e2, + 0xda65cdf4, 0x0506d5be, 0x34d11f62, 0xa6c48afe, + 0x2e349d53, 0xf3a2a055, 0x8a0532e1, 0xf6a475eb, + 0x830b39ec, 0x6040aaef, 0x715e069f, 0x6ebd5110, + 0x213ef98a, 0xdd963d06, 0x3eddae05, 0xe64d46bd, + 0x5491b58d, 0xc471055d, 0x06046fd4, 0x5060ff15, + 0x981924fb, 0xbdd697e9, 0x4089cc43, 0xd967779e, + 0xe8b0bd42, 0x8907888b, 0x19e7385b, 0xc879dbee, + 0x7ca1470a, 0x427ce90f, 0x84f8c91e, 0x00000000, + 0x80098386, 0x2b3248ed, 0x111eac70, 0x5a6c4e72, + 0x0efdfbff, 0x850f5638, 0xae3d1ed5, 0x2d362739, + 0x0f0a64d9, 0x5c6821a6, 0x5b9bd154, 0x36243a2e, + 0x0a0cb167, 0x57930fe7, 0xeeb4d296, 0x9b1b9e91, + 0xc0804fc5, 0xdc61a220, 0x775a694b, 0x121c161a, + 0x93e20aba, 0xa0c0e52a, 0x223c43e0, 0x1b121d17, + 0x090e0b0d, 0x8bf2adc7, 0xb62db9a8, 0x1e14c8a9, + 0xf1578519, 0x75af4c07, 0x99eebbdd, 0x7fa3fd60, + 0x01f79f26, 0x725cbcf5, 0x6644c53b, 0xfb5b347e, + 0x438b7629, 0x23cbdcc6, 0xedb668fc, 0xe4b863f1, + 0x31d7cadc, 0x63421085, 0x97134022, 0xc6842011, + 0x4a857d24, 0xbbd2f83d, 0xf9ae1132, 0x29c76da1, + 0x9e1d4b2f, 0xb2dcf330, 0x860dec52, 0xc177d0e3, + 0xb32b6c16, 0x70a999b9, 0x9411fa48, 0xe9472264, + 0xfca8c48c, 0xf0a01a3f, 0x7d56d82c, 0x3322ef90, + 0x4987c74e, 0x38d9c1d1, 0xca8cfea2, 0xd498360b, + 0xf5a6cf81, 0x7aa528de, 0xb7da268e, 0xad3fa4bf, + 0x3a2ce49d, 0x78500d92, 0x5f6a9bcc, 0x7e546246, + 0x8df6c213, 0xd890e8b8, 0x392e5ef7, 0xc382f5af, + 0x5d9fbe80, 0xd0697c93, 0xd56fa92d, 0x25cfb312, + 0xacc83b99, 0x1810a77d, 0x9ce86e63, 0x3bdb7bbb, + 0x26cd0978, 0x596ef418, 0x9aec01b7, 0x4f83a89a, + 0x95e6656e, 0xffaa7ee6, 0xbc2108cf, 0x15efe6e8, + 0xe7bad99b, 0x6f4ace36, 0x9fead409, 0xb029d67c, + 0xa431afb2, 0x3f2a3123, 0xa5c63094, 0xa235c066, + 0x4e7437bc, 0x82fca6ca, 0x90e0b0d0, 0xa73315d8, + 0x04f14a98, 0xec41f7da, 0xcd7f0e50, 0x91172ff6, + 0x4d768dd6, 0xef434db0, 0xaacc544d, 0x96e4df04, + 0xd19ee3b5, 0x6a4c1b88, 0x2cc1b81f, 0x65467f51, + 0x5e9d04ea, 0x8c015d35, 0x87fa7374, 0x0bfb2e41, + 0x67b35a1d, 0xdb9252d2, 0x10e93356, 0xd66d1347, + 0xd79a8c61, 0xa1377a0c, 0xf8598e14, 0x13eb893c, + 0xa9ceee27, 0x61b735c9, 0x1ce1ede5, 0x477a3cb1, + 0xd29c59df, 0xf2553f73, 0x141879ce, 0xc773bf37, + 0xf753eacd, 0xfd5f5baa, 0x3ddf146f, 0x447886db, + 0xafca81f3, 0x68b93ec4, 0x24382c34, 0xa3c25f40, + 0x1d1672c3, 0xe2bc0c25, 0x3c288b49, 0x0dff4195, + 0xa8397101, 0x0c08deb3, 0xb4d89ce4, 0x566490c1, + 0xcb7b6184, 0x32d570b6, 0x6c48745c, 0xb8d04257, + }, { /* Before: itable[3] */ + 0x5150a7f4, 0x7e536541, 0x1ac3a417, 0x3a965e27, + 0x3bcb6bab, 0x1ff1459d, 0xacab58fa, 0x4b9303e3, + 0x2055fa30, 0xadf66d76, 0x889176cc, 0xf5254c02, + 0x4ffcd7e5, 0xc5d7cb2a, 0x26804435, 0xb58fa362, + 0xde495ab1, 0x25671bba, 0x45980eea, 0x5de1c0fe, + 0xc302752f, 0x8112f04c, 0x8da39746, 0x6bc6f9d3, + 0x03e75f8f, 0x15959c92, 0xbfeb7a6d, 0x95da5952, + 0xd42d83be, 0x58d32174, 0x492969e0, 0x8e44c8c9, + 0x756a89c2, 0xf478798e, 0x996b3e58, 0x27dd71b9, + 0xbeb64fe1, 0xf017ad88, 0xc966ac20, 0x7db43ace, + 0x63184adf, 0xe582311a, 0x97603351, 0x62457f53, + 0xb1e07764, 0xbb84ae6b, 0xfe1ca081, 0xf9942b08, + 0x70586848, 0x8f19fd45, 0x94876cde, 0x52b7f87b, + 0xab23d373, 0x72e2024b, 0xe3578f1f, 0x662aab55, + 0xb20728eb, 0x2f03c2b5, 0x869a7bc5, 0xd3a50837, + 0x30f28728, 0x23b2a5bf, 0x02ba6a03, 0xed5c8216, + 0x8a2b1ccf, 0xa792b479, 0xf3f0f207, 0x4ea1e269, + 0x65cdf4da, 0x06d5be05, 0xd11f6234, 0xc48afea6, + 0x349d532e, 0xa2a055f3, 0x0532e18a, 0xa475ebf6, + 0x0b39ec83, 0x40aaef60, 0x5e069f71, 0xbd51106e, + 0x3ef98a21, 0x963d06dd, 0xddae053e, 0x4d46bde6, + 0x91b58d54, 0x71055dc4, 0x046fd406, 0x60ff1550, + 0x1924fb98, 0xd697e9bd, 0x89cc4340, 0x67779ed9, + 0xb0bd42e8, 0x07888b89, 0xe7385b19, 0x79dbeec8, + 0xa1470a7c, 0x7ce90f42, 0xf8c91e84, 0x00000000, + 0x09838680, 0x3248ed2b, 0x1eac7011, 0x6c4e725a, + 0xfdfbff0e, 0x0f563885, 0x3d1ed5ae, 0x3627392d, + 0x0a64d90f, 0x6821a65c, 0x9bd1545b, 0x243a2e36, + 0x0cb1670a, 0x930fe757, 0xb4d296ee, 0x1b9e919b, + 0x804fc5c0, 0x61a220dc, 0x5a694b77, 0x1c161a12, + 0xe20aba93, 0xc0e52aa0, 0x3c43e022, 0x121d171b, + 0x0e0b0d09, 0xf2adc78b, 0x2db9a8b6, 0x14c8a91e, + 0x578519f1, 0xaf4c0775, 0xeebbdd99, 0xa3fd607f, + 0xf79f2601, 0x5cbcf572, 0x44c53b66, 0x5b347efb, + 0x8b762943, 0xcbdcc623, 0xb668fced, 0xb863f1e4, + 0xd7cadc31, 0x42108563, 0x13402297, 0x842011c6, + 0x857d244a, 0xd2f83dbb, 0xae1132f9, 0xc76da129, + 0x1d4b2f9e, 0xdcf330b2, 0x0dec5286, 0x77d0e3c1, + 0x2b6c16b3, 0xa999b970, 0x11fa4894, 0x472264e9, + 0xa8c48cfc, 0xa01a3ff0, 0x56d82c7d, 0x22ef9033, + 0x87c74e49, 0xd9c1d138, 0x8cfea2ca, 0x98360bd4, + 0xa6cf81f5, 0xa528de7a, 0xda268eb7, 0x3fa4bfad, + 0x2ce49d3a, 0x500d9278, 0x6a9bcc5f, 0x5462467e, + 0xf6c2138d, 0x90e8b8d8, 0x2e5ef739, 0x82f5afc3, + 0x9fbe805d, 0x697c93d0, 0x6fa92dd5, 0xcfb31225, + 0xc83b99ac, 0x10a77d18, 0xe86e639c, 0xdb7bbb3b, + 0xcd097826, 0x6ef41859, 0xec01b79a, 0x83a89a4f, + 0xe6656e95, 0xaa7ee6ff, 0x2108cfbc, 0xefe6e815, + 0xbad99be7, 0x4ace366f, 0xead4099f, 0x29d67cb0, + 0x31afb2a4, 0x2a31233f, 0xc63094a5, 0x35c066a2, + 0x7437bc4e, 0xfca6ca82, 0xe0b0d090, 0x3315d8a7, + 0xf14a9804, 0x41f7daec, 0x7f0e50cd, 0x172ff691, + 0x768dd64d, 0x434db0ef, 0xcc544daa, 0xe4df0496, + 0x9ee3b5d1, 0x4c1b886a, 0xc1b81f2c, 0x467f5165, + 0x9d04ea5e, 0x015d358c, 0xfa737487, 0xfb2e410b, + 0xb35a1d67, 0x9252d2db, 0xe9335610, 0x6d1347d6, + 0x9a8c61d7, 0x377a0ca1, 0x598e14f8, 0xeb893c13, + 0xceee27a9, 0xb735c961, 0xe1ede51c, 0x7a3cb147, + 0x9c59dfd2, 0x553f73f2, 0x1879ce14, 0x73bf37c7, + 0x53eacdf7, 0x5f5baafd, 0xdf146f3d, 0x7886db44, + 0xca81f3af, 0xb93ec468, 0x382c3424, 0xc25f40a3, + 0x1672c31d, 0xbc0c25e2, 0x288b493c, 0xff41950d, + 0x397101a8, 0x08deb30c, 0xd89ce4b4, 0x6490c156, + 0x7b6184cb, 0xd570b632, 0x48745c6c, 0xd04257b8, + }, +#endif /* !AES_SMALL */ + } +}; + + +// From nettle/aes.h + +#define AES128_KEY_SIZE 16 +#define AES192_KEY_SIZE 24 +#define AES256_KEY_SIZE 32 +#define _AES128_ROUNDS 10 +#define _AES192_ROUNDS 12 +#define _AES256_ROUNDS 14 +#define AES_BLOCK_SIZE 16 + +/* Variable key size between 128 and 256 bits. But the only valid + * values are 16 (128 bits), 24 (192 bits) and 32 (256 bits). */ +#define AES_MIN_KEY_SIZE AES128_KEY_SIZE +#define AES_MAX_KEY_SIZE AES256_KEY_SIZE + +struct aes_ctx +{ + unsigned rounds; /* number of rounds to use for our key size */ + uint32_t keys[4 * (_AES256_ROUNDS + 1)]; /* maximum size of key schedule */ +}; + + +// From nettle/aes-set-key-internal.c + +void +_aes_set_key (unsigned nr, unsigned nk, + uint32_t * subkeys, const uint8_t * key) +{ + static const uint8_t rcon[10] = { + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, + }; + const uint8_t *rp; + unsigned lastkey, i; + uint32_t t; + + assert_beebs (nk != 0); + lastkey = (AES_BLOCK_SIZE / 4) * (nr + 1); + + for (i = 0, rp = rcon; i < nk; i++) + subkeys[i] = LE_READ_UINT32 (key + i * 4); + + for (i = nk; i < lastkey; i++) + { + t = subkeys[i - 1]; + if (i % nk == 0) + t = SUBBYTE (ROTL32 (24, t), aes_sbox) ^ *rp++; + + else if (nk > 6 && (i % nk) == 4) + t = SUBBYTE (t, aes_sbox); + + subkeys[i] = subkeys[i - nk] ^ t; + } +} + + +// From nettle/aes-set-encrypt-key.c + +void +aes_set_encrypt_key (struct aes_ctx *ctx, size_t keysize, const uint8_t * key) +{ + unsigned nk, nr; + + assert_beebs (keysize >= AES_MIN_KEY_SIZE); + assert_beebs (keysize <= AES_MAX_KEY_SIZE); + + /* Truncate keysizes to the valid key sizes provided by Rijndael */ + if (keysize == AES256_KEY_SIZE) + { + nk = 8; + nr = _AES256_ROUNDS; + } + else if (keysize >= AES192_KEY_SIZE) + { + nk = 6; + nr = _AES192_ROUNDS; + } + else + { /* must be 16 or more */ + nk = 4; + nr = _AES128_ROUNDS; + } + + ctx->rounds = nr; + _aes_set_key (nr, nk, ctx->keys, key); +} + + +// From nettle/aes-invert-internal.c + +/* NOTE: We don't include rotated versions of the table. */ +static const uint32_t mtable[0x100] = { + 0x00000000, 0x0b0d090e, 0x161a121c, 0x1d171b12, + 0x2c342438, 0x27392d36, 0x3a2e3624, 0x31233f2a, + 0x58684870, 0x5365417e, 0x4e725a6c, 0x457f5362, + 0x745c6c48, 0x7f516546, 0x62467e54, 0x694b775a, + 0xb0d090e0, 0xbbdd99ee, 0xa6ca82fc, 0xadc78bf2, + 0x9ce4b4d8, 0x97e9bdd6, 0x8afea6c4, 0x81f3afca, + 0xe8b8d890, 0xe3b5d19e, 0xfea2ca8c, 0xf5afc382, + 0xc48cfca8, 0xcf81f5a6, 0xd296eeb4, 0xd99be7ba, + 0x7bbb3bdb, 0x70b632d5, 0x6da129c7, 0x66ac20c9, + 0x578f1fe3, 0x5c8216ed, 0x41950dff, 0x4a9804f1, + 0x23d373ab, 0x28de7aa5, 0x35c961b7, 0x3ec468b9, + 0x0fe75793, 0x04ea5e9d, 0x19fd458f, 0x12f04c81, + 0xcb6bab3b, 0xc066a235, 0xdd71b927, 0xd67cb029, + 0xe75f8f03, 0xec52860d, 0xf1459d1f, 0xfa489411, + 0x9303e34b, 0x980eea45, 0x8519f157, 0x8e14f859, + 0xbf37c773, 0xb43ace7d, 0xa92dd56f, 0xa220dc61, + 0xf66d76ad, 0xfd607fa3, 0xe07764b1, 0xeb7a6dbf, + 0xda595295, 0xd1545b9b, 0xcc434089, 0xc74e4987, + 0xae053edd, 0xa50837d3, 0xb81f2cc1, 0xb31225cf, + 0x82311ae5, 0x893c13eb, 0x942b08f9, 0x9f2601f7, + 0x46bde64d, 0x4db0ef43, 0x50a7f451, 0x5baafd5f, + 0x6a89c275, 0x6184cb7b, 0x7c93d069, 0x779ed967, + 0x1ed5ae3d, 0x15d8a733, 0x08cfbc21, 0x03c2b52f, + 0x32e18a05, 0x39ec830b, 0x24fb9819, 0x2ff69117, + 0x8dd64d76, 0x86db4478, 0x9bcc5f6a, 0x90c15664, + 0xa1e2694e, 0xaaef6040, 0xb7f87b52, 0xbcf5725c, + 0xd5be0506, 0xdeb30c08, 0xc3a4171a, 0xc8a91e14, + 0xf98a213e, 0xf2872830, 0xef903322, 0xe49d3a2c, + 0x3d06dd96, 0x360bd498, 0x2b1ccf8a, 0x2011c684, + 0x1132f9ae, 0x1a3ff0a0, 0x0728ebb2, 0x0c25e2bc, + 0x656e95e6, 0x6e639ce8, 0x737487fa, 0x78798ef4, + 0x495ab1de, 0x4257b8d0, 0x5f40a3c2, 0x544daacc, + 0xf7daec41, 0xfcd7e54f, 0xe1c0fe5d, 0xeacdf753, + 0xdbeec879, 0xd0e3c177, 0xcdf4da65, 0xc6f9d36b, + 0xafb2a431, 0xa4bfad3f, 0xb9a8b62d, 0xb2a5bf23, + 0x83868009, 0x888b8907, 0x959c9215, 0x9e919b1b, + 0x470a7ca1, 0x4c0775af, 0x51106ebd, 0x5a1d67b3, + 0x6b3e5899, 0x60335197, 0x7d244a85, 0x7629438b, + 0x1f6234d1, 0x146f3ddf, 0x097826cd, 0x02752fc3, + 0x335610e9, 0x385b19e7, 0x254c02f5, 0x2e410bfb, + 0x8c61d79a, 0x876cde94, 0x9a7bc586, 0x9176cc88, + 0xa055f3a2, 0xab58faac, 0xb64fe1be, 0xbd42e8b0, + 0xd4099fea, 0xdf0496e4, 0xc2138df6, 0xc91e84f8, + 0xf83dbbd2, 0xf330b2dc, 0xee27a9ce, 0xe52aa0c0, + 0x3cb1477a, 0x37bc4e74, 0x2aab5566, 0x21a65c68, + 0x10856342, 0x1b886a4c, 0x069f715e, 0x0d927850, + 0x64d90f0a, 0x6fd40604, 0x72c31d16, 0x79ce1418, + 0x48ed2b32, 0x43e0223c, 0x5ef7392e, 0x55fa3020, + 0x01b79aec, 0x0aba93e2, 0x17ad88f0, 0x1ca081fe, + 0x2d83bed4, 0x268eb7da, 0x3b99acc8, 0x3094a5c6, + 0x59dfd29c, 0x52d2db92, 0x4fc5c080, 0x44c8c98e, + 0x75ebf6a4, 0x7ee6ffaa, 0x63f1e4b8, 0x68fcedb6, + 0xb1670a0c, 0xba6a0302, 0xa77d1810, 0xac70111e, + 0x9d532e34, 0x965e273a, 0x8b493c28, 0x80443526, + 0xe90f427c, 0xe2024b72, 0xff155060, 0xf418596e, + 0xc53b6644, 0xce366f4a, 0xd3217458, 0xd82c7d56, + 0x7a0ca137, 0x7101a839, 0x6c16b32b, 0x671bba25, + 0x5638850f, 0x5d358c01, 0x40229713, 0x4b2f9e1d, + 0x2264e947, 0x2969e049, 0x347efb5b, 0x3f73f255, + 0x0e50cd7f, 0x055dc471, 0x184adf63, 0x1347d66d, + 0xcadc31d7, 0xc1d138d9, 0xdcc623cb, 0xd7cb2ac5, + 0xe6e815ef, 0xede51ce1, 0xf0f207f3, 0xfbff0efd, + 0x92b479a7, 0x99b970a9, 0x84ae6bbb, 0x8fa362b5, + 0xbe805d9f, 0xb58d5491, 0xa89a4f83, 0xa397468d, +}; + +#define MIX_COLUMN(T, key) do { \ + uint32_t _k, _nk, _t; \ + _k = (key); \ + _nk = T[_k & 0xff]; \ + _k >>= 8; \ + _t = T[_k & 0xff]; \ + _nk ^= ROTL32(8, _t); \ + _k >>= 8; \ + _t = T[_k & 0xff]; \ + _nk ^= ROTL32(16, _t); \ + _k >>= 8; \ + _t = T[_k & 0xff]; \ + _nk ^= ROTL32(24, _t); \ + (key) = _nk; \ + } while(0) + + +#define SWAP(a, b) \ +do { uint32_t t_swap = (a); (a) = (b); (b) = t_swap; } while(0) + +void +_nettle_aes_invert (unsigned rounds, uint32_t * dst, const uint32_t * src) +{ + unsigned i; + + /* Reverse the order of subkeys, in groups of 4. */ + /* FIXME: Instead of reordering the subkeys, change the access order + of aes_decrypt, since it's a separate function anyway? */ + if (src == dst) + { + unsigned j, k; + + for (i = 0, j = rounds * 4; i < j; i += 4, j -= 4) + for (k = 0; k < 4; k++) + SWAP (dst[i + k], dst[j + k]); + } + else + { + unsigned k; + + for (i = 0; i <= rounds * 4; i += 4) + for (k = 0; k < 4; k++) + dst[i + k] = src[rounds * 4 - i + k]; + } + + /* Transform all subkeys but the first and last. */ + for (i = 4; i < 4 * rounds; i++) + MIX_COLUMN (mtable, dst[i]); +} + + +// From nettle/aes-set-decrypt-key.c + +void +aes_invert_key (struct aes_ctx *dst, const struct aes_ctx *src) +{ + _nettle_aes_invert (src->rounds, dst->keys, src->keys); + dst->rounds = src->rounds; +} + +void +aes_set_decrypt_key (struct aes_ctx *ctx, size_t keysize, const uint8_t * key) +{ + /* We first create subkeys for encryption, + * then modify the subkeys for decryption. */ + aes_set_encrypt_key (ctx, keysize, key); + aes_invert_key (ctx, ctx); +} + + +// From nettle/aes-encrypt-internal.c + +void +_nettle_aes_encrypt (unsigned rounds, const uint32_t * keys, + const struct aes_table *T, + size_t length, uint8_t * dst, const uint8_t * src) +{ + FOR_BLOCKS (length, dst, src, AES_BLOCK_SIZE) + { + uint32_t w0, w1, w2, w3; /* working ciphertext */ + uint32_t t0, t1, t2, t3; + unsigned i; + + /* Get clear text, using little-endian byte order. + * Also XOR with the first subkey. */ + + w0 = LE_READ_UINT32 (src) ^ keys[0]; + w1 = LE_READ_UINT32 (src + 4) ^ keys[1]; + w2 = LE_READ_UINT32 (src + 8) ^ keys[2]; + w3 = LE_READ_UINT32 (src + 12) ^ keys[3]; + + for (i = 1; i < rounds; i++) + { + t0 = AES_ROUND (T, w0, w1, w2, w3, keys[4 * i]); + t1 = AES_ROUND (T, w1, w2, w3, w0, keys[4 * i + 1]); + t2 = AES_ROUND (T, w2, w3, w0, w1, keys[4 * i + 2]); + t3 = AES_ROUND (T, w3, w0, w1, w2, keys[4 * i + 3]); + + /* We could unroll the loop twice, to avoid these + assignments. If all eight variables fit in registers, + that should give a slight speedup. */ + w0 = t0; + w1 = t1; + w2 = t2; + w3 = t3; + } + + /* Final round */ + + t0 = AES_FINAL_ROUND (T, w0, w1, w2, w3, keys[4 * i]); + t1 = AES_FINAL_ROUND (T, w1, w2, w3, w0, keys[4 * i + 1]); + t2 = AES_FINAL_ROUND (T, w2, w3, w0, w1, keys[4 * i + 2]); + t3 = AES_FINAL_ROUND (T, w3, w0, w1, w2, keys[4 * i + 3]); + + LE_WRITE_UINT32 (dst, t0); + LE_WRITE_UINT32 (dst + 4, t1); + LE_WRITE_UINT32 (dst + 8, t2); + LE_WRITE_UINT32 (dst + 12, t3); + } +} + + +// From nettle/aes-decrypt-internal.c + +void +_nettle_aes_decrypt (unsigned rounds, const uint32_t * keys, + const struct aes_table *T, + size_t length, uint8_t * dst, const uint8_t * src) +{ + FOR_BLOCKS (length, dst, src, AES_BLOCK_SIZE) + { + uint32_t w0, w1, w2, w3; /* working ciphertext */ + uint32_t t0, t1, t2, t3; + unsigned i; + + /* Get clear text, using little-endian byte order. + * Also XOR with the first subkey. */ + + w0 = LE_READ_UINT32 (src) ^ keys[0]; + w1 = LE_READ_UINT32 (src + 4) ^ keys[1]; + w2 = LE_READ_UINT32 (src + 8) ^ keys[2]; + w3 = LE_READ_UINT32 (src + 12) ^ keys[3]; + + for (i = 1; i < rounds; i++) + { + t0 = AES_ROUND (T, w0, w3, w2, w1, keys[4 * i]); + t1 = AES_ROUND (T, w1, w0, w3, w2, keys[4 * i + 1]); + t2 = AES_ROUND (T, w2, w1, w0, w3, keys[4 * i + 2]); + t3 = AES_ROUND (T, w3, w2, w1, w0, keys[4 * i + 3]); + + /* We could unroll the loop twice, to avoid these + assignments. If all eight variables fit in registers, + that should give a slight speedup. */ + w0 = t0; + w1 = t1; + w2 = t2; + w3 = t3; + } + + /* Final round */ + + t0 = AES_FINAL_ROUND (T, w0, w3, w2, w1, keys[4 * i]); + t1 = AES_FINAL_ROUND (T, w1, w0, w3, w2, keys[4 * i + 1]); + t2 = AES_FINAL_ROUND (T, w2, w1, w0, w3, keys[4 * i + 2]); + t3 = AES_FINAL_ROUND (T, w3, w2, w1, w0, keys[4 * i + 3]); + + LE_WRITE_UINT32 (dst, t0); + LE_WRITE_UINT32 (dst + 4, t1); + LE_WRITE_UINT32 (dst + 8, t2); + LE_WRITE_UINT32 (dst + 12, t3); + } +} + + +// From nettle/aes-encrypt.c + +void +aes_encrypt (const struct aes_ctx *ctx, + size_t length, uint8_t * dst, const uint8_t * src) +{ + assert_beebs (!(length % AES_BLOCK_SIZE)); + _nettle_aes_encrypt (ctx->rounds, ctx->keys, &_aes_encrypt_table, + length, dst, src); +} + + +// From nettle/aes-decrypt.c + +void +aes_decrypt (const struct aes_ctx *ctx, + size_t length, uint8_t * dst, const uint8_t * src) +{ + assert_beebs (!(length % AES_BLOCK_SIZE)); + _nettle_aes_decrypt (ctx->rounds, ctx->keys, &_aes_decrypt_table, + length, dst, src); +} + + +// BEEBS benchmark code + +unsigned char key[32] = + { 0xC9, 0x95, 0x55, 0x31, 0xA6, 0x50, 0xD1, 0x54, 0x7B, 0xD8, 0xC5, 0xAA, + 0xA4, 0xA4, 0xBD, 0xAC, 0x5C, 0xEA, 0x12, 0xC7, 0xF8, 0x83, 0xD6, 0xB8, + 0x5D, 0xD6, 0xCF, 0x2D, 0x60, 0xC8, 0xA5, 0xF0 +}; + +#define LEN 256 +unsigned char plaintext[LEN] = + { 0xD7, 0x7F, 0xB3, 0x8C, 0x22, 0x25, 0xC4, 0x6F, 0xB9, 0xD5, 0xC9, 0x18, + 0xC0, 0x92, 0xD0, 0x08, 0x85, 0x2A, 0xF3, 0x68, 0xBD, 0x84, 0xAF, 0xF2, + 0x0C, 0x8B, 0xF5, 0x1E, 0x51, 0x70, 0x46, 0x70, 0x9E, 0x8B, 0xDE, 0xE1, + 0x86, 0xA1, 0xF8, 0xCD, 0x71, 0x02, 0x9F, 0xA1, 0x7B, 0x44, 0xB0, 0x82, + 0x40, 0x7F, 0xCE, 0xB4, 0xBE, 0x5D, 0xBC, 0x8E, 0x19, 0x43, 0x0B, 0x3A, + 0x46, 0x69, 0xA0, 0xCC, 0xED, 0x4F, 0x61, 0xAF, 0xA6, 0xA9, 0x5B, 0x47, + 0x69, 0x51, 0xD5, 0x00, 0x77, 0x7E, 0xDE, 0x2E, 0x7E, 0xA6, 0x3C, 0xE0, + 0x33, 0xDF, 0xED, 0x40, 0x3F, 0x1A, 0xC7, 0xE0, 0xC7, 0x46, 0xE3, 0x3B, + 0x90, 0x4E, 0x64, 0x55, 0x2E, 0x8D, 0x36, 0x3B, 0x92, 0x9B, 0x87, 0x6F, + 0xAE, 0x94, 0x3D, 0x0A, 0xC8, 0xA2, 0x4E, 0x7F, 0x5A, 0x83, 0xEC, 0x18, + 0xFD, 0x82, 0x54, 0xC8, 0xD8, 0xED, 0x1E, 0x52, 0x7D, 0xCA, 0xCF, 0x4B, + 0xBA, 0x31, 0x68, 0xB9, 0x78, 0xA3, 0xCA, 0x4E, 0x72, 0x86, 0xB2, 0x33, + 0x79, 0xCB, 0xCD, 0xA6, 0x43, 0xA3, 0x9C, 0xFA, 0xEE, 0x2A, 0xAE, 0x3B, + 0x72, 0xC6, 0x46, 0x32, 0xA5, 0x99, 0x45, 0x92, 0x46, 0x79, 0xDC, 0xE3, + 0x3E, 0xA9, 0x8A, 0x11, 0x37, 0x49, 0x85, 0xE4, 0x58, 0x1A, 0x1F, 0x6E, + 0xD7, 0xAA, 0xE6, 0x0A, 0xC4, 0x27, 0xFD, 0x46, 0x5C, 0x6C, 0xB0, 0x28, + 0x2E, 0x6B, 0x84, 0x35, 0x90, 0x1A, 0x6D, 0x38, 0xF2, 0x69, 0x4A, 0xBC, + 0x96, 0xEC, 0xD7, 0x56, 0x65, 0x27, 0xEE, 0xA6, 0xB0, 0x5F, 0x9C, 0x70, + 0x71, 0xA5, 0x2B, 0xEC, 0x93, 0x67, 0x16, 0xC1, 0xC4, 0xB3, 0x43, 0x70, + 0xB5, 0x6D, 0xAD, 0x95, 0x41, 0xF0, 0x02, 0xFC, 0x8D, 0x58, 0x8E, 0xA1, + 0x46, 0x32, 0x34, 0x68, 0x11, 0x8C, 0xB3, 0x3A, 0xDB, 0x54, 0xBE, 0x3A, + 0xB3, 0x38, 0x2E, 0x7C +}; + +unsigned char expected[LEN] = + { 0x0F, 0x17, 0x00, 0x10, 0x07, 0x82, 0x7F, 0xF9, 0x45, 0xDA, 0x15, 0x0E, + 0x54, 0x94, 0x8F, 0x22, 0x74, 0x9F, 0x03, 0xCD, 0x58, 0x1A, 0xB2, 0x6B, + 0x9A, 0x68, 0x05, 0xE7, 0xCB, 0x1F, 0x75, 0xAD, 0x51, 0x85, 0x56, 0xA1, + 0xF6, 0xD8, 0xB7, 0xEC, 0x9E, 0x0D, 0xC3, 0x48, 0x7D, 0xAA, 0xF7, 0x99, + 0xC2, 0x1D, 0xEA, 0x3F, 0x53, 0xDB, 0xA8, 0x84, 0xED, 0x61, 0xC0, 0xE7, + 0x38, 0xAD, 0xDC, 0xB7, 0x9B, 0xFA, 0xC0, 0xB6, 0x88, 0x7C, 0xF0, 0x87, + 0x25, 0x20, 0xBC, 0x0B, 0x03, 0x6D, 0xB8, 0x9B, 0x10, 0xD3, 0xA8, 0x87, + 0x38, 0xBA, 0xDB, 0x43, 0x40, 0x02, 0x0F, 0x89, 0x6E, 0x11, 0x69, 0x7E, + 0x15, 0x4A, 0xC5, 0xE3, 0xB1, 0x7A, 0x9D, 0x3B, 0x74, 0xBE, 0x05, 0x58, + 0x1E, 0x40, 0x73, 0x1D, 0x83, 0xA0, 0x45, 0x89, 0xFC, 0xCF, 0xC3, 0x4E, + 0xA2, 0x52, 0xEF, 0x7E, 0x5E, 0x2C, 0x98, 0x38, 0x26, 0x57, 0xB4, 0x12, + 0x4E, 0x24, 0x10, 0xAC, 0x7C, 0x89, 0x42, 0x0D, 0x9D, 0xAF, 0x49, 0x2F, + 0xC0, 0x60, 0x75, 0x43, 0xC5, 0xD1, 0xCC, 0xFD, 0x46, 0xAE, 0x4E, 0x38, + 0xA9, 0xF3, 0x83, 0x98, 0x9F, 0xFA, 0x0A, 0x15, 0x05, 0x46, 0x2A, 0x0E, + 0xBE, 0xA8, 0xAC, 0x2D, 0x59, 0x27, 0x2E, 0x54, 0x05, 0x77, 0x52, 0x64, + 0x39, 0x60, 0xC4, 0x7C, 0xA7, 0x30, 0xB9, 0x13, 0x3B, 0x1F, 0xFE, 0x37, + 0xB0, 0xEA, 0xFD, 0x3D, 0x83, 0xED, 0x7E, 0xF2, 0xB0, 0xF2, 0x0A, 0x86, + 0x78, 0xB9, 0x08, 0x1F, 0xFF, 0xC0, 0x50, 0xAD, 0xB8, 0x92, 0x68, 0x19, + 0x30, 0x9C, 0x7E, 0xE5, 0x4C, 0x57, 0x5E, 0xA6, 0x58, 0x3A, 0x87, 0x70, + 0x80, 0x1A, 0xCF, 0x1E, 0xE8, 0x3B, 0x43, 0xC6, 0xE9, 0x27, 0x47, 0xBA, + 0x9E, 0x58, 0x52, 0x14, 0xC0, 0xB7, 0xF1, 0x77, 0x77, 0x8F, 0x23, 0x43, + 0x49, 0x0E, 0x24, 0xCE +}; + +unsigned char encrypted[LEN]; +unsigned char decrypted[LEN]; + +struct aes_ctx encctx; +struct aes_ctx decctx; + +int +verify_benchmark (int res __attribute ((unused))) +{ + bool correct = true; + + for (unsigned int i = 0; i < LEN; i++) + { + if (encrypted[i] != expected[i]) + correct = false; + if (plaintext[i] != decrypted[i]) + correct = false; + } + + return correct; +} + +void +initialise_benchmark (void) +{ +} + + +static int benchmark_body (int rpt); + +void +warm_caches (int heat) +{ + int res = benchmark_body (heat); + + return; +} + + +int +benchmark (void) +{ + return benchmark_body (LOCAL_SCALE_FACTOR * CPU_MHZ); +} + + +static int __attribute__ ((noinline)) +benchmark_body (int rpt) +{ + int i; + + for (i = 0; i < rpt; i++) + { + aes_set_encrypt_key (&encctx, 32, key); + aes_encrypt (&encctx, LEN, encrypted, plaintext); + + aes_set_decrypt_key (&decctx, 32, key); + aes_decrypt (&decctx, LEN, decrypted, encrypted); + } + + return 0; +} + + +/* + Local Variables: + mode: C + c-file-style: "gnu" + End: +*/ diff --git a/benchies/embench/benchemarks/nettle-sha256/nettle-sha256.c b/benchies/embench/benchemarks/nettle-sha256/nettle-sha256.c new file mode 100644 index 0000000000..8e42e97e1a --- /dev/null +++ b/benchies/embench/benchemarks/nettle-sha256/nettle-sha256.c @@ -0,0 +1,490 @@ +/* BEEBS Nettle-SHA256 + + Copyright (C) 2001 Niels Möller + Copyright (C) 2019 Embecosm Limited + + Contributor Graham Markall + + This file is part of Embench and was formerly part of the Bristol/Embecosm + Embedded Benchmark Suite. + + SPDX-License-Identifier: GPL-3.0-or-later */ + +#include +#include +#include +#include +#include +#include +#include "../../src/support.h" + +/* This scale factor will be changed to equalise the runtime of the + benchmarks. */ +#define LOCAL_SCALE_FACTOR 475 + +// From nettle/nettle-types.h + +/* Hash algorithms */ +typedef void nettle_hash_init_func (void *ctx); +typedef void nettle_hash_update_func (void *ctx, + size_t length, const uint8_t * src); +typedef void nettle_hash_digest_func (void *ctx, + size_t length, uint8_t * dst); + + +// From nettle/macros.h + +#define MD_UPDATE(ctx, length, data, f, incr) \ + do { \ + if ((ctx)->index) \ + { \ + /* Try to fill partial block */ \ + unsigned __md_left = sizeof((ctx)->block) - (ctx)->index; \ + if ((length) < __md_left) \ + { \ + memcpy((ctx)->block + (ctx)->index, (data), (length)); \ + (ctx)->index += (length); \ + goto __md_done; /* Finished */ \ + } \ + else \ + { \ + memcpy((ctx)->block + (ctx)->index, (data), __md_left); \ + \ + f((ctx), (ctx)->block); \ + (incr); \ + \ + (data) += __md_left; \ + (length) -= __md_left; \ + } \ + } \ + while ((length) >= sizeof((ctx)->block)) \ + { \ + f((ctx), (data)); \ + (incr); \ + \ + (data) += sizeof((ctx)->block); \ + (length) -= sizeof((ctx)->block); \ + } \ + memcpy ((ctx)->block, (data), (length)); \ + (ctx)->index = (length); \ + __md_done: \ + ; \ + } while (0) + +#define MD_PAD(ctx, size, f) \ + do { \ + unsigned __md_i; \ + __md_i = (ctx)->index; \ + \ + /* Set the first char of padding to 0x80. This is safe since there \ + is always at least one byte free */ \ + \ + assert_beebs(__md_i < sizeof((ctx)->block)); \ + (ctx)->block[__md_i++] = 0x80; \ + \ + if (__md_i > (sizeof((ctx)->block) - (size))) \ + { /* No room for length in this block. Process it and \ + pad with another one */ \ + memset((ctx)->block + __md_i, 0, sizeof((ctx)->block) - __md_i); \ + \ + f((ctx), (ctx)->block); \ + __md_i = 0; \ + } \ + memset((ctx)->block + __md_i, 0, \ + sizeof((ctx)->block) - (size) - __md_i); \ + \ + } while (0) + +#define WRITE_UINT64(p, i) \ +do { \ + (p)[0] = ((i) >> 56) & 0xff; \ + (p)[1] = ((i) >> 48) & 0xff; \ + (p)[2] = ((i) >> 40) & 0xff; \ + (p)[3] = ((i) >> 32) & 0xff; \ + (p)[4] = ((i) >> 24) & 0xff; \ + (p)[5] = ((i) >> 16) & 0xff; \ + (p)[6] = ((i) >> 8) & 0xff; \ + (p)[7] = (i) & 0xff; \ +} while(0) + +#define WRITE_UINT32(p, i) \ +do { \ + (p)[0] = ((i) >> 24) & 0xff; \ + (p)[1] = ((i) >> 16) & 0xff; \ + (p)[2] = ((i) >> 8) & 0xff; \ + (p)[3] = (i) & 0xff; \ +} while(0) + +/* Reads a 32-bit integer, in network, big-endian, byte order */ +#define READ_UINT32(p) \ +( (((uint32_t) (p)[0]) << 24) \ + | (((uint32_t) (p)[1]) << 16) \ + | (((uint32_t) (p)[2]) << 8) \ + | ((uint32_t) (p)[3])) + +#define ROTL32(n,x) (((x)<<(n)) | ((x)>>((-(n)&31)))) + + +// From nettle/write-be32.c + +void +_nettle_write_be32 (size_t length, uint8_t * dst, const uint32_t * src) +{ + size_t i; + size_t words; + unsigned leftover; + + words = length / 4; + leftover = length % 4; + + for (i = 0; i < words; i++, dst += 4) + WRITE_UINT32 (dst, src[i]); + + if (leftover) + { + uint32_t word; + unsigned j = leftover; + + word = src[i]; + + switch (leftover) + { + default: + abort (); + case 3: + dst[--j] = (word >> 8) & 0xff; + /* Fall through */ + case 2: + dst[--j] = (word >> 16) & 0xff; + /* Fall through */ + case 1: + dst[--j] = (word >> 24) & 0xff; + } + } +} + +// From nettle/sha2.h + +#define SHA256_DIGEST_SIZE 32 +#define SHA256_BLOCK_SIZE 64 + +/* Digest is kept internally as 8 32-bit words. */ +#define _SHA256_DIGEST_LENGTH 8 + +struct sha256_ctx +{ + uint32_t state[_SHA256_DIGEST_LENGTH]; /* State variables */ + uint64_t count; /* 64-bit block count */ + uint8_t block[SHA256_BLOCK_SIZE]; /* SHA256 data buffer */ + unsigned int index; /* index into buffer */ +}; + + +// From nettle/sha256-compress.c + +#define SHA256_DATA_LENGTH 16 + +#define DEBUG(i) + +#define Choice(x,y,z) ( (z) ^ ( (x) & ( (y) ^ (z) ) ) ) +#define Majority(x,y,z) ( ((x) & (y)) ^ ((z) & ((x) ^ (y))) ) + +#define S0(x) (ROTL32(30,(x)) ^ ROTL32(19,(x)) ^ ROTL32(10,(x))) +#define S1(x) (ROTL32(26,(x)) ^ ROTL32(21,(x)) ^ ROTL32(7,(x))) + +#define s0(x) (ROTL32(25,(x)) ^ ROTL32(14,(x)) ^ ((x) >> 3)) +#define s1(x) (ROTL32(15,(x)) ^ ROTL32(13,(x)) ^ ((x) >> 10)) + +#define EXPAND(W,i) \ +( W[(i) & 15 ] += (s1(W[((i)-2) & 15]) + W[((i)-7) & 15] + s0(W[((i)-15) & 15])) ) + +/* It's crucial that DATA is only used once, as that argument will + * have side effects. */ +#define ROUND(a,b,c,d,e,f,g,h,k,data) do { \ + h += S1(e) + Choice(e,f,g) + k + data; \ + d += h; \ + h += S0(a) + Majority(a,b,c); \ + } while (0) + +void +_nettle_sha256_compress (uint32_t * state, const uint8_t * input, + const uint32_t * k) +{ + uint32_t data[SHA256_DATA_LENGTH]; + uint32_t A, B, C, D, E, F, G, H; /* Local vars */ + unsigned i; + uint32_t *d; + + for (i = 0; i < SHA256_DATA_LENGTH; i++, input += 4) + { + data[i] = READ_UINT32 (input); + } + + /* Set up first buffer and local data buffer */ + A = state[0]; + B = state[1]; + C = state[2]; + D = state[3]; + E = state[4]; + F = state[5]; + G = state[6]; + H = state[7]; + + /* Heavy mangling */ + /* First 16 subrounds that act on the original data */ + + DEBUG (-1); + for (i = 0, d = data; i < 16; i += 8, k += 8, d += 8) + { + ROUND (A, B, C, D, E, F, G, H, k[0], d[0]); + DEBUG (i); + ROUND (H, A, B, C, D, E, F, G, k[1], d[1]); + DEBUG (i + 1); + ROUND (G, H, A, B, C, D, E, F, k[2], d[2]); + ROUND (F, G, H, A, B, C, D, E, k[3], d[3]); + ROUND (E, F, G, H, A, B, C, D, k[4], d[4]); + ROUND (D, E, F, G, H, A, B, C, k[5], d[5]); + ROUND (C, D, E, F, G, H, A, B, k[6], d[6]); + DEBUG (i + 6); + ROUND (B, C, D, E, F, G, H, A, k[7], d[7]); + DEBUG (i + 7); + } + + for (; i < 64; i += 16, k += 16) + { + ROUND (A, B, C, D, E, F, G, H, k[0], EXPAND (data, 0)); + DEBUG (i); + ROUND (H, A, B, C, D, E, F, G, k[1], EXPAND (data, 1)); + DEBUG (i + 1); + ROUND (G, H, A, B, C, D, E, F, k[2], EXPAND (data, 2)); + DEBUG (i + 2); + ROUND (F, G, H, A, B, C, D, E, k[3], EXPAND (data, 3)); + DEBUG (i + 3); + ROUND (E, F, G, H, A, B, C, D, k[4], EXPAND (data, 4)); + DEBUG (i + 4); + ROUND (D, E, F, G, H, A, B, C, k[5], EXPAND (data, 5)); + DEBUG (i + 5); + ROUND (C, D, E, F, G, H, A, B, k[6], EXPAND (data, 6)); + DEBUG (i + 6); + ROUND (B, C, D, E, F, G, H, A, k[7], EXPAND (data, 7)); + DEBUG (i + 7); + ROUND (A, B, C, D, E, F, G, H, k[8], EXPAND (data, 8)); + DEBUG (i + 8); + ROUND (H, A, B, C, D, E, F, G, k[9], EXPAND (data, 9)); + DEBUG (i + 9); + ROUND (G, H, A, B, C, D, E, F, k[10], EXPAND (data, 10)); + DEBUG (i + 10); + ROUND (F, G, H, A, B, C, D, E, k[11], EXPAND (data, 11)); + DEBUG (i + 11); + ROUND (E, F, G, H, A, B, C, D, k[12], EXPAND (data, 12)); + DEBUG (i + 12); + ROUND (D, E, F, G, H, A, B, C, k[13], EXPAND (data, 13)); + DEBUG (i + 13); + ROUND (C, D, E, F, G, H, A, B, k[14], EXPAND (data, 14)); + DEBUG (i + 14); + ROUND (B, C, D, E, F, G, H, A, k[15], EXPAND (data, 15)); + DEBUG (i + 15); + } + + /* Update state */ + state[0] += A; + state[1] += B; + state[2] += C; + state[3] += D; + state[4] += E; + state[5] += F; + state[6] += G; + state[7] += H; +} + + +// From nettle/sha256.c + +/* Generated by the shadata program. */ +static const uint32_t K[64] = { + 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, + 0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, + 0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL, + 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL, + 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, + 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, + 0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, + 0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL, + 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL, + 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, + 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, + 0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, + 0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL, + 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL, + 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, + 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL, +}; + +#define COMPRESS(ctx, data) (_nettle_sha256_compress((ctx)->state, (data), K)) + +/* Initialize the SHA values */ + +void +sha256_init (struct sha256_ctx *ctx) +{ + /* Initial values, also generated by the shadata program. */ + static const uint32_t H0[_SHA256_DIGEST_LENGTH] = { + 0x6a09e667UL, 0xbb67ae85UL, 0x3c6ef372UL, 0xa54ff53aUL, + 0x510e527fUL, 0x9b05688cUL, 0x1f83d9abUL, 0x5be0cd19UL, + }; + + memcpy (ctx->state, H0, sizeof (H0)); + + /* Initialize bit count */ + ctx->count = 0; + + /* Initialize buffer */ + ctx->index = 0; +} + +void +sha256_update (struct sha256_ctx *ctx, size_t length, const uint8_t * data) +{ + MD_UPDATE (ctx, length, data, COMPRESS, ctx->count++); +} + +static void +sha256_write_digest (struct sha256_ctx *ctx, size_t length, uint8_t * digest) +{ + uint64_t bit_count; + + assert_beebs (length <= SHA256_DIGEST_SIZE); + + MD_PAD (ctx, 8, COMPRESS); + + /* There are 512 = 2^9 bits in one block */ + bit_count = (ctx->count << 9) | (ctx->index << 3); + + /* This is slightly inefficient, as the numbers are converted to + big-endian format, and will be converted back by the compression + function. It's probably not worth the effort to fix this. */ + WRITE_UINT64 (ctx->block + (SHA256_BLOCK_SIZE - 8), bit_count); + COMPRESS (ctx, ctx->block); + + _nettle_write_be32 (length, digest, ctx->state); +} + +void +sha256_digest (struct sha256_ctx *ctx, size_t length, uint8_t * digest) +{ + sha256_write_digest (ctx, length, digest); + sha256_init (ctx); +} + + +// From nettle/nettle-meta.h + +struct nettle_hash +{ + const char *name; + + /* Size of the context struct */ + unsigned context_size; + + /* Size of digests */ + unsigned digest_size; + + /* Internal block size */ + unsigned block_size; + + nettle_hash_init_func *init; + nettle_hash_update_func *update; + nettle_hash_digest_func *digest; +}; + +#define _NETTLE_HASH(name, NAME) { \ + #name, \ + sizeof(struct name##_ctx), \ + NAME##_DIGEST_SIZE, \ + NAME##_BLOCK_SIZE, \ + (nettle_hash_init_func *) name##_init, \ + (nettle_hash_update_func *) name##_update, \ + (nettle_hash_digest_func *) name##_digest \ +} + + +// From nettle/sha256-meta.c + +const struct nettle_hash nettle_sha256 = _NETTLE_HASH (sha256, SHA256); + + +// BEEBS benchmark code + +unsigned char msg[56] = + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"; + +unsigned char hash[32] = + { 0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8, 0xe5, 0xc0, 0x26, 0x93, + 0x0c, 0x3e, 0x60, 0x39, 0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff, 0x21, 0x67, + 0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1 +}; + +uint8_t buffer[SHA256_DIGEST_SIZE]; + +int +verify_benchmark (int res __attribute ((unused))) +{ + bool correct = true; + + for (size_t i = 0; i < _SHA256_DIGEST_LENGTH; i++) + { + if (hash[i] != buffer[i]) + correct = false; + } + + return correct; +} + +void +initialise_benchmark (void) +{ +} + + +static int benchmark_body (int rpt); + +void +warm_caches (int heat) +{ + int res = benchmark_body (heat); + + return; +} + + +int +benchmark (void) +{ + return benchmark_body (LOCAL_SCALE_FACTOR * CPU_MHZ); +} + + +static int __attribute__ ((noinline)) +benchmark_body (int rpt) +{ + int i; + + for (i = 0; i < rpt; i++) + { + memset (buffer, 0, sizeof (buffer)); + struct sha256_ctx ctx; + nettle_sha256.init (&ctx); + nettle_sha256.update (&ctx, sizeof (msg), msg); + nettle_sha256.digest (&ctx, nettle_sha256.digest_size, buffer); + } + + return 0; +} + + +/* + Local Variables: + mode: C + c-file-style: "gnu" + End: +*/ diff --git a/benchies/embench/benchemarks/nsichneu/libnsichneu.c b/benchies/embench/benchemarks/nsichneu/libnsichneu.c new file mode 100644 index 0000000000..78b88a2662 --- /dev/null +++ b/benchies/embench/benchemarks/nsichneu/libnsichneu.c @@ -0,0 +1,4594 @@ +/* BEEBS nsichneu benchmark + + This version, copyright (C) 2014-2019 Embecosm Limited and University of + Bristol + + Contributor James Pallister + Contributor Jeremy Bennett + + This file is part of Embench and was formerly part of the Bristol/Embecosm + Embedded Benchmark Suite. + + SPDX-License-Identifier: GPL-3.0-or-later */ + +/*************************************************************************** +* +* Copyright (c) 1998/1999, C-LAB, Paderborn +* +* File generated by Sea2CHaRy +* +* This file containes a CHaRy description generated from the +* file: NSicherNeu.sea +* The name of the Pr/T-Net was: NSicherNeu +* +* Modified and maintained by +* Friedhelm Stappert +* C-LAB, Paderborn, Germany +* fst@c-lab.de +* +* Modifications: +* o made the local variables global and volatile, +* so the compiler won't optimise everything away. +* + +***************************************************************************/ +// #define DO_TRACING + +#include "../../src/support.h" + +/* This scale factor will be changed to equalise the runtime of the + benchmarks. */ +#define LOCAL_SCALE_FACTOR 1231 + +#ifdef DO_TRACING // ON PC + +#include +#define TRACE(x) trace((x)) +#undef TEST /* finished testing! */ +void +trace (char *s) +{ + printf ("%s\n", s); +} + +#else // ON TARGET + +#define TRACE(x) +#undef TEST + +#endif + +volatile int P1_is_marked = 3; +volatile long P1_marking_member_0[3]; +volatile int P2_is_marked = 5; +volatile long P2_marking_member_0[5]; +volatile int P3_is_marked = 0; +volatile long P3_marking_member_0[6]; + +void +initialise_benchmark (void) +{ +} + + +static int benchmark_body (int rpt); + +void +warm_caches (int heat) +{ + int res = benchmark_body (heat); + + return; +} + + +int +benchmark (void) +{ + return benchmark_body (LOCAL_SCALE_FACTOR * CPU_MHZ); +} + + +/**void NSicherNeu()**/ +static int __attribute__ ((noinline)) +benchmark_body (int rpt) +{ + int j; + + for (j = 0; j < rpt; j++) + { + P1_is_marked = 3; + P2_is_marked = 5; + P3_is_marked = 0; + + /* Permutation for Place P1 : 0, 1, 2 */ + /* Transition T1 */ + if ((P1_is_marked >= 3) && + (P3_is_marked + 3 <= 6) && + (P1_marking_member_0[1] == P1_marking_member_0[2])) + { + + long x; + long y; + long z; + + x = P1_marking_member_0[0]; + y = P1_marking_member_0[1]; + + /* Transition condition */ + if (x < y) + { + + /* demarking of input places */ + P1_is_marked -= 3; + + /* preaction */ + z = x - y; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = x; + P3_marking_member_0[P3_is_marked + 1] = y; + P3_marking_member_0[P3_is_marked + 2] = z; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + /* Permutation for Place P1 : 0, 2, 1 */ + /* Transition T1 */ + if ((P1_is_marked >= 3) && + (P3_is_marked + 3 <= 6) && + (P1_marking_member_0[2] == P1_marking_member_0[1])) + { + + long x; + long y; + long z; + + x = P1_marking_member_0[0]; + y = P1_marking_member_0[2]; + + /* Transition condition */ + if ((x < y)) + { + + + /* demarking of input places */ + P1_is_marked -= 3; + + /* preaction */ + z = x - y; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = x; + P3_marking_member_0[P3_is_marked + 1] = y; + P3_marking_member_0[P3_is_marked + 2] = z; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + /* Permutation for Place P1 : 1, 0, 2 */ + /* Transition T1 */ + if ((P1_is_marked >= 3) && + (P3_is_marked + 3 <= 6) && + (P1_marking_member_0[0] == P1_marking_member_0[2])) + { + + long x; + long y; + long z; + + x = P1_marking_member_0[1]; + y = P1_marking_member_0[0]; + + /* Transition condition */ + if (x < y) + { + + + /* demarking of input places */ + P1_is_marked -= 3; + + /* preaction */ + z = x - y; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = x; + P3_marking_member_0[P3_is_marked + 1] = y; + P3_marking_member_0[P3_is_marked + 2] = z; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + /* Permutation for Place P1 : 1, 2, 0 */ + /* Transition T1 */ + if ((P1_is_marked >= 3) && + (P3_is_marked + 3 <= 6) && + (P1_marking_member_0[2] == P1_marking_member_0[0])) + { + + long x; + long y; + long z; + + x = P1_marking_member_0[1]; + y = P1_marking_member_0[2]; + + /* Transition condition */ + if ((x < y)) + { + + + /* demarking of input places */ + P1_is_marked -= 3; + + /* preaction */ + z = x - y; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = x; + P3_marking_member_0[P3_is_marked + 1] = y; + P3_marking_member_0[P3_is_marked + 2] = z; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + /* Permutation for Place P1 : 2, 0, 1 */ + /* Transition T1 */ + if ((P1_is_marked >= 3) && + (P3_is_marked + 3 <= 6) && + (P1_marking_member_0[0] == P1_marking_member_0[1])) + { + long x; + long y; + long z; + + x = P1_marking_member_0[2]; + y = P1_marking_member_0[0]; + + /* Transition condition */ + if ((x < y)) + { + + /* demarking of input places */ + P1_is_marked -= 3; + + /* preaction */ + z = x - y; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = x; + P3_marking_member_0[P3_is_marked + 1] = y; + P3_marking_member_0[P3_is_marked + 2] = z; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + /* Permutation for Place P1 : 2, 1, 0 */ + /* Transition T1 */ + if ((P1_is_marked >= 3) && + (P3_is_marked + 3 <= 6) && + (P1_marking_member_0[1] == P1_marking_member_0[0])) + { + long x; + long y; + long z; + + x = P1_marking_member_0[2]; + y = P1_marking_member_0[1]; + + /* Transition condition */ + if ((x < y)) + { + + /* demarking of input places */ + P1_is_marked -= 3; + + /* preaction */ + z = x - y; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = x; + P3_marking_member_0[P3_is_marked + 1] = y; + P3_marking_member_0[P3_is_marked + 2] = z; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + /* Permutation for Place P2 : 0, 1, 2, 3 */ + /* Transition T2 */ + if ((P2_is_marked >= 4) && + (((P3_is_marked + 3) <= 6)) && + (((P2_marking_member_0[1] == P2_marking_member_0[2])) && + ((P2_marking_member_0[1] == P2_marking_member_0[3])))) + { + long a; + long b; + long c; + + a = P2_marking_member_0[0]; + b = P2_marking_member_0[1]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + /* Permutation for Place P2 : 0, 1, 3, 2 */ + /* Transition T2 */ + if ((P2_is_marked >= 4) && + (((P3_is_marked + 3) <= 6)) && + ((P2_marking_member_0[1] == P2_marking_member_0[3]) && + (P2_marking_member_0[1] == P2_marking_member_0[2]))) + { + long a; + long b; + long c; + + a = P2_marking_member_0[0]; + b = P2_marking_member_0[1]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + /* Permutation for Place P2 : 0, 2, 1, 3 */ + /* Transition T2 */ + if ((P2_is_marked >= 4) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[2] == P2_marking_member_0[1]) && + (P2_marking_member_0[2] == P2_marking_member_0[3]))) + { + long a; + long b; + long c; + + a = P2_marking_member_0[0]; + b = P2_marking_member_0[2]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + /* Permutation for Place P2 : 0, 2, 3, 1 */ + /* Transition T2 */ + if ((P2_is_marked >= 4) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[2] == P2_marking_member_0[3]) && + (P2_marking_member_0[2] == P2_marking_member_0[1]))) + { + long a; + long b; + long c; + + a = P2_marking_member_0[0]; + b = P2_marking_member_0[2]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + /* Permutation for Place P2 : 0, 3, 1, 2 */ + /* Transition T2 */ + if ((P2_is_marked >= 4) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[3] == P2_marking_member_0[1]) && + (P2_marking_member_0[3] == P2_marking_member_0[2]))) + { + long a; + long b; + long c; + + a = P2_marking_member_0[0]; + b = P2_marking_member_0[3]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + /* Permutation for Place P2 : 0, 3, 2, 1 */ + /* Transition T2 */ + if ((P2_is_marked >= 4) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[3] == P2_marking_member_0[2]) && + (P2_marking_member_0[3] == P2_marking_member_0[1]))) + { + long a; + long b; + long c; + + a = P2_marking_member_0[0]; + b = P2_marking_member_0[3]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + /* Permutation for Place P2 : 1, 0, 2, 3 */ + /* Transition T2 */ + if ((P2_is_marked >= 4) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[0] == P2_marking_member_0[2]) && + (P2_marking_member_0[0] == P2_marking_member_0[3]))) + { + long a; + long b; + long c; + + a = P2_marking_member_0[1]; + b = P2_marking_member_0[0]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + /* Permutation for Place P2 : 1, 0, 3, 2 */ + /* Transition T2 */ + if ((P2_is_marked >= 4) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[0] == P2_marking_member_0[3]) && + (P2_marking_member_0[0] == P2_marking_member_0[2]))) + { + long a; + long b; + long c; + + a = P2_marking_member_0[1]; + b = P2_marking_member_0[0]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + /* Permutation for Place P2 : 1, 2, 0, 3 */ + /* Transition T2 */ + if ((P2_is_marked >= 4) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[2] == P2_marking_member_0[0]) && + (P2_marking_member_0[2] == P2_marking_member_0[3]))) + { + long a; + long b; + long c; + + a = P2_marking_member_0[1]; + b = P2_marking_member_0[2]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + /* Permutation for Place P2 : 1, 2, 3, 0 */ + /* Transition T2 */ + if ((P2_is_marked >= 4) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[2] == P2_marking_member_0[3]) && + (P2_marking_member_0[2] == P2_marking_member_0[0]))) + { + long a; + long b; + long c; + + a = P2_marking_member_0[1]; + b = P2_marking_member_0[2]; + + /* Transition condition */ + if ((b > a)) + { + /* demarking of input places */ + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + /* Permutation for Place P2 : 1, 3, 0, 2 */ + /* Transition T2 */ + if ((P2_is_marked >= 4) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[3] == P2_marking_member_0[0]) && + (P2_marking_member_0[3] == P2_marking_member_0[2]))) + { + long a; + long b; + long c; + + a = P2_marking_member_0[1]; + b = P2_marking_member_0[3]; + + /* Transition condition */ + if ((b > a)) + { + /* demarking of input places */ + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 1, 3, 2, 0 */ + /* Transition T2 */ + if ((P2_is_marked >= 4) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[3] == P2_marking_member_0[2]) && + (P2_marking_member_0[3] == P2_marking_member_0[0]))) + { + long a; + long b; + long c; + + a = P2_marking_member_0[1]; + b = P2_marking_member_0[3]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 2, 0, 1, 3 */ + /* Transition T2 */ + if ((P2_is_marked >= 4) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[0] == P2_marking_member_0[1]) && + (P2_marking_member_0[0] == P2_marking_member_0[3]))) + { + long a; + long b; + long c; + + a = P2_marking_member_0[2]; + b = P2_marking_member_0[0]; + + /* Transition condition */ + if ((b > a)) + { + /* demarking of input places */ + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + /* Permutation for Place P2 : 2, 0, 3, 1 */ + /* Transition T2 */ + if ((P2_is_marked >= 4) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[0] == P2_marking_member_0[3]) && + (P2_marking_member_0[0] == P2_marking_member_0[1]))) + { + long a; + long b; + long c; + + a = P2_marking_member_0[2]; + b = P2_marking_member_0[0]; + + /* Transition condition */ + if ((b > a)) + { + /* demarking of input places */ + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + /* Permutation for Place P2 : 2, 1, 0, 3 */ + /* Transition T2 */ + if ((P2_is_marked >= 4) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[1] == P2_marking_member_0[0]) && + (P2_marking_member_0[1] == P2_marking_member_0[3]))) + { + long a; + long b; + long c; + + a = P2_marking_member_0[2]; + b = P2_marking_member_0[1]; + + /* Transition condition */ + if ((b > a)) + { + /* demarking of input places */ + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + /* Permutation for Place P2 : 2, 1, 3, 0 */ + /* Transition T2 */ + if ((P2_is_marked >= 4) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[1] == P2_marking_member_0[3]) && + (P2_marking_member_0[1] == P2_marking_member_0[0]))) + { + long a; + long b; + long c; + + a = P2_marking_member_0[2]; + b = P2_marking_member_0[1]; + + /* Transition condition */ + if ((b > a)) + { + /* demarking of input places */ + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + /* Permutation for Place P2 : 2, 3, 0, 1 */ + /* Transition T2 */ + if ((P2_is_marked >= 4) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[3] == P2_marking_member_0[0]) && + (P2_marking_member_0[3] == P2_marking_member_0[1]))) + { + long a; + long b; + long c; + + a = P2_marking_member_0[2]; + b = P2_marking_member_0[3]; + + /* Transition condition */ + if ((b > a)) + { + /* demarking of input places */ + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + /* Permutation for Place P2 : 2, 3, 1, 0 */ + /* Transition T2 */ + if ((P2_is_marked >= 4) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[3] == P2_marking_member_0[1]) && + (P2_marking_member_0[3] == P2_marking_member_0[0]))) + { + long a; + long b; + long c; + + a = P2_marking_member_0[2]; + b = P2_marking_member_0[3]; + + /* Transition condition */ + if ((b > a)) + { + /* demarking of input places */ + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + /* Permutation for Place P2 : 3, 0, 1, 2 */ + /* Transition T2 */ + if ((P2_is_marked >= 4) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[0] == P2_marking_member_0[1]) && + (P2_marking_member_0[0] == P2_marking_member_0[2]))) + { + long a; + long b; + long c; + + a = P2_marking_member_0[3]; + b = P2_marking_member_0[0]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 3, 0, 2, 1 */ + /* Transition T2 */ + if ((P2_is_marked >= 4) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[0] == P2_marking_member_0[2]) && + (P2_marking_member_0[0] == P2_marking_member_0[1]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[3]; + b = P2_marking_member_0[0]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 3, 1, 0, 2 */ + /* Transition T2 */ + if ((P2_is_marked >= 4) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[1] == P2_marking_member_0[0]) && + (P2_marking_member_0[1] == P2_marking_member_0[2]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[3]; + b = P2_marking_member_0[1]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 3, 1, 2, 0 */ + /* Transition T2 */ + if ((P2_is_marked >= 4) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[1] == P2_marking_member_0[2]) && + (P2_marking_member_0[1] == P2_marking_member_0[0]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[3]; + b = P2_marking_member_0[1]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 3, 2, 0, 1 */ + /* Transition T2 */ + if ((P2_is_marked >= 4) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[2] == P2_marking_member_0[0]) && + (P2_marking_member_0[2] == P2_marking_member_0[1]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[3]; + b = P2_marking_member_0[2]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 3, 2, 1, 0 */ + /* Transition T2 */ + if ((P2_is_marked >= 4) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[2] == P2_marking_member_0[1]) && + (P2_marking_member_0[2] == P2_marking_member_0[0]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[3]; + b = P2_marking_member_0[2]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 0, 1, 2, 4 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[1] == P2_marking_member_0[2]) && + (P2_marking_member_0[1] == P2_marking_member_0[4]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[0]; + b = P2_marking_member_0[1]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_marking_member_0[0] = P2_marking_member_0[3]; + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 0, 1, 3, 4 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[1] == P2_marking_member_0[3]) && + (P2_marking_member_0[1] == P2_marking_member_0[4]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[0]; + b = P2_marking_member_0[1]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_marking_member_0[0] = P2_marking_member_0[2]; + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 0, 1, 4, 2 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[1] == P2_marking_member_0[4]) && + (P2_marking_member_0[1] == P2_marking_member_0[2]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[0]; + b = P2_marking_member_0[1]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_marking_member_0[0] = P2_marking_member_0[3]; + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 0, 1, 4, 3 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[1] == P2_marking_member_0[4]) && + (P2_marking_member_0[1] == P2_marking_member_0[3]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[0]; + b = P2_marking_member_0[1]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_marking_member_0[0] = P2_marking_member_0[2]; + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 0, 2, 1, 4 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[2] == P2_marking_member_0[1]) && + (P2_marking_member_0[2] == P2_marking_member_0[4]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[0]; + b = P2_marking_member_0[2]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_marking_member_0[0] = P2_marking_member_0[3]; + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 0, 2, 3, 4 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[2] == P2_marking_member_0[3]) && + (P2_marking_member_0[2] == P2_marking_member_0[4]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[0]; + b = P2_marking_member_0[2]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_marking_member_0[0] = P2_marking_member_0[1]; + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 0, 2, 4, 1 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[2] == P2_marking_member_0[4]) && + (P2_marking_member_0[2] == P2_marking_member_0[1]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[0]; + b = P2_marking_member_0[2]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_marking_member_0[0] = P2_marking_member_0[3]; + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 0, 2, 4, 3 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[2] == P2_marking_member_0[4]) && + (P2_marking_member_0[2] == P2_marking_member_0[3]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[0]; + b = P2_marking_member_0[2]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_marking_member_0[0] = P2_marking_member_0[1]; + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 0, 3, 1, 4 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[3] == P2_marking_member_0[1]) && + (P2_marking_member_0[3] == P2_marking_member_0[4]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[0]; + b = P2_marking_member_0[3]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_marking_member_0[0] = P2_marking_member_0[2]; + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 0, 3, 2, 4 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[3] == P2_marking_member_0[2]) && + (P2_marking_member_0[3] == P2_marking_member_0[4]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[0]; + b = P2_marking_member_0[3]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_marking_member_0[0] = P2_marking_member_0[1]; + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 0, 3, 4, 1 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[3] == P2_marking_member_0[4]) && + (P2_marking_member_0[3] == P2_marking_member_0[1]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[0]; + b = P2_marking_member_0[3]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_marking_member_0[0] = P2_marking_member_0[2]; + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 0, 3, 4, 2 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[3] == P2_marking_member_0[4]) && + (P2_marking_member_0[3] == P2_marking_member_0[2]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[0]; + b = P2_marking_member_0[3]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_marking_member_0[0] = P2_marking_member_0[1]; + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 0, 4, 1, 2 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[4] == P2_marking_member_0[1]) && + (P2_marking_member_0[4] == P2_marking_member_0[2]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[0]; + b = P2_marking_member_0[4]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_marking_member_0[0] = P2_marking_member_0[3]; + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 0, 4, 1, 3 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[4] == P2_marking_member_0[1]) && + (P2_marking_member_0[4] == P2_marking_member_0[3]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[0]; + b = P2_marking_member_0[4]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_marking_member_0[0] = P2_marking_member_0[2]; + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 0, 4, 2, 1 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[4] == P2_marking_member_0[2]) && + (P2_marking_member_0[4] == P2_marking_member_0[1]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[0]; + b = P2_marking_member_0[4]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_marking_member_0[0] = P2_marking_member_0[3]; + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 0, 4, 2, 3 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[4] == P2_marking_member_0[2]) && + (P2_marking_member_0[4] == P2_marking_member_0[3]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[0]; + b = P2_marking_member_0[4]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_marking_member_0[0] = P2_marking_member_0[1]; + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 0, 4, 3, 1 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[4] == P2_marking_member_0[3]) && + (P2_marking_member_0[4] == P2_marking_member_0[1]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[0]; + b = P2_marking_member_0[4]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_marking_member_0[0] = P2_marking_member_0[2]; + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 0, 4, 3, 2 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[4] == P2_marking_member_0[3]) && + (P2_marking_member_0[4] == P2_marking_member_0[2]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[0]; + b = P2_marking_member_0[4]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_marking_member_0[0] = P2_marking_member_0[1]; + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 1, 0, 2, 4 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[0] == P2_marking_member_0[2]) && + (P2_marking_member_0[0] == P2_marking_member_0[4]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[1]; + b = P2_marking_member_0[0]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_marking_member_0[0] = P2_marking_member_0[3]; + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 1, 0, 3, 4 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[0] == P2_marking_member_0[3]) && + (P2_marking_member_0[0] == P2_marking_member_0[4]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[1]; + b = P2_marking_member_0[0]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_marking_member_0[0] = P2_marking_member_0[2]; + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 1, 0, 4, 2 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[0] == P2_marking_member_0[4]) && + (P2_marking_member_0[0] == P2_marking_member_0[2]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[1]; + b = P2_marking_member_0[0]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_marking_member_0[0] = P2_marking_member_0[3]; + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 1, 0, 4, 3 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[0] == P2_marking_member_0[4]) && + (P2_marking_member_0[0] == P2_marking_member_0[3]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[1]; + b = P2_marking_member_0[0]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_marking_member_0[0] = P2_marking_member_0[2]; + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 1, 2, 0, 4 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[2] == P2_marking_member_0[0]) && + (P2_marking_member_0[2] == P2_marking_member_0[4]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[1]; + b = P2_marking_member_0[2]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_marking_member_0[0] = P2_marking_member_0[3]; + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 1, 2, 3, 4 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[2] == P2_marking_member_0[3]) && + (P2_marking_member_0[2] == P2_marking_member_0[4]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[1]; + b = P2_marking_member_0[2]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 1, 2, 4, 0 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[2] == P2_marking_member_0[4]) && + (P2_marking_member_0[2] == P2_marking_member_0[0]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[1]; + b = P2_marking_member_0[2]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_marking_member_0[0] = P2_marking_member_0[3]; + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 1, 2, 4, 3 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[2] == P2_marking_member_0[4]) && + (P2_marking_member_0[2] == P2_marking_member_0[3]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[1]; + b = P2_marking_member_0[2]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 1, 3, 0, 4 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[3] == P2_marking_member_0[0]) && + (P2_marking_member_0[3] == P2_marking_member_0[4]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[1]; + b = P2_marking_member_0[3]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_marking_member_0[0] = P2_marking_member_0[2]; + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 1, 3, 2, 4 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[3] == P2_marking_member_0[2]) && + (P2_marking_member_0[3] == P2_marking_member_0[4]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[1]; + b = P2_marking_member_0[3]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 1, 3, 4, 0 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[3] == P2_marking_member_0[4]) && + (P2_marking_member_0[3] == P2_marking_member_0[0]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[1]; + b = P2_marking_member_0[3]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_marking_member_0[0] = P2_marking_member_0[2]; + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 1, 3, 4, 2 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[3] == P2_marking_member_0[4]) && + (P2_marking_member_0[3] == P2_marking_member_0[2]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[1]; + b = P2_marking_member_0[3]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 1, 4, 0, 2 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[4] == P2_marking_member_0[0]) && + (P2_marking_member_0[4] == P2_marking_member_0[2]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[1]; + b = P2_marking_member_0[4]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_marking_member_0[0] = P2_marking_member_0[3]; + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 1, 4, 0, 3 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[4] == P2_marking_member_0[0]) && + (P2_marking_member_0[4] == P2_marking_member_0[3]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[1]; + b = P2_marking_member_0[4]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_marking_member_0[0] = P2_marking_member_0[2]; + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 1, 4, 2, 0 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[4] == P2_marking_member_0[2]) && + (P2_marking_member_0[4] == P2_marking_member_0[0]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[1]; + b = P2_marking_member_0[4]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_marking_member_0[0] = P2_marking_member_0[3]; + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 1, 4, 2, 3 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[4] == P2_marking_member_0[2]) && + (P2_marking_member_0[4] == P2_marking_member_0[3]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[1]; + b = P2_marking_member_0[4]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 1, 4, 3, 0 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[4] == P2_marking_member_0[3]) && + (P2_marking_member_0[4] == P2_marking_member_0[0]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[1]; + b = P2_marking_member_0[4]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_marking_member_0[0] = P2_marking_member_0[2]; + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 1, 4, 3, 2 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[4] == P2_marking_member_0[3]) && + (P2_marking_member_0[4] == P2_marking_member_0[2]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[1]; + b = P2_marking_member_0[4]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 2, 0, 1, 4 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[0] == P2_marking_member_0[1]) && + (P2_marking_member_0[0] == P2_marking_member_0[4]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[2]; + b = P2_marking_member_0[0]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_marking_member_0[0] = P2_marking_member_0[3]; + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 2, 0, 3, 4 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[0] == P2_marking_member_0[3]) && + (P2_marking_member_0[0] == P2_marking_member_0[4]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[2]; + b = P2_marking_member_0[0]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_marking_member_0[0] = P2_marking_member_0[1]; + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 2, 0, 4, 1 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[0] == P2_marking_member_0[4]) && + (P2_marking_member_0[0] == P2_marking_member_0[1]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[2]; + b = P2_marking_member_0[0]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_marking_member_0[0] = P2_marking_member_0[3]; + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 2, 0, 4, 3 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[0] == P2_marking_member_0[4]) && + (P2_marking_member_0[0] == P2_marking_member_0[3]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[2]; + b = P2_marking_member_0[0]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_marking_member_0[0] = P2_marking_member_0[1]; + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 2, 1, 0, 4 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[1] == P2_marking_member_0[0]) && + (P2_marking_member_0[1] == P2_marking_member_0[4]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[2]; + b = P2_marking_member_0[1]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_marking_member_0[0] = P2_marking_member_0[3]; + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 2, 1, 3, 4 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[1] == P2_marking_member_0[3]) && + (P2_marking_member_0[1] == P2_marking_member_0[4]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[2]; + b = P2_marking_member_0[1]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 2, 1, 4, 0 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[1] == P2_marking_member_0[4]) && + (P2_marking_member_0[1] == P2_marking_member_0[0]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[2]; + b = P2_marking_member_0[1]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_marking_member_0[0] = P2_marking_member_0[3]; + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 2, 1, 4, 3 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[1] == P2_marking_member_0[4]) && + (P2_marking_member_0[1] == P2_marking_member_0[3]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[2]; + b = P2_marking_member_0[1]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 2, 3, 0, 4 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[3] == P2_marking_member_0[0]) && + (P2_marking_member_0[3] == P2_marking_member_0[4]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[2]; + b = P2_marking_member_0[3]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_marking_member_0[0] = P2_marking_member_0[1]; + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 2, 3, 1, 4 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[3] == P2_marking_member_0[1]) && + (P2_marking_member_0[3] == P2_marking_member_0[4]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[2]; + b = P2_marking_member_0[3]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 2, 3, 4, 0 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[3] == P2_marking_member_0[4]) && + (P2_marking_member_0[3] == P2_marking_member_0[0]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[2]; + b = P2_marking_member_0[3]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_marking_member_0[0] = P2_marking_member_0[1]; + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 2, 3, 4, 1 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[3] == P2_marking_member_0[4]) && + (P2_marking_member_0[3] == P2_marking_member_0[1]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[2]; + b = P2_marking_member_0[3]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 2, 4, 0, 1 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[4] == P2_marking_member_0[0]) && + (P2_marking_member_0[4] == P2_marking_member_0[1]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[2]; + b = P2_marking_member_0[4]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_marking_member_0[0] = P2_marking_member_0[3]; + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 2, 4, 0, 3 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[4] == P2_marking_member_0[0]) && + (P2_marking_member_0[4] == P2_marking_member_0[3]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[2]; + b = P2_marking_member_0[4]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_marking_member_0[0] = P2_marking_member_0[1]; + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 2, 4, 1, 0 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[4] == P2_marking_member_0[1]) && + (P2_marking_member_0[4] == P2_marking_member_0[0]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[2]; + b = P2_marking_member_0[4]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_marking_member_0[0] = P2_marking_member_0[3]; + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 2, 4, 1, 3 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[4] == P2_marking_member_0[1]) && + (P2_marking_member_0[4] == P2_marking_member_0[3]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[2]; + b = P2_marking_member_0[4]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 2, 4, 3, 0 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[4] == P2_marking_member_0[3]) && + (P2_marking_member_0[4] == P2_marking_member_0[0]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[2]; + b = P2_marking_member_0[4]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_marking_member_0[0] = P2_marking_member_0[1]; + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 2, 4, 3, 1 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[4] == P2_marking_member_0[3]) && + (P2_marking_member_0[4] == P2_marking_member_0[1]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[2]; + b = P2_marking_member_0[4]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 3, 0, 1, 4 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[0] == P2_marking_member_0[1]) && + (P2_marking_member_0[0] == P2_marking_member_0[4]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[3]; + b = P2_marking_member_0[0]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_marking_member_0[0] = P2_marking_member_0[2]; + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 3, 0, 2, 4 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[0] == P2_marking_member_0[2]) && + (P2_marking_member_0[0] == P2_marking_member_0[4]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[3]; + b = P2_marking_member_0[0]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_marking_member_0[0] = P2_marking_member_0[1]; + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 3, 0, 4, 1 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[0] == P2_marking_member_0[4]) && + (P2_marking_member_0[0] == P2_marking_member_0[1]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[3]; + b = P2_marking_member_0[0]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_marking_member_0[0] = P2_marking_member_0[2]; + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 3, 0, 4, 2 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[0] == P2_marking_member_0[4]) && + (P2_marking_member_0[0] == P2_marking_member_0[2]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[3]; + b = P2_marking_member_0[0]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_marking_member_0[0] = P2_marking_member_0[1]; + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 3, 1, 0, 4 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[1] == P2_marking_member_0[0]) && + (P2_marking_member_0[1] == P2_marking_member_0[4]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[3]; + b = P2_marking_member_0[1]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_marking_member_0[0] = P2_marking_member_0[2]; + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 3, 1, 2, 4 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[1] == P2_marking_member_0[2]) && + (P2_marking_member_0[1] == P2_marking_member_0[4]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[3]; + b = P2_marking_member_0[1]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 3, 1, 4, 0 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[1] == P2_marking_member_0[4]) && + (P2_marking_member_0[1] == P2_marking_member_0[0]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[3]; + b = P2_marking_member_0[1]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_marking_member_0[0] = P2_marking_member_0[2]; + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 3, 1, 4, 2 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[1] == P2_marking_member_0[4]) && + (P2_marking_member_0[1] == P2_marking_member_0[2]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[3]; + b = P2_marking_member_0[1]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 3, 2, 0, 4 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[2] == P2_marking_member_0[0]) && + (P2_marking_member_0[2] == P2_marking_member_0[4]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[3]; + b = P2_marking_member_0[2]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_marking_member_0[0] = P2_marking_member_0[1]; + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 3, 2, 1, 4 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[2] == P2_marking_member_0[1]) && + (P2_marking_member_0[2] == P2_marking_member_0[4]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[3]; + b = P2_marking_member_0[2]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 3, 2, 4, 0 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[2] == P2_marking_member_0[4]) && + (P2_marking_member_0[2] == P2_marking_member_0[0]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[3]; + b = P2_marking_member_0[2]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_marking_member_0[0] = P2_marking_member_0[1]; + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 3, 2, 4, 1 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[2] == P2_marking_member_0[4]) && + (P2_marking_member_0[2] == P2_marking_member_0[1]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[3]; + b = P2_marking_member_0[2]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 3, 4, 0, 1 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[4] == P2_marking_member_0[0]) && + (P2_marking_member_0[4] == P2_marking_member_0[1]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[3]; + b = P2_marking_member_0[4]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_marking_member_0[0] = P2_marking_member_0[2]; + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 3, 4, 0, 2 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[4] == P2_marking_member_0[0]) && + (P2_marking_member_0[4] == P2_marking_member_0[2]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[3]; + b = P2_marking_member_0[4]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_marking_member_0[0] = P2_marking_member_0[1]; + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 3, 4, 1, 0 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[4] == P2_marking_member_0[1]) && + (P2_marking_member_0[4] == P2_marking_member_0[0]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[3]; + b = P2_marking_member_0[4]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_marking_member_0[0] = P2_marking_member_0[2]; + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 3, 4, 1, 2 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[4] == P2_marking_member_0[1]) && + (P2_marking_member_0[4] == P2_marking_member_0[2]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[3]; + b = P2_marking_member_0[4]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 3, 4, 2, 0 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[4] == P2_marking_member_0[2]) && + (P2_marking_member_0[4] == P2_marking_member_0[0]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[3]; + b = P2_marking_member_0[4]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_marking_member_0[0] = P2_marking_member_0[1]; + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 3, 4, 2, 1 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[4] == P2_marking_member_0[2]) && + (P2_marking_member_0[4] == P2_marking_member_0[1]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[3]; + b = P2_marking_member_0[4]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 4, 0, 1, 2 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[0] == P2_marking_member_0[1]) && + (P2_marking_member_0[0] == P2_marking_member_0[2]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[4]; + b = P2_marking_member_0[0]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_marking_member_0[0] = P2_marking_member_0[3]; + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 4, 0, 1, 3 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[0] == P2_marking_member_0[1]) && + (P2_marking_member_0[0] == P2_marking_member_0[3]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[4]; + b = P2_marking_member_0[0]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_marking_member_0[0] = P2_marking_member_0[2]; + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 4, 0, 2, 1 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[0] == P2_marking_member_0[2]) && + (P2_marking_member_0[0] == P2_marking_member_0[1]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[4]; + b = P2_marking_member_0[0]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_marking_member_0[0] = P2_marking_member_0[3]; + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 4, 0, 2, 3 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[0] == P2_marking_member_0[2]) && + (P2_marking_member_0[0] == P2_marking_member_0[3]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[4]; + b = P2_marking_member_0[0]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_marking_member_0[0] = P2_marking_member_0[1]; + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 4, 0, 3, 1 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[0] == P2_marking_member_0[3]) && + (P2_marking_member_0[0] == P2_marking_member_0[1]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[4]; + b = P2_marking_member_0[0]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_marking_member_0[0] = P2_marking_member_0[2]; + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 4, 0, 3, 2 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[0] == P2_marking_member_0[3]) && + (P2_marking_member_0[0] == P2_marking_member_0[2]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[4]; + b = P2_marking_member_0[0]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_marking_member_0[0] = P2_marking_member_0[1]; + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 4, 1, 0, 2 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[1] == P2_marking_member_0[0]) && + (P2_marking_member_0[1] == P2_marking_member_0[2]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[4]; + b = P2_marking_member_0[1]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_marking_member_0[0] = P2_marking_member_0[3]; + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 4, 1, 0, 3 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[1] == P2_marking_member_0[0]) && + (P2_marking_member_0[1] == P2_marking_member_0[3]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[4]; + b = P2_marking_member_0[1]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_marking_member_0[0] = P2_marking_member_0[2]; + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 4, 1, 2, 0 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[1] == P2_marking_member_0[2]) && + (P2_marking_member_0[1] == P2_marking_member_0[0]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[4]; + b = P2_marking_member_0[1]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_marking_member_0[0] = P2_marking_member_0[3]; + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 4, 1, 2, 3 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[1] == P2_marking_member_0[2]) && + (P2_marking_member_0[1] == P2_marking_member_0[3]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[4]; + b = P2_marking_member_0[1]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 4, 1, 3, 0 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[1] == P2_marking_member_0[3]) && + (P2_marking_member_0[1] == P2_marking_member_0[0]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[4]; + b = P2_marking_member_0[1]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_marking_member_0[0] = P2_marking_member_0[2]; + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 4, 1, 3, 2 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[1] == P2_marking_member_0[3]) && + (P2_marking_member_0[1] == P2_marking_member_0[2]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[4]; + b = P2_marking_member_0[1]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 4, 2, 0, 1 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[2] == P2_marking_member_0[0]) && + (P2_marking_member_0[2] == P2_marking_member_0[1]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[4]; + b = P2_marking_member_0[2]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_marking_member_0[0] = P2_marking_member_0[3]; + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 4, 2, 0, 3 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[2] == P2_marking_member_0[0]) && + (P2_marking_member_0[2] == P2_marking_member_0[3]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[4]; + b = P2_marking_member_0[2]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_marking_member_0[0] = P2_marking_member_0[1]; + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 4, 2, 1, 0 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[2] == P2_marking_member_0[1]) && + (P2_marking_member_0[2] == P2_marking_member_0[0]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[4]; + b = P2_marking_member_0[2]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_marking_member_0[0] = P2_marking_member_0[3]; + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 4, 2, 1, 3 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[2] == P2_marking_member_0[1]) && + (P2_marking_member_0[2] == P2_marking_member_0[3]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[4]; + b = P2_marking_member_0[2]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 4, 2, 3, 0 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[2] == P2_marking_member_0[3]) && + (P2_marking_member_0[2] == P2_marking_member_0[0]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[4]; + b = P2_marking_member_0[2]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_marking_member_0[0] = P2_marking_member_0[1]; + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 4, 2, 3, 1 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[2] == P2_marking_member_0[3]) && + (P2_marking_member_0[2] == P2_marking_member_0[1]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[4]; + b = P2_marking_member_0[2]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 4, 3, 0, 1 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[3] == P2_marking_member_0[0]) && + (P2_marking_member_0[3] == P2_marking_member_0[1]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[4]; + b = P2_marking_member_0[3]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_marking_member_0[0] = P2_marking_member_0[2]; + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 4, 3, 0, 2 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[3] == P2_marking_member_0[0]) && + (P2_marking_member_0[3] == P2_marking_member_0[2]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[4]; + b = P2_marking_member_0[3]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_marking_member_0[0] = P2_marking_member_0[1]; + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 4, 3, 1, 0 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[3] == P2_marking_member_0[1]) && + (P2_marking_member_0[3] == P2_marking_member_0[0]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[4]; + b = P2_marking_member_0[3]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_marking_member_0[0] = P2_marking_member_0[2]; + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 4, 3, 1, 2 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[3] == P2_marking_member_0[1]) && + (P2_marking_member_0[3] == P2_marking_member_0[2]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[4]; + b = P2_marking_member_0[3]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 4, 3, 2, 0 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[3] == P2_marking_member_0[2]) && + (P2_marking_member_0[3] == P2_marking_member_0[0]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[4]; + b = P2_marking_member_0[3]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_marking_member_0[0] = P2_marking_member_0[1]; + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + + + /* Permutation for Place P2 : 4, 3, 2, 1 */ + /* Transition T2 */ + if ((P2_is_marked >= 5) && + ((P3_is_marked + 3) <= 6) && + ((P2_marking_member_0[3] == P2_marking_member_0[2]) && + (P2_marking_member_0[3] == P2_marking_member_0[1]))) + { + + long a; + long b; + long c; + + a = P2_marking_member_0[4]; + b = P2_marking_member_0[3]; + + /* Transition condition */ + if ((b > a)) + { + + /* demarking of input places */ + P2_is_marked -= 4; + + /* preaction */ + c = a + b; + + /* marking of output places */ + P3_marking_member_0[P3_is_marked + 0] = a; + P3_marking_member_0[P3_is_marked + 1] = b; + P3_marking_member_0[P3_is_marked + 2] = c; + P3_is_marked += 3; + + } /* end of if (Transition condition) */ + } + } + + return 0; +} + + +int +verify_benchmark (int unused) +{ + int expP1_is_marked = 3; + long expP1_marking_member_0[3] = { 0, 0, 0 }; + int expP2_is_marked = 5; + long expP2_marking_member_0[5] = { 0, 0, 0, 0, 0 }; + int expP3_is_marked = 0; + long expP3_marking_member_0[6] = { 0, 0, 0, 0, 0, 0 }; + int i; + if (expP1_is_marked != P1_is_marked || + expP2_is_marked != P2_is_marked || expP3_is_marked != P3_is_marked) + { + return 0; + } + // for (i=0; i<3; i++) + // printf("%ld, ", P1_marking_member_0[i]); + // printf("\n"); + // for (i=0; i<5; i++) + // printf("%ld, ", P2_marking_member_0[i]); + // printf("\n"); + // for (i=0; i<6; i++) + // printf("%ld, ", P3_marking_member_0[i]); + // printf("\n"); + for (i = 0; i < 3; i++) + { + if (expP1_marking_member_0[i] != P1_marking_member_0[i] || + expP2_marking_member_0[i] != P2_marking_member_0[i] || + expP3_marking_member_0[i] != P3_marking_member_0[i]) + { + return 0; + } + } + for (i = 3; i < 5; i++) + { + if (expP2_marking_member_0[i] != P2_marking_member_0[i] || + expP3_marking_member_0[i] != P3_marking_member_0[i]) + { + return 0; + } + } + for (i = 5; i < 6; i++) + { + if (expP3_marking_member_0[i] != P3_marking_member_0[i]) + { + return 0; + } + } + + return 1; +} + + +/* + Local Variables: + mode: C + c-file-style: "gnu" + End: +*/ diff --git a/benchies/embench/benchemarks/picojpeg/libpicojpeg.c b/benchies/embench/benchemarks/picojpeg/libpicojpeg.c new file mode 100644 index 0000000000..87d7f1d5c8 --- /dev/null +++ b/benchies/embench/benchemarks/picojpeg/libpicojpeg.c @@ -0,0 +1,2528 @@ +/* This file is part of the Bristol/Embecosm Embedded Benchmark Suite. + + This version, copyright (C) 2014-2019 Embecosm Limited and University of + Bristol + + Contributor Jeremy Bennett + + This file is part of Embench and was formerly part of the Bristol/Embecosm + Embedded Benchmark Suite. + + SPDX-License-Identifier: GPL-3.0-or-later */ + +//------------------------------------------------------------------------------ +// picojpeg.c v1.1 - Public domain, Rich Geldreich +// Nov. 27, 2010 - Initial release +// Feb. 9, 2013 - Added H1V2/H2V1 support, cleaned up macros, signed shift fixes +// Also integrated and tested changes from Chris Phoenix . +//------------------------------------------------------------------------------ +#include "picojpeg.h" +//------------------------------------------------------------------------------ +// Set to 1 if right shifts on signed ints are always unsigned (logical) shifts +// When 1, arithmetic right shifts will be emulated by using a logical shift +// with special case code to ensure the sign bit is replicated. +#define PJPG_RIGHT_SHIFT_IS_ALWAYS_UNSIGNED 0 + +// Define PJPG_INLINE to "inline" if your C compiler supports explicit inlining +#define PJPG_INLINE +//------------------------------------------------------------------------------ +typedef unsigned char uint8; +typedef unsigned short uint16; +typedef signed char int8; +typedef signed short int16; +//------------------------------------------------------------------------------ +#if PJPG_RIGHT_SHIFT_IS_ALWAYS_UNSIGNED +static int16 +replicateSignBit16 (int8 n) +{ + switch (n) + { + case 0: + return 0x0000; + case 1: + return 0x8000; + case 2: + return 0xC000; + case 3: + return 0xE000; + case 4: + return 0xF000; + case 5: + return 0xF800; + case 6: + return 0xFC00; + case 7: + return 0xFE00; + case 8: + return 0xFF00; + case 9: + return 0xFF80; + case 10: + return 0xFFC0; + case 11: + return 0xFFE0; + case 12: + return 0xFFF0; + case 13: + return 0xFFF8; + case 14: + return 0xFFFC; + case 15: + return 0xFFFE; + default: + return 0xFFFF; + } +} + +static PJPG_INLINE int16 +arithmeticRightShiftN16 (int16 x, int8 n) +{ + int16 r = (uint16) x >> (uint8) n; + if (x < 0) + r |= replicateSignBit16 (n); + return r; +} + +static PJPG_INLINE long +arithmeticRightShift8L (long x) +{ + long r = (unsigned long) x >> 8U; + if (x < 0) + r |= ~(~(unsigned long) 0U >> 8U); + return r; +} + +#define PJPG_ARITH_SHIFT_RIGHT_N_16(x, n) arithmeticRightShiftN16(x, n) +#define PJPG_ARITH_SHIFT_RIGHT_8_L(x) arithmeticRightShift8L(x) +#else +#define PJPG_ARITH_SHIFT_RIGHT_N_16(x, n) ((x) >> (n)) +#define PJPG_ARITH_SHIFT_RIGHT_8_L(x) ((x) >> 8) +#endif +//------------------------------------------------------------------------------ +// Change as needed - the PJPG_MAX_WIDTH/PJPG_MAX_HEIGHT checks are only present +// to quickly detect bogus files. +#define PJPG_MAX_WIDTH 16384 +#define PJPG_MAX_HEIGHT 16384 +#define PJPG_MAXCOMPSINSCAN 3 +//------------------------------------------------------------------------------ +typedef enum +{ + M_SOF0 = 0xC0, + M_SOF1 = 0xC1, + M_SOF2 = 0xC2, + M_SOF3 = 0xC3, + + M_SOF5 = 0xC5, + M_SOF6 = 0xC6, + M_SOF7 = 0xC7, + + M_JPG = 0xC8, + M_SOF9 = 0xC9, + M_SOF10 = 0xCA, + M_SOF11 = 0xCB, + + M_SOF13 = 0xCD, + M_SOF14 = 0xCE, + M_SOF15 = 0xCF, + + M_DHT = 0xC4, + + M_DAC = 0xCC, + + M_RST0 = 0xD0, + M_RST1 = 0xD1, + M_RST2 = 0xD2, + M_RST3 = 0xD3, + M_RST4 = 0xD4, + M_RST5 = 0xD5, + M_RST6 = 0xD6, + M_RST7 = 0xD7, + + M_SOI = 0xD8, + M_EOI = 0xD9, + M_SOS = 0xDA, + M_DQT = 0xDB, + M_DNL = 0xDC, + M_DRI = 0xDD, + M_DHP = 0xDE, + M_EXP = 0xDF, + + M_APP0 = 0xE0, + M_APP15 = 0xEF, + + M_JPG0 = 0xF0, + M_JPG13 = 0xFD, + M_COM = 0xFE, + + M_TEM = 0x01, + + M_ERROR = 0x100, + + RST0 = 0xD0 +} JPEG_MARKER; +//------------------------------------------------------------------------------ +static const int8 ZAG[] = { + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, + 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, + 53, 60, 61, 54, 47, 55, 62, 63, +}; + +//------------------------------------------------------------------------------ +// 128 bytes +static int16 gCoeffBuf[8 * 8]; + +// 8*8*4 bytes * 3 = 768 +static uint8 gMCUBufR[256]; +static uint8 gMCUBufG[256]; +static uint8 gMCUBufB[256]; + +// 256 bytes +static int16 gQuant0[8 * 8]; +static int16 gQuant1[8 * 8]; + +// 6 bytes +static int16 gLastDC[3]; + +typedef struct HuffTableT +{ + uint16 mMinCode[16]; + uint16 mMaxCode[16]; + uint8 mValPtr[16]; +} HuffTable; + +// DC - 192 +static HuffTable gHuffTab0; + +static uint8 gHuffVal0[16]; + +static HuffTable gHuffTab1; +static uint8 gHuffVal1[16]; + +// AC - 672 +static HuffTable gHuffTab2; +static uint8 gHuffVal2[256]; + +static HuffTable gHuffTab3; +static uint8 gHuffVal3[256]; + +static uint8 gValidHuffTables; +static uint8 gValidQuantTables; + +static uint8 gTemFlag; +#define PJPG_MAX_IN_BUF_SIZE 256 +static uint8 gInBuf[PJPG_MAX_IN_BUF_SIZE]; +static uint8 gInBufOfs; +static uint8 gInBufLeft; + +static uint16 gBitBuf; +static uint8 gBitsLeft; +//------------------------------------------------------------------------------ +static uint16 gImageXSize; +static uint16 gImageYSize; +static uint8 gCompsInFrame; +static uint8 gCompIdent[3]; +static uint8 gCompHSamp[3]; +static uint8 gCompVSamp[3]; +static uint8 gCompQuant[3]; + +static uint16 gRestartInterval; +static uint16 gNextRestartNum; +static uint16 gRestartsLeft; + +static uint8 gCompsInScan; +static uint8 gCompList[3]; +static uint8 gCompDCTab[3]; // 0,1 +static uint8 gCompACTab[3]; // 0,1 + +static pjpeg_scan_type_t gScanType; + +static uint8 gMaxBlocksPerMCU; +static uint8 gMaxMCUXSize; +static uint8 gMaxMCUYSize; +static uint16 gMaxMCUSPerRow; +static uint16 gMaxMCUSPerCol; +static uint16 gNumMCUSRemaining; +static uint8 gMCUOrg[6]; + +static pjpeg_need_bytes_callback_t g_pNeedBytesCallback; +static void *g_pCallback_data; +static uint8 gCallbackStatus; +static uint8 gReduce; +//------------------------------------------------------------------------------ +static void +fillInBuf (void) +{ + unsigned char status; + + // Reserve a few bytes at the beginning of the buffer for putting back ("stuffing") chars. + gInBufOfs = 4; + gInBufLeft = 0; + + status = + (*g_pNeedBytesCallback) (gInBuf + gInBufOfs, + PJPG_MAX_IN_BUF_SIZE - gInBufOfs, &gInBufLeft, + g_pCallback_data); + if (status) + { + // The user provided need bytes callback has indicated an error, so record the error and continue trying to decode. + // The highest level pjpeg entrypoints will catch the error and return the non-zero status. + gCallbackStatus = status; + } +} + +//------------------------------------------------------------------------------ +static PJPG_INLINE uint8 +getChar (void) +{ + if (!gInBufLeft) + { + fillInBuf (); + if (!gInBufLeft) + { + gTemFlag = ~gTemFlag; + return gTemFlag ? 0xFF : 0xD9; + } + } + + gInBufLeft--; + return gInBuf[gInBufOfs++]; +} + +//------------------------------------------------------------------------------ +static PJPG_INLINE void +stuffChar (uint8 i) +{ + gInBufOfs--; + gInBuf[gInBufOfs] = i; + gInBufLeft++; +} + +//------------------------------------------------------------------------------ +static PJPG_INLINE uint8 +getOctet (uint8 FFCheck) +{ + uint8 c = getChar (); + + if ((FFCheck) && (c == 0xFF)) + { + uint8 n = getChar (); + + if (n) + { + stuffChar (n); + stuffChar (0xFF); + } + } + + return c; +} + +//------------------------------------------------------------------------------ +static uint16 +getBits (uint8 numBits, uint8 FFCheck) +{ + uint8 origBits = numBits; + uint16 ret = gBitBuf; + + if (numBits > 8) + { + numBits -= 8; + + gBitBuf <<= gBitsLeft; + + gBitBuf |= getOctet (FFCheck); + + gBitBuf <<= (8 - gBitsLeft); + + ret = (ret & 0xFF00) | (gBitBuf >> 8); + } + + if (gBitsLeft < numBits) + { + gBitBuf <<= gBitsLeft; + + gBitBuf |= getOctet (FFCheck); + + gBitBuf <<= (numBits - gBitsLeft); + + gBitsLeft = 8 - (numBits - gBitsLeft); + } + else + { + gBitsLeft = (uint8) (gBitsLeft - numBits); + gBitBuf <<= numBits; + } + + return ret >> (16 - origBits); +} + +//------------------------------------------------------------------------------ +static PJPG_INLINE uint16 +getBits1 (uint8 numBits) +{ + return getBits (numBits, 0); +} + +//------------------------------------------------------------------------------ +static PJPG_INLINE uint16 +getBits2 (uint8 numBits) +{ + return getBits (numBits, 1); +} + +//------------------------------------------------------------------------------ +static PJPG_INLINE uint8 +getBit (void) +{ + uint8 ret = 0; + if (gBitBuf & 0x8000) + ret = 1; + + if (!gBitsLeft) + { + gBitBuf |= getOctet (1); + + gBitsLeft += 8; + } + + gBitsLeft--; + gBitBuf <<= 1; + + return ret; +} + +//------------------------------------------------------------------------------ +static uint16 +getExtendTest (uint8 i) +{ + switch (i) + { + case 0: + return 0; + case 1: + return 0x0001; + case 2: + return 0x0002; + case 3: + return 0x0004; + case 4: + return 0x0008; + case 5: + return 0x0010; + case 6: + return 0x0020; + case 7: + return 0x0040; + case 8: + return 0x0080; + case 9: + return 0x0100; + case 10: + return 0x0200; + case 11: + return 0x0400; + case 12: + return 0x0800; + case 13: + return 0x1000; + case 14: + return 0x2000; + case 15: + return 0x4000; + default: + return 0; + } +} + +//------------------------------------------------------------------------------ +static int16 +getExtendOffset (uint8 i) +{ + switch (i) + { + case 0: + return 0; + case 1: + return -1; + case 2: + return -3; + case 3: + return -7; + case 4: + return -15; + case 5: + return -31; + case 6: + return -63; + case 7: + return -127; + case 8: + return -255; + case 9: + return -511; + case 10: + return -1023; + case 11: + return -2047; + case 12: + return -4095; + case 13: + return -8191; + case 14: + return -16383; + case 15: + return -32767; + default: + return 0; + } +} + +//------------------------------------------------------------------------------ +static PJPG_INLINE int16 +huffExtend (uint16 x, uint8 s) +{ + return ((x < + getExtendTest (s)) ? ((int16) x + + getExtendOffset (s)) : (int16) x); +} + +//------------------------------------------------------------------------------ +static PJPG_INLINE uint8 +huffDecode (const HuffTable * pHuffTable, const uint8 * pHuffVal) +{ + uint8 i = 0; + uint8 j; + uint16 code = getBit (); + + // This func only reads a bit at a time, which on modern CPU's is not terribly efficient. + // But on microcontrollers without strong integer shifting support this seems like a + // more reasonable approach. + for (;;) + { + uint16 maxCode; + + if (i == 16) + return 0; + + maxCode = pHuffTable->mMaxCode[i]; + if ((code <= maxCode) && (maxCode != 0xFFFF)) + break; + + i++; + code <<= 1; + code |= getBit (); + } + + j = pHuffTable->mValPtr[i]; + j = (uint8) (j + (code - pHuffTable->mMinCode[i])); + + return pHuffVal[j]; +} + +//------------------------------------------------------------------------------ +static void +huffCreate (const uint8 * pBits, HuffTable * pHuffTable) +{ + uint8 i = 0; + uint8 j = 0; + + uint16 code = 0; + + for (;;) + { + uint8 num = pBits[i]; + + if (!num) + { + pHuffTable->mMinCode[i] = 0x0000; + pHuffTable->mMaxCode[i] = 0xFFFF; + pHuffTable->mValPtr[i] = 0; + } + else + { + pHuffTable->mMinCode[i] = code; + pHuffTable->mMaxCode[i] = code + num - 1; + pHuffTable->mValPtr[i] = j; + + j = (uint8) (j + num); + + code = (uint16) (code + num); + } + + code <<= 1; + + i++; + if (i > 15) + break; + } +} + +//------------------------------------------------------------------------------ +static HuffTable * +getHuffTable (uint8 index) +{ + // 0-1 = DC + // 2-3 = AC + switch (index) + { + case 0: + return &gHuffTab0; + case 1: + return &gHuffTab1; + case 2: + return &gHuffTab2; + case 3: + return &gHuffTab3; + default: + return 0; + } +} + +//------------------------------------------------------------------------------ +static uint8 * +getHuffVal (uint8 index) +{ + // 0-1 = DC + // 2-3 = AC + switch (index) + { + case 0: + return gHuffVal0; + case 1: + return gHuffVal1; + case 2: + return gHuffVal2; + case 3: + return gHuffVal3; + default: + return 0; + } +} + +//------------------------------------------------------------------------------ +static uint16 +getMaxHuffCodes (uint8 index) +{ + return (index < 2) ? 12 : 255; +} + +//------------------------------------------------------------------------------ +static uint8 +readDHTMarker (void) +{ + uint8 bits[16]; + uint16 left = getBits1 (16); + + if (left < 2) + return PJPG_BAD_DHT_MARKER; + + left -= 2; + + while (left) + { + uint8 i, tableIndex, index; + uint8 *pHuffVal; + HuffTable *pHuffTable; + uint16 count, totalRead; + + index = (uint8) getBits1 (8); + + if (((index & 0xF) > 1) || ((index & 0xF0) > 0x10)) + return PJPG_BAD_DHT_INDEX; + + tableIndex = ((index >> 3) & 2) + (index & 1); + + pHuffTable = getHuffTable (tableIndex); + pHuffVal = getHuffVal (tableIndex); + + gValidHuffTables |= (1 << tableIndex); + + count = 0; + for (i = 0; i <= 15; i++) + { + uint8 n = (uint8) getBits1 (8); + bits[i] = n; + count = (uint16) (count + n); + } + + if (count > getMaxHuffCodes (tableIndex)) + return PJPG_BAD_DHT_COUNTS; + + for (i = 0; i < count; i++) + pHuffVal[i] = (uint8) getBits1 (8); + + totalRead = 1 + 16 + count; + + if (left < totalRead) + return PJPG_BAD_DHT_MARKER; + + left = (uint16) (left - totalRead); + + huffCreate (bits, pHuffTable); + } + + return 0; +} + +//------------------------------------------------------------------------------ +static void createWinogradQuant (int16 * pQuant); + +static uint8 +readDQTMarker (void) +{ + uint16 left = getBits1 (16); + + if (left < 2) + return PJPG_BAD_DQT_MARKER; + + left -= 2; + + while (left) + { + uint8 i; + uint8 n = (uint8) getBits1 (8); + uint8 prec = n >> 4; + uint16 totalRead; + + n &= 0x0F; + + if (n > 1) + return PJPG_BAD_DQT_TABLE; + + gValidQuantTables |= (n ? 2 : 1); + + // read quantization entries, in zag order + for (i = 0; i < 64; i++) + { + uint16 temp = getBits1 (8); + + if (prec) + temp = (temp << 8) + getBits1 (8); + + if (n) + gQuant1[i] = (int16) temp; + else + gQuant0[i] = (int16) temp; + } + + createWinogradQuant (n ? gQuant1 : gQuant0); + + totalRead = 64 + 1; + + if (prec) + totalRead += 64; + + if (left < totalRead) + return PJPG_BAD_DQT_LENGTH; + + left = (uint16) (left - totalRead); + } + + return 0; +} + +//------------------------------------------------------------------------------ +static uint8 +readSOFMarker (void) +{ + uint8 i; + uint16 left = getBits1 (16); + + if (getBits1 (8) != 8) + return PJPG_BAD_PRECISION; + + gImageYSize = getBits1 (16); + + if ((!gImageYSize) || (gImageYSize > PJPG_MAX_HEIGHT)) + return PJPG_BAD_HEIGHT; + + gImageXSize = getBits1 (16); + + if ((!gImageXSize) || (gImageXSize > PJPG_MAX_WIDTH)) + return PJPG_BAD_WIDTH; + + gCompsInFrame = (uint8) getBits1 (8); + + if (gCompsInFrame > 3) + return PJPG_TOO_MANY_COMPONENTS; + + if (left != (gCompsInFrame + gCompsInFrame + gCompsInFrame + 8)) + return PJPG_BAD_SOF_LENGTH; + + for (i = 0; i < gCompsInFrame; i++) + { + gCompIdent[i] = (uint8) getBits1 (8); + gCompHSamp[i] = (uint8) getBits1 (4); + gCompVSamp[i] = (uint8) getBits1 (4); + gCompQuant[i] = (uint8) getBits1 (8); + + if (gCompQuant[i] > 1) + return PJPG_UNSUPPORTED_QUANT_TABLE; + } + + return 0; +} + +//------------------------------------------------------------------------------ +// Used to skip unrecognized markers. +static uint8 +skipVariableMarker (void) +{ + uint16 left = getBits1 (16); + + if (left < 2) + return PJPG_BAD_VARIABLE_MARKER; + + left -= 2; + + while (left) + { + getBits1 (8); + left--; + } + + return 0; +} + +//------------------------------------------------------------------------------ +// Read a define restart interval (DRI) marker. +static uint8 +readDRIMarker (void) +{ + if (getBits1 (16) != 4) + return PJPG_BAD_DRI_LENGTH; + + gRestartInterval = getBits1 (16); + + return 0; +} + +//------------------------------------------------------------------------------ +// Read a start of scan (SOS) marker. + +/* Make these volatile global so the compiler does not optimise out + calls within READSOSMARKER. */ +volatile uint8 spectral_start, spectral_end; +volatile uint8 successive_high, successive_low; + +static uint8 +readSOSMarker (void) +{ + uint8 i; + uint16 left = getBits1 (16); + + gCompsInScan = (uint8) getBits1 (8); + + left -= 3; + + if ((left != (gCompsInScan + gCompsInScan + 3)) || (gCompsInScan < 1) + || (gCompsInScan > PJPG_MAXCOMPSINSCAN)) + return PJPG_BAD_SOS_LENGTH; + + for (i = 0; i < gCompsInScan; i++) + { + uint8 cc = (uint8) getBits1 (8); + uint8 c = (uint8) getBits1 (8); + uint8 ci; + + left -= 2; + + for (ci = 0; ci < gCompsInFrame; ci++) + if (cc == gCompIdent[ci]) + break; + + if (ci >= gCompsInFrame) + return PJPG_BAD_SOS_COMP_ID; + + gCompList[i] = ci; + gCompDCTab[ci] = (c >> 4) & 15; + gCompACTab[ci] = (c & 15); + } + + spectral_start = (uint8) getBits1 (8); + spectral_end = (uint8) getBits1 (8); + successive_high = (uint8) getBits1 (4); + successive_low = (uint8) getBits1 (4); + + left -= 3; + + while (left) + { + getBits1 (8); + left--; + } + + return 0; +} + +//------------------------------------------------------------------------------ +static uint8 +nextMarker (void) +{ + uint8 c; + uint8 bytes = 0; + + do + { + do + { + bytes++; + + c = (uint8) getBits1 (8); + + } + while (c != 0xFF); + + do + { + c = (uint8) getBits1 (8); + + } + while (c == 0xFF); + + } + while (c == 0); + + // If bytes > 0 here, there where extra bytes before the marker (not good). + + return c; +} + +//------------------------------------------------------------------------------ +// Process markers. Returns when an SOFx, SOI, EOI, or SOS marker is +// encountered. +static uint8 +processMarkers (uint8 * pMarker) +{ + for (;;) + { + uint8 c = nextMarker (); + + switch (c) + { + case M_SOF0: + case M_SOF1: + case M_SOF2: + case M_SOF3: + case M_SOF5: + case M_SOF6: + case M_SOF7: + // case M_JPG: + case M_SOF9: + case M_SOF10: + case M_SOF11: + case M_SOF13: + case M_SOF14: + case M_SOF15: + case M_SOI: + case M_EOI: + case M_SOS: + { + *pMarker = c; + return 0; + } + case M_DHT: + { + readDHTMarker (); + break; + } + // Sorry, no arithmetic support at this time. Dumb patents! + case M_DAC: + { + return PJPG_NO_ARITHMITIC_SUPPORT; + } + case M_DQT: + { + readDQTMarker (); + break; + } + case M_DRI: + { + readDRIMarker (); + break; + } + //case M_APP0: /* no need to read the JFIF marker */ + + case M_JPG: + case M_RST0: /* no parameters */ + case M_RST1: + case M_RST2: + case M_RST3: + case M_RST4: + case M_RST5: + case M_RST6: + case M_RST7: + case M_TEM: + { + return PJPG_UNEXPECTED_MARKER; + } + default: /* must be DNL, DHP, EXP, APPn, JPGn, COM, or RESn or APP0 */ + { + skipVariableMarker (); + break; + } + } + } +// return 0; +} + +//------------------------------------------------------------------------------ +// Finds the start of image (SOI) marker. +static uint8 +locateSOIMarker (void) +{ + uint16 bytesleft; + + uint8 lastchar = (uint8) getBits1 (8); + + uint8 thischar = (uint8) getBits1 (8); + + /* ok if it's a normal JPEG file without a special header */ + + if ((lastchar == 0xFF) && (thischar == M_SOI)) + return 0; + + bytesleft = 4096; //512; + + for (;;) + { + if (--bytesleft == 0) + return PJPG_NOT_JPEG; + + lastchar = thischar; + + thischar = (uint8) getBits1 (8); + + if (lastchar == 0xFF) + { + if (thischar == M_SOI) + break; + else if (thischar == M_EOI) //getBits1 will keep returning M_EOI if we read past the end + return PJPG_NOT_JPEG; + } + } + + /* Check the next character after marker: if it's not 0xFF, it can't + be the start of the next marker, so the file is bad */ + + thischar = (uint8) ((gBitBuf >> 8) & 0xFF); + + if (thischar != 0xFF) + return PJPG_NOT_JPEG; + + return 0; +} + +//------------------------------------------------------------------------------ +// Find a start of frame (SOF) marker. +static uint8 +locateSOFMarker (void) +{ + uint8 c; + + uint8 status = locateSOIMarker (); + if (status) + return status; + + status = processMarkers (&c); + if (status) + return status; + + switch (c) + { + case M_SOF2: + { + // Progressive JPEG - not supported by picojpeg (would require too + // much memory, or too many IDCT's for embedded systems). + return PJPG_UNSUPPORTED_MODE; + } + case M_SOF0: /* baseline DCT */ + { + status = readSOFMarker (); + if (status) + return status; + + break; + } + case M_SOF9: + { + return PJPG_NO_ARITHMITIC_SUPPORT; + } + case M_SOF1: /* extended sequential DCT */ + default: + { + return PJPG_UNSUPPORTED_MARKER; + } + } + + return 0; +} + +//------------------------------------------------------------------------------ +// Find a start of scan (SOS) marker. +static uint8 +locateSOSMarker (uint8 * pFoundEOI) +{ + uint8 c; + uint8 status; + + *pFoundEOI = 0; + + status = processMarkers (&c); + if (status) + return status; + + if (c == M_EOI) + { + *pFoundEOI = 1; + return 0; + } + else if (c != M_SOS) + return PJPG_UNEXPECTED_MARKER; + + return readSOSMarker (); +} + +//------------------------------------------------------------------------------ +static uint8 +init (void) +{ + gImageXSize = 0; + gImageYSize = 0; + gCompsInFrame = 0; + gRestartInterval = 0; + gCompsInScan = 0; + gValidHuffTables = 0; + gValidQuantTables = 0; + gTemFlag = 0; + gInBufOfs = 0; + gInBufLeft = 0; + gBitBuf = 0; + gBitsLeft = 8; + + getBits1 (8); + getBits1 (8); + + return 0; +} + +//------------------------------------------------------------------------------ +// This method throws back into the stream any bytes that where read +// into the bit buffer during initial marker scanning. +static void +fixInBuffer (void) +{ + /* In case any 0xFF's where pulled into the buffer during marker scanning */ + + if (gBitsLeft > 0) + stuffChar ((uint8) gBitBuf); + + stuffChar ((uint8) (gBitBuf >> 8)); + + gBitsLeft = 8; + getBits2 (8); + getBits2 (8); +} + +//------------------------------------------------------------------------------ +// Restart interval processing. +static uint8 +processRestart (void) +{ + // Let's scan a little bit to find the marker, but not _too_ far. + // 1536 is a "fudge factor" that determines how much to scan. + uint16 i; + uint8 c = 0; + + for (i = 1536; i > 0; i--) + if (getChar () == 0xFF) + break; + + if (i == 0) + return PJPG_BAD_RESTART_MARKER; + + for (; i > 0; i--) + if ((c = getChar ()) != 0xFF) + break; + + if (i == 0) + return PJPG_BAD_RESTART_MARKER; + + // Is it the expected marker? If not, something bad happened. + if (c != (gNextRestartNum + M_RST0)) + return PJPG_BAD_RESTART_MARKER; + + // Reset each component's DC prediction values. + gLastDC[0] = 0; + gLastDC[1] = 0; + gLastDC[2] = 0; + + gRestartsLeft = gRestartInterval; + + gNextRestartNum = (gNextRestartNum + 1) & 7; + + // Get the bit buffer going again + + gBitsLeft = 8; + getBits2 (8); + getBits2 (8); + + return 0; +} + +//------------------------------------------------------------------------------ +static uint8 +checkHuffTables (void) +{ + uint8 i; + + for (i = 0; i < gCompsInScan; i++) + { + uint8 compDCTab = gCompDCTab[gCompList[i]]; + uint8 compACTab = gCompACTab[gCompList[i]] + 2; + + if (((gValidHuffTables & (1 << compDCTab)) == 0) || + ((gValidHuffTables & (1 << compACTab)) == 0)) + return PJPG_UNDEFINED_HUFF_TABLE; + } + + return 0; +} + +//------------------------------------------------------------------------------ +static uint8 +checkQuantTables (void) +{ + uint8 i; + + for (i = 0; i < gCompsInScan; i++) + { + uint8 compQuantMask = gCompQuant[gCompList[i]] ? 2 : 1; + + if ((gValidQuantTables & compQuantMask) == 0) + return PJPG_UNDEFINED_QUANT_TABLE; + } + + return 0; +} + +//------------------------------------------------------------------------------ +static uint8 +initScan (void) +{ + uint8 foundEOI; + uint8 status = locateSOSMarker (&foundEOI); + if (status) + return status; + if (foundEOI) + return PJPG_UNEXPECTED_MARKER; + + status = checkHuffTables (); + if (status) + return status; + + status = checkQuantTables (); + if (status) + return status; + + gLastDC[0] = 0; + gLastDC[1] = 0; + gLastDC[2] = 0; + + if (gRestartInterval) + { + gRestartsLeft = gRestartInterval; + gNextRestartNum = 0; + } + + fixInBuffer (); + + return 0; +} + +//------------------------------------------------------------------------------ +static uint8 +initFrame (void) +{ + if (gCompsInFrame == 1) + { + if ((gCompHSamp[0] != 1) || (gCompVSamp[0] != 1)) + return PJPG_UNSUPPORTED_SAMP_FACTORS; + + gScanType = PJPG_GRAYSCALE; + + gMaxBlocksPerMCU = 1; + gMCUOrg[0] = 0; + + gMaxMCUXSize = 8; + gMaxMCUYSize = 8; + } + else if (gCompsInFrame == 3) + { + if (((gCompHSamp[1] != 1) || (gCompVSamp[1] != 1)) || + ((gCompHSamp[2] != 1) || (gCompVSamp[2] != 1))) + return PJPG_UNSUPPORTED_SAMP_FACTORS; + + if ((gCompHSamp[0] == 1) && (gCompVSamp[0] == 1)) + { + gScanType = PJPG_YH1V1; + + gMaxBlocksPerMCU = 3; + gMCUOrg[0] = 0; + gMCUOrg[1] = 1; + gMCUOrg[2] = 2; + + gMaxMCUXSize = 8; + gMaxMCUYSize = 8; + } + else if ((gCompHSamp[0] == 1) && (gCompVSamp[0] == 2)) + { + gScanType = PJPG_YH1V2; + + gMaxBlocksPerMCU = 4; + gMCUOrg[0] = 0; + gMCUOrg[1] = 0; + gMCUOrg[2] = 1; + gMCUOrg[3] = 2; + + gMaxMCUXSize = 8; + gMaxMCUYSize = 16; + } + else if ((gCompHSamp[0] == 2) && (gCompVSamp[0] == 1)) + { + gScanType = PJPG_YH2V1; + + gMaxBlocksPerMCU = 4; + gMCUOrg[0] = 0; + gMCUOrg[1] = 0; + gMCUOrg[2] = 1; + gMCUOrg[3] = 2; + + gMaxMCUXSize = 16; + gMaxMCUYSize = 8; + } + else if ((gCompHSamp[0] == 2) && (gCompVSamp[0] == 2)) + { + gScanType = PJPG_YH2V2; + + gMaxBlocksPerMCU = 6; + gMCUOrg[0] = 0; + gMCUOrg[1] = 0; + gMCUOrg[2] = 0; + gMCUOrg[3] = 0; + gMCUOrg[4] = 1; + gMCUOrg[5] = 2; + + gMaxMCUXSize = 16; + gMaxMCUYSize = 16; + } + else + return PJPG_UNSUPPORTED_SAMP_FACTORS; + } + else + return PJPG_UNSUPPORTED_COLORSPACE; + + gMaxMCUSPerRow = + (gImageXSize + (gMaxMCUXSize - 1)) >> ((gMaxMCUXSize == 8) ? 3 : 4); + gMaxMCUSPerCol = + (gImageYSize + (gMaxMCUYSize - 1)) >> ((gMaxMCUYSize == 8) ? 3 : 4); + + gNumMCUSRemaining = gMaxMCUSPerRow * gMaxMCUSPerCol; + + return 0; +} + +//---------------------------------------------------------------------------- +// Winograd IDCT: 5 multiplies per row/col, up to 80 muls for the 2D IDCT + +#define PJPG_DCT_SCALE_BITS 7 + +#define PJPG_DCT_SCALE (1U << PJPG_DCT_SCALE_BITS) + +#define PJPG_DESCALE(x) PJPG_ARITH_SHIFT_RIGHT_N_16(((x) + (1U << (PJPG_DCT_SCALE_BITS - 1))), PJPG_DCT_SCALE_BITS) + +#define PJPG_WFIX(x) ((x) * PJPG_DCT_SCALE + 0.5f) + +#define PJPG_WINOGRAD_QUANT_SCALE_BITS 10 + +const uint8 gWinogradQuant[] = { + 128, 178, 178, 167, 246, 167, 151, 232, + 232, 151, 128, 209, 219, 209, 128, 101, + 178, 197, 197, 178, 101, 69, 139, 167, + 177, 167, 139, 69, 35, 96, 131, 151, + 151, 131, 96, 35, 49, 91, 118, 128, + 118, 91, 49, 46, 81, 101, 101, 81, + 46, 42, 69, 79, 69, 42, 35, 54, + 54, 35, 28, 37, 28, 19, 19, 10, +}; + +// Multiply quantization matrix by the Winograd IDCT scale factors +static void +createWinogradQuant (int16 * pQuant) +{ + uint8 i; + + for (i = 0; i < 64; i++) + { + long x = pQuant[i]; + x *= gWinogradQuant[i]; + pQuant[i] = + (int16) ((x + + (1 << + (PJPG_WINOGRAD_QUANT_SCALE_BITS - PJPG_DCT_SCALE_BITS - + 1))) >> (PJPG_WINOGRAD_QUANT_SCALE_BITS - + PJPG_DCT_SCALE_BITS)); + } +} + +// These multiply helper functions are the 4 types of signed multiplies needed by the Winograd IDCT. +// A smart C compiler will optimize them to use 16x8 = 24 bit muls, if not you may need to tweak +// these functions or drop to CPU specific inline assembly. + +// 1/cos(4*pi/16) +// 362, 256+106 +static PJPG_INLINE int16 +imul_b1_b3 (int16 w) +{ + long x = (w * 362L); + x += 128L; + return (int16) (PJPG_ARITH_SHIFT_RIGHT_8_L (x)); +} + +// 1/cos(6*pi/16) +// 669, 256+256+157 +static PJPG_INLINE int16 +imul_b2 (int16 w) +{ + long x = (w * 669L); + x += 128L; + return (int16) (PJPG_ARITH_SHIFT_RIGHT_8_L (x)); +} + +// 1/cos(2*pi/16) +// 277, 256+21 +static PJPG_INLINE int16 +imul_b4 (int16 w) +{ + long x = (w * 277L); + x += 128L; + return (int16) (PJPG_ARITH_SHIFT_RIGHT_8_L (x)); +} + +// 1/(cos(2*pi/16) + cos(6*pi/16)) +// 196, 196 +static PJPG_INLINE int16 +imul_b5 (int16 w) +{ + long x = (w * 196L); + x += 128L; + return (int16) (PJPG_ARITH_SHIFT_RIGHT_8_L (x)); +} + +static PJPG_INLINE uint8 +clamp (int16 s) +{ + if ((uint16) s > 255U) + { + if (s < 0) + return 0; + else if (s > 255) + return 255; + } + + return (uint8) s; +} + +static void +idctRows (void) +{ + uint8 i; + int16 *pSrc = gCoeffBuf; + + for (i = 0; i < 8; i++) + { + if ((pSrc[1] | pSrc[2] | pSrc[3] | pSrc[4] | pSrc[5] | pSrc[6] | + pSrc[7]) == 0) + { + // Short circuit the 1D IDCT if only the DC component is non-zero + int16 src0 = *pSrc; + + *(pSrc + 1) = src0; + *(pSrc + 2) = src0; + *(pSrc + 3) = src0; + *(pSrc + 4) = src0; + *(pSrc + 5) = src0; + *(pSrc + 6) = src0; + *(pSrc + 7) = src0; + } + else + { + int16 src4 = *(pSrc + 5); + int16 src7 = *(pSrc + 3); + int16 x4 = src4 - src7; + int16 x7 = src4 + src7; + + int16 src5 = *(pSrc + 1); + int16 src6 = *(pSrc + 7); + int16 x5 = src5 + src6; + int16 x6 = src5 - src6; + + int16 tmp1 = imul_b5 (x4 - x6); + int16 stg26 = imul_b4 (x6) - tmp1; + + int16 x24 = tmp1 - imul_b2 (x4); + + int16 x15 = x5 - x7; + int16 x17 = x5 + x7; + + int16 tmp2 = stg26 - x17; + int16 tmp3 = imul_b1_b3 (x15) - tmp2; + int16 x44 = tmp3 + x24; + + int16 src0 = *(pSrc + 0); + int16 src1 = *(pSrc + 4); + int16 x30 = src0 + src1; + int16 x31 = src0 - src1; + + int16 src2 = *(pSrc + 2); + int16 src3 = *(pSrc + 6); + int16 x12 = src2 - src3; + int16 x13 = src2 + src3; + + int16 x32 = imul_b1_b3 (x12) - x13; + + int16 x40 = x30 + x13; + int16 x43 = x30 - x13; + int16 x41 = x31 + x32; + int16 x42 = x31 - x32; + + *(pSrc + 0) = x40 + x17; + *(pSrc + 1) = x41 + tmp2; + *(pSrc + 2) = x42 + tmp3; + *(pSrc + 3) = x43 - x44; + *(pSrc + 4) = x43 + x44; + *(pSrc + 5) = x42 - tmp3; + *(pSrc + 6) = x41 - tmp2; + *(pSrc + 7) = x40 - x17; + } + + pSrc += 8; + } +} + +static void +idctCols (void) +{ + uint8 i; + + int16 *pSrc = gCoeffBuf; + + for (i = 0; i < 8; i++) + { + if ((pSrc[1 * 8] | pSrc[2 * 8] | pSrc[3 * 8] | pSrc[4 * 8] | pSrc[5 * 8] + | pSrc[6 * 8] | pSrc[7 * 8]) == 0) + { + // Short circuit the 1D IDCT if only the DC component is non-zero + uint8 c = clamp (PJPG_DESCALE (*pSrc) + 128); + *(pSrc + 0 * 8) = c; + *(pSrc + 1 * 8) = c; + *(pSrc + 2 * 8) = c; + *(pSrc + 3 * 8) = c; + *(pSrc + 4 * 8) = c; + *(pSrc + 5 * 8) = c; + *(pSrc + 6 * 8) = c; + *(pSrc + 7 * 8) = c; + } + else + { + int16 src4 = *(pSrc + 5 * 8); + int16 src7 = *(pSrc + 3 * 8); + int16 x4 = src4 - src7; + int16 x7 = src4 + src7; + + int16 src5 = *(pSrc + 1 * 8); + int16 src6 = *(pSrc + 7 * 8); + int16 x5 = src5 + src6; + int16 x6 = src5 - src6; + + int16 tmp1 = imul_b5 (x4 - x6); + int16 stg26 = imul_b4 (x6) - tmp1; + + int16 x24 = tmp1 - imul_b2 (x4); + + int16 x15 = x5 - x7; + int16 x17 = x5 + x7; + + int16 tmp2 = stg26 - x17; + int16 tmp3 = imul_b1_b3 (x15) - tmp2; + int16 x44 = tmp3 + x24; + + int16 src0 = *(pSrc + 0 * 8); + int16 src1 = *(pSrc + 4 * 8); + int16 x30 = src0 + src1; + int16 x31 = src0 - src1; + + int16 src2 = *(pSrc + 2 * 8); + int16 src3 = *(pSrc + 6 * 8); + int16 x12 = src2 - src3; + int16 x13 = src2 + src3; + + int16 x32 = imul_b1_b3 (x12) - x13; + + int16 x40 = x30 + x13; + int16 x43 = x30 - x13; + int16 x41 = x31 + x32; + int16 x42 = x31 - x32; + + // descale, convert to unsigned and clamp to 8-bit + *(pSrc + 0 * 8) = clamp (PJPG_DESCALE (x40 + x17) + 128); + *(pSrc + 1 * 8) = clamp (PJPG_DESCALE (x41 + tmp2) + 128); + *(pSrc + 2 * 8) = clamp (PJPG_DESCALE (x42 + tmp3) + 128); + *(pSrc + 3 * 8) = clamp (PJPG_DESCALE (x43 - x44) + 128); + *(pSrc + 4 * 8) = clamp (PJPG_DESCALE (x43 + x44) + 128); + *(pSrc + 5 * 8) = clamp (PJPG_DESCALE (x42 - tmp3) + 128); + *(pSrc + 6 * 8) = clamp (PJPG_DESCALE (x41 - tmp2) + 128); + *(pSrc + 7 * 8) = clamp (PJPG_DESCALE (x40 - x17) + 128); + } + + pSrc++; + } +} + +/*----------------------------------------------------------------------------*/ +static PJPG_INLINE uint8 +addAndClamp (uint8 a, int16 b) +{ + b = a + b; + + if ((uint16) b > 255U) + { + if (b < 0) + return 0; + else if (b > 255) + return 255; + } + + return (uint8) b; +} + +/*----------------------------------------------------------------------------*/ +static PJPG_INLINE uint8 +subAndClamp (uint8 a, int16 b) +{ + b = a - b; + + if ((uint16) b > 255U) + { + if (b < 0) + return 0; + else if (b > 255) + return 255; + } + + return (uint8) b; +} + +/*----------------------------------------------------------------------------*/ +// 103/256 +//R = Y + 1.402 (Cr-128) + +// 88/256, 183/256 +//G = Y - 0.34414 (Cb-128) - 0.71414 (Cr-128) + +// 198/256 +//B = Y + 1.772 (Cb-128) +/*----------------------------------------------------------------------------*/ +// Cb upsample and accumulate, 4x4 to 8x8 +static void +upsampleCb (uint8 srcOfs, uint8 dstOfs) +{ + // Cb - affects G and B + uint8 x, y; + int16 *pSrc = gCoeffBuf + srcOfs; + uint8 *pDstG = gMCUBufG + dstOfs; + uint8 *pDstB = gMCUBufB + dstOfs; + for (y = 0; y < 4; y++) + { + for (x = 0; x < 4; x++) + { + uint8 cb = (uint8) * pSrc++; + int16 cbG, cbB; + + cbG = ((cb * 88U) >> 8U) - 44U; + pDstG[0] = subAndClamp (pDstG[0], cbG); + pDstG[1] = subAndClamp (pDstG[1], cbG); + pDstG[8] = subAndClamp (pDstG[8], cbG); + pDstG[9] = subAndClamp (pDstG[9], cbG); + + cbB = (cb + ((cb * 198U) >> 8U)) - 227U; + pDstB[0] = addAndClamp (pDstB[0], cbB); + pDstB[1] = addAndClamp (pDstB[1], cbB); + pDstB[8] = addAndClamp (pDstB[8], cbB); + pDstB[9] = addAndClamp (pDstB[9], cbB); + + pDstG += 2; + pDstB += 2; + } + + pSrc = pSrc - 4 + 8; + pDstG = pDstG - 8 + 16; + pDstB = pDstB - 8 + 16; + } +} + +/*----------------------------------------------------------------------------*/ +// Cb upsample and accumulate, 4x8 to 8x8 +static void +upsampleCbH (uint8 srcOfs, uint8 dstOfs) +{ + // Cb - affects G and B + uint8 x, y; + int16 *pSrc = gCoeffBuf + srcOfs; + uint8 *pDstG = gMCUBufG + dstOfs; + uint8 *pDstB = gMCUBufB + dstOfs; + for (y = 0; y < 8; y++) + { + for (x = 0; x < 4; x++) + { + uint8 cb = (uint8) * pSrc++; + int16 cbG, cbB; + + cbG = ((cb * 88U) >> 8U) - 44U; + pDstG[0] = subAndClamp (pDstG[0], cbG); + pDstG[1] = subAndClamp (pDstG[1], cbG); + + cbB = (cb + ((cb * 198U) >> 8U)) - 227U; + pDstB[0] = addAndClamp (pDstB[0], cbB); + pDstB[1] = addAndClamp (pDstB[1], cbB); + + pDstG += 2; + pDstB += 2; + } + + pSrc = pSrc - 4 + 8; + } +} + +/*----------------------------------------------------------------------------*/ +// Cb upsample and accumulate, 8x4 to 8x8 +static void +upsampleCbV (uint8 srcOfs, uint8 dstOfs) +{ + // Cb - affects G and B + uint8 x, y; + int16 *pSrc = gCoeffBuf + srcOfs; + uint8 *pDstG = gMCUBufG + dstOfs; + uint8 *pDstB = gMCUBufB + dstOfs; + for (y = 0; y < 4; y++) + { + for (x = 0; x < 8; x++) + { + uint8 cb = (uint8) * pSrc++; + int16 cbG, cbB; + + cbG = ((cb * 88U) >> 8U) - 44U; + pDstG[0] = subAndClamp (pDstG[0], cbG); + pDstG[8] = subAndClamp (pDstG[8], cbG); + + cbB = (cb + ((cb * 198U) >> 8U)) - 227U; + pDstB[0] = addAndClamp (pDstB[0], cbB); + pDstB[8] = addAndClamp (pDstB[8], cbB); + + ++pDstG; + ++pDstB; + } + + pDstG = pDstG - 8 + 16; + pDstB = pDstB - 8 + 16; + } +} + +/*----------------------------------------------------------------------------*/ +// 103/256 +//R = Y + 1.402 (Cr-128) + +// 88/256, 183/256 +//G = Y - 0.34414 (Cb-128) - 0.71414 (Cr-128) + +// 198/256 +//B = Y + 1.772 (Cb-128) +/*----------------------------------------------------------------------------*/ +// Cr upsample and accumulate, 4x4 to 8x8 +static void +upsampleCr (uint8 srcOfs, uint8 dstOfs) +{ + // Cr - affects R and G + uint8 x, y; + int16 *pSrc = gCoeffBuf + srcOfs; + uint8 *pDstR = gMCUBufR + dstOfs; + uint8 *pDstG = gMCUBufG + dstOfs; + for (y = 0; y < 4; y++) + { + for (x = 0; x < 4; x++) + { + uint8 cr = (uint8) * pSrc++; + int16 crR, crG; + + crR = (cr + ((cr * 103U) >> 8U)) - 179; + pDstR[0] = addAndClamp (pDstR[0], crR); + pDstR[1] = addAndClamp (pDstR[1], crR); + pDstR[8] = addAndClamp (pDstR[8], crR); + pDstR[9] = addAndClamp (pDstR[9], crR); + + crG = ((cr * 183U) >> 8U) - 91; + pDstG[0] = subAndClamp (pDstG[0], crG); + pDstG[1] = subAndClamp (pDstG[1], crG); + pDstG[8] = subAndClamp (pDstG[8], crG); + pDstG[9] = subAndClamp (pDstG[9], crG); + + pDstR += 2; + pDstG += 2; + } + + pSrc = pSrc - 4 + 8; + pDstR = pDstR - 8 + 16; + pDstG = pDstG - 8 + 16; + } +} + +/*----------------------------------------------------------------------------*/ +// Cr upsample and accumulate, 4x8 to 8x8 +static void +upsampleCrH (uint8 srcOfs, uint8 dstOfs) +{ + // Cr - affects R and G + uint8 x, y; + int16 *pSrc = gCoeffBuf + srcOfs; + uint8 *pDstR = gMCUBufR + dstOfs; + uint8 *pDstG = gMCUBufG + dstOfs; + for (y = 0; y < 8; y++) + { + for (x = 0; x < 4; x++) + { + uint8 cr = (uint8) * pSrc++; + int16 crR, crG; + + crR = (cr + ((cr * 103U) >> 8U)) - 179; + pDstR[0] = addAndClamp (pDstR[0], crR); + pDstR[1] = addAndClamp (pDstR[1], crR); + + crG = ((cr * 183U) >> 8U) - 91; + pDstG[0] = subAndClamp (pDstG[0], crG); + pDstG[1] = subAndClamp (pDstG[1], crG); + + pDstR += 2; + pDstG += 2; + } + + pSrc = pSrc - 4 + 8; + } +} + +/*----------------------------------------------------------------------------*/ +// Cr upsample and accumulate, 8x4 to 8x8 +static void +upsampleCrV (uint8 srcOfs, uint8 dstOfs) +{ + // Cr - affects R and G + uint8 x, y; + int16 *pSrc = gCoeffBuf + srcOfs; + uint8 *pDstR = gMCUBufR + dstOfs; + uint8 *pDstG = gMCUBufG + dstOfs; + for (y = 0; y < 4; y++) + { + for (x = 0; x < 8; x++) + { + uint8 cr = (uint8) * pSrc++; + int16 crR, crG; + + crR = (cr + ((cr * 103U) >> 8U)) - 179; + pDstR[0] = addAndClamp (pDstR[0], crR); + pDstR[8] = addAndClamp (pDstR[8], crR); + + crG = ((cr * 183U) >> 8U) - 91; + pDstG[0] = subAndClamp (pDstG[0], crG); + pDstG[8] = subAndClamp (pDstG[8], crG); + + ++pDstR; + ++pDstG; + } + + pDstR = pDstR - 8 + 16; + pDstG = pDstG - 8 + 16; + } +} + +/*----------------------------------------------------------------------------*/ +// Convert Y to RGB +static void +copyY (uint8 dstOfs) +{ + uint8 i; + uint8 *pRDst = gMCUBufR + dstOfs; + uint8 *pGDst = gMCUBufG + dstOfs; + uint8 *pBDst = gMCUBufB + dstOfs; + int16 *pSrc = gCoeffBuf; + + for (i = 64; i > 0; i--) + { + uint8 c = (uint8) * pSrc++; + + *pRDst++ = c; + *pGDst++ = c; + *pBDst++ = c; + } +} + +/*----------------------------------------------------------------------------*/ +// Cb convert to RGB and accumulate +static void +convertCb (uint8 dstOfs) +{ + uint8 i; + uint8 *pDstG = gMCUBufG + dstOfs; + uint8 *pDstB = gMCUBufB + dstOfs; + int16 *pSrc = gCoeffBuf; + + for (i = 64; i > 0; i--) + { + uint8 cb = (uint8) * pSrc++; + int16 cbG, cbB; + + cbG = ((cb * 88U) >> 8U) - 44U; + *pDstG = subAndClamp (pDstG[0], cbG); + pDstG++; + + cbB = (cb + ((cb * 198U) >> 8U)) - 227U; + *pDstB = addAndClamp (pDstB[0], cbB); + pDstB++; + } +} + +/*----------------------------------------------------------------------------*/ +// Cr convert to RGB and accumulate +static void +convertCr (uint8 dstOfs) +{ + uint8 i; + uint8 *pDstR = gMCUBufR + dstOfs; + uint8 *pDstG = gMCUBufG + dstOfs; + int16 *pSrc = gCoeffBuf; + + for (i = 64; i > 0; i--) + { + uint8 cr = (uint8) * pSrc++; + int16 crR, crG; + + crR = (cr + ((cr * 103U) >> 8U)) - 179; + *pDstR = addAndClamp (pDstR[0], crR); + pDstR++; + + crG = ((cr * 183U) >> 8U) - 91; + *pDstG = subAndClamp (pDstG[0], crG); + pDstG++; + } +} + +/*----------------------------------------------------------------------------*/ +static void +transformBlock (uint8 mcuBlock) +{ + idctRows (); + idctCols (); + + switch (gScanType) + { + case PJPG_GRAYSCALE: + { + // MCU size: 1, 1 block per MCU + copyY (0); + break; + } + case PJPG_YH1V1: + { + // MCU size: 8x8, 3 blocks per MCU + switch (mcuBlock) + { + case 0: + { + copyY (0); + break; + } + case 1: + { + convertCb (0); + break; + } + case 2: + { + convertCr (0); + break; + } + } + + break; + } + case PJPG_YH1V2: + { + // MCU size: 8x16, 4 blocks per MCU + switch (mcuBlock) + { + case 0: + { + copyY (0); + break; + } + case 1: + { + copyY (128); + break; + } + case 2: + { + upsampleCbV (0, 0); + upsampleCbV (4 * 8, 128); + break; + } + case 3: + { + upsampleCrV (0, 0); + upsampleCrV (4 * 8, 128); + break; + } + } + + break; + } + case PJPG_YH2V1: + { + // MCU size: 16x8, 4 blocks per MCU + switch (mcuBlock) + { + case 0: + { + copyY (0); + break; + } + case 1: + { + copyY (64); + break; + } + case 2: + { + upsampleCbH (0, 0); + upsampleCbH (4, 64); + break; + } + case 3: + { + upsampleCrH (0, 0); + upsampleCrH (4, 64); + break; + } + } + + break; + } + case PJPG_YH2V2: + { + // MCU size: 16x16, 6 blocks per MCU + switch (mcuBlock) + { + case 0: + { + copyY (0); + break; + } + case 1: + { + copyY (64); + break; + } + case 2: + { + copyY (128); + break; + } + case 3: + { + copyY (192); + break; + } + case 4: + { + upsampleCb (0, 0); + upsampleCb (4, 64); + upsampleCb (4 * 8, 128); + upsampleCb (4 + 4 * 8, 192); + break; + } + case 5: + { + upsampleCr (0, 0); + upsampleCr (4, 64); + upsampleCr (4 * 8, 128); + upsampleCr (4 + 4 * 8, 192); + break; + } + } + + break; + } + } +} + +//------------------------------------------------------------------------------ +static void +transformBlockReduce (uint8 mcuBlock) +{ + uint8 c = clamp (PJPG_DESCALE (gCoeffBuf[0]) + 128); + int16 cbG, cbB, crR, crG; + + switch (gScanType) + { + case PJPG_GRAYSCALE: + { + // MCU size: 1, 1 block per MCU + gMCUBufR[0] = c; + break; + } + case PJPG_YH1V1: + { + // MCU size: 8x8, 3 blocks per MCU + switch (mcuBlock) + { + case 0: + { + gMCUBufR[0] = c; + gMCUBufG[0] = c; + gMCUBufB[0] = c; + break; + } + case 1: + { + cbG = ((c * 88U) >> 8U) - 44U; + gMCUBufG[0] = subAndClamp (gMCUBufG[0], cbG); + + cbB = (c + ((c * 198U) >> 8U)) - 227U; + gMCUBufB[0] = addAndClamp (gMCUBufB[0], cbB); + break; + } + case 2: + { + crR = (c + ((c * 103U) >> 8U)) - 179; + gMCUBufR[0] = addAndClamp (gMCUBufR[0], crR); + + crG = ((c * 183U) >> 8U) - 91; + gMCUBufG[0] = subAndClamp (gMCUBufG[0], crG); + break; + } + } + + break; + } + case PJPG_YH1V2: + { + // MCU size: 8x16, 4 blocks per MCU + switch (mcuBlock) + { + case 0: + { + gMCUBufR[0] = c; + gMCUBufG[0] = c; + gMCUBufB[0] = c; + break; + } + case 1: + { + gMCUBufR[128] = c; + gMCUBufG[128] = c; + gMCUBufB[128] = c; + break; + } + case 2: + { + cbG = ((c * 88U) >> 8U) - 44U; + gMCUBufG[0] = subAndClamp (gMCUBufG[0], cbG); + gMCUBufG[128] = subAndClamp (gMCUBufG[128], cbG); + + cbB = (c + ((c * 198U) >> 8U)) - 227U; + gMCUBufB[0] = addAndClamp (gMCUBufB[0], cbB); + gMCUBufB[128] = addAndClamp (gMCUBufB[128], cbB); + + break; + } + case 3: + { + crR = (c + ((c * 103U) >> 8U)) - 179; + gMCUBufR[0] = addAndClamp (gMCUBufR[0], crR); + gMCUBufR[128] = addAndClamp (gMCUBufR[128], crR); + + crG = ((c * 183U) >> 8U) - 91; + gMCUBufG[0] = subAndClamp (gMCUBufG[0], crG); + gMCUBufG[128] = subAndClamp (gMCUBufG[128], crG); + + break; + } + } + break; + } + case PJPG_YH2V1: + { + // MCU size: 16x8, 4 blocks per MCU + switch (mcuBlock) + { + case 0: + { + gMCUBufR[0] = c; + gMCUBufG[0] = c; + gMCUBufB[0] = c; + break; + } + case 1: + { + gMCUBufR[64] = c; + gMCUBufG[64] = c; + gMCUBufB[64] = c; + break; + } + case 2: + { + cbG = ((c * 88U) >> 8U) - 44U; + gMCUBufG[0] = subAndClamp (gMCUBufG[0], cbG); + gMCUBufG[64] = subAndClamp (gMCUBufG[64], cbG); + + cbB = (c + ((c * 198U) >> 8U)) - 227U; + gMCUBufB[0] = addAndClamp (gMCUBufB[0], cbB); + gMCUBufB[64] = addAndClamp (gMCUBufB[64], cbB); + + break; + } + case 3: + { + crR = (c + ((c * 103U) >> 8U)) - 179; + gMCUBufR[0] = addAndClamp (gMCUBufR[0], crR); + gMCUBufR[64] = addAndClamp (gMCUBufR[64], crR); + + crG = ((c * 183U) >> 8U) - 91; + gMCUBufG[0] = subAndClamp (gMCUBufG[0], crG); + gMCUBufG[64] = subAndClamp (gMCUBufG[64], crG); + + break; + } + } + break; + } + case PJPG_YH2V2: + { + // MCU size: 16x16, 6 blocks per MCU + switch (mcuBlock) + { + case 0: + { + gMCUBufR[0] = c; + gMCUBufG[0] = c; + gMCUBufB[0] = c; + break; + } + case 1: + { + gMCUBufR[64] = c; + gMCUBufG[64] = c; + gMCUBufB[64] = c; + break; + } + case 2: + { + gMCUBufR[128] = c; + gMCUBufG[128] = c; + gMCUBufB[128] = c; + break; + } + case 3: + { + gMCUBufR[192] = c; + gMCUBufG[192] = c; + gMCUBufB[192] = c; + break; + } + case 4: + { + cbG = ((c * 88U) >> 8U) - 44U; + gMCUBufG[0] = subAndClamp (gMCUBufG[0], cbG); + gMCUBufG[64] = subAndClamp (gMCUBufG[64], cbG); + gMCUBufG[128] = subAndClamp (gMCUBufG[128], cbG); + gMCUBufG[192] = subAndClamp (gMCUBufG[192], cbG); + + cbB = (c + ((c * 198U) >> 8U)) - 227U; + gMCUBufB[0] = addAndClamp (gMCUBufB[0], cbB); + gMCUBufB[64] = addAndClamp (gMCUBufB[64], cbB); + gMCUBufB[128] = addAndClamp (gMCUBufB[128], cbB); + gMCUBufB[192] = addAndClamp (gMCUBufB[192], cbB); + + break; + } + case 5: + { + crR = (c + ((c * 103U) >> 8U)) - 179; + gMCUBufR[0] = addAndClamp (gMCUBufR[0], crR); + gMCUBufR[64] = addAndClamp (gMCUBufR[64], crR); + gMCUBufR[128] = addAndClamp (gMCUBufR[128], crR); + gMCUBufR[192] = addAndClamp (gMCUBufR[192], crR); + + crG = ((c * 183U) >> 8U) - 91; + gMCUBufG[0] = subAndClamp (gMCUBufG[0], crG); + gMCUBufG[64] = subAndClamp (gMCUBufG[64], crG); + gMCUBufG[128] = subAndClamp (gMCUBufG[128], crG); + gMCUBufG[192] = subAndClamp (gMCUBufG[192], crG); + + break; + } + } + break; + } + } +} + +//------------------------------------------------------------------------------ +static uint8 +decodeNextMCU (void) +{ + uint8 status; + uint8 mcuBlock; + + if (gRestartInterval) + { + if (gRestartsLeft == 0) + { + status = processRestart (); + if (status) + return status; + } + gRestartsLeft--; + } + + for (mcuBlock = 0; mcuBlock < gMaxBlocksPerMCU; mcuBlock++) + { + uint8 componentID = gMCUOrg[mcuBlock]; + uint8 compQuant = gCompQuant[componentID]; + uint8 compDCTab = gCompDCTab[componentID]; + uint8 numExtraBits, compACTab, k; + const int16 *pQ = compQuant ? gQuant1 : gQuant0; + uint16 r, dc; + + uint8 s = + huffDecode (compDCTab ? &gHuffTab1 : &gHuffTab0, + compDCTab ? gHuffVal1 : gHuffVal0); + + r = 0; + numExtraBits = s & 0xF; + if (numExtraBits) + r = getBits2 (numExtraBits); + dc = huffExtend (r, s); + + dc = dc + gLastDC[componentID]; + gLastDC[componentID] = dc; + + gCoeffBuf[0] = dc * pQ[0]; + + compACTab = gCompACTab[componentID]; + + if (gReduce) + { + // Decode, but throw out the AC coefficients in reduce mode. + for (k = 1; k < 64; k++) + { + s = + huffDecode (compACTab ? &gHuffTab3 : &gHuffTab2, + compACTab ? gHuffVal3 : gHuffVal2); + + numExtraBits = s & 0xF; + if (numExtraBits) + getBits2 (numExtraBits); + + r = s >> 4; + s &= 15; + + if (s) + { + if (r) + { + if ((k + r) > 63) + return PJPG_DECODE_ERROR; + + k = (uint8) (k + r); + } + } + else + { + if (r == 15) + { + if ((k + 16) > 64) + return PJPG_DECODE_ERROR; + + k += (16 - 1); // - 1 because the loop counter is k + } + else + break; + } + } + + transformBlockReduce (mcuBlock); + } + else + { + // Decode and dequantize AC coefficients + for (k = 1; k < 64; k++) + { + uint16 extraBits; + + s = + huffDecode (compACTab ? &gHuffTab3 : &gHuffTab2, + compACTab ? gHuffVal3 : gHuffVal2); + + extraBits = 0; + numExtraBits = s & 0xF; + if (numExtraBits) + extraBits = getBits2 (numExtraBits); + + r = s >> 4; + s &= 15; + + if (s) + { + int16 ac; + + if (r) + { + if ((k + r) > 63) + return PJPG_DECODE_ERROR; + + while (r) + { + gCoeffBuf[ZAG[k++]] = 0; + r--; + } + } + + ac = huffExtend (extraBits, s); + + gCoeffBuf[ZAG[k]] = ac * pQ[k]; + } + else + { + if (r == 15) + { + if ((k + 16) > 64) + return PJPG_DECODE_ERROR; + + for (r = 16; r > 0; r--) + gCoeffBuf[ZAG[k++]] = 0; + + k--; // - 1 because the loop counter is k + } + else + break; + } + } + + while (k < 64) + gCoeffBuf[ZAG[k++]] = 0; + + transformBlock (mcuBlock); + } + } + + return 0; +} + +//------------------------------------------------------------------------------ +unsigned char +pjpeg_decode_mcu (void) +{ + uint8 status; + + if (gCallbackStatus) + return gCallbackStatus; + + if (!gNumMCUSRemaining) + return PJPG_NO_MORE_BLOCKS; + + status = decodeNextMCU (); + if ((status) || (gCallbackStatus)) + return gCallbackStatus ? gCallbackStatus : status; + + gNumMCUSRemaining--; + + return 0; +} + +//------------------------------------------------------------------------------ +unsigned char +pjpeg_decode_init (pjpeg_image_info_t * pInfo, + pjpeg_need_bytes_callback_t pNeed_bytes_callback, + void *pCallback_data, unsigned char reduce) +{ + uint8 status; + + pInfo->m_width = 0; + pInfo->m_height = 0; + pInfo->m_comps = 0; + pInfo->m_MCUSPerRow = 0; + pInfo->m_MCUSPerCol = 0; + pInfo->m_scanType = PJPG_GRAYSCALE; + pInfo->m_MCUWidth = 0; + pInfo->m_MCUHeight = 0; + pInfo->m_pMCUBufR = (unsigned char *) 0; + pInfo->m_pMCUBufG = (unsigned char *) 0; + pInfo->m_pMCUBufB = (unsigned char *) 0; + + g_pNeedBytesCallback = pNeed_bytes_callback; + g_pCallback_data = pCallback_data; + gCallbackStatus = 0; + gReduce = reduce; + + status = init (); + if ((status) || (gCallbackStatus)) + return gCallbackStatus ? gCallbackStatus : status; + + status = locateSOFMarker (); + if ((status) || (gCallbackStatus)) + return gCallbackStatus ? gCallbackStatus : status; + + status = initFrame (); + if ((status) || (gCallbackStatus)) + return gCallbackStatus ? gCallbackStatus : status; + + status = initScan (); + if ((status) || (gCallbackStatus)) + return gCallbackStatus ? gCallbackStatus : status; + + pInfo->m_width = gImageXSize; + pInfo->m_height = gImageYSize; + pInfo->m_comps = gCompsInFrame; + pInfo->m_scanType = gScanType; + pInfo->m_MCUSPerRow = gMaxMCUSPerRow; + pInfo->m_MCUSPerCol = gMaxMCUSPerCol; + pInfo->m_MCUWidth = gMaxMCUXSize; + pInfo->m_MCUHeight = gMaxMCUYSize; + pInfo->m_pMCUBufR = gMCUBufR; + pInfo->m_pMCUBufG = gMCUBufG; + pInfo->m_pMCUBufB = gMCUBufB; + + return 0; +} + + +/* + Local Variables: + mode: C + c-file-style: "gnu" + End: +*/ diff --git a/benchies/embench/benchemarks/picojpeg/picojpeg.h b/benchies/embench/benchemarks/picojpeg/picojpeg.h new file mode 100644 index 0000000000..475be398fd --- /dev/null +++ b/benchies/embench/benchemarks/picojpeg/picojpeg.h @@ -0,0 +1,150 @@ +/* This file is part of the Bristol/Embecosm Embedded Benchmark Suite. + + This version, copyright (C) 2014-2019 Embecosm Limited and University of + Bristol + + Contributor Jeremy Bennett + + This file is part of Embench and was formerly part of the Bristol/Embecosm + Embedded Benchmark Suite. + + SPDX-License-Identifier: GPL-3.0-or-later */ + +//------------------------------------------------------------------------------ +// picojpeg - Public domain, Rich Geldreich +//------------------------------------------------------------------------------ +#ifndef PICOJPEG_H +#define PICOJPEG_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +// Error codes + enum + { + PJPG_NO_MORE_BLOCKS = 1, + PJPG_BAD_DHT_COUNTS, + PJPG_BAD_DHT_INDEX, + PJPG_BAD_DHT_MARKER, + PJPG_BAD_DQT_MARKER, + PJPG_BAD_DQT_TABLE, + PJPG_BAD_PRECISION, + PJPG_BAD_HEIGHT, + PJPG_BAD_WIDTH, + PJPG_TOO_MANY_COMPONENTS, + PJPG_BAD_SOF_LENGTH, + PJPG_BAD_VARIABLE_MARKER, + PJPG_BAD_DRI_LENGTH, + PJPG_BAD_SOS_LENGTH, + PJPG_BAD_SOS_COMP_ID, + PJPG_W_EXTRA_BYTES_BEFORE_MARKER, + PJPG_NO_ARITHMITIC_SUPPORT, + PJPG_UNEXPECTED_MARKER, + PJPG_NOT_JPEG, + PJPG_UNSUPPORTED_MARKER, + PJPG_BAD_DQT_LENGTH, + PJPG_TOO_MANY_BLOCKS, + PJPG_UNDEFINED_QUANT_TABLE, + PJPG_UNDEFINED_HUFF_TABLE, + PJPG_NOT_SINGLE_SCAN, + PJPG_UNSUPPORTED_COLORSPACE, + PJPG_UNSUPPORTED_SAMP_FACTORS, + PJPG_DECODE_ERROR, + PJPG_BAD_RESTART_MARKER, + PJPG_ASSERTION_ERROR, + PJPG_BAD_SOS_SPECTRAL, + PJPG_BAD_SOS_SUCCESSIVE, + PJPG_STREAM_READ_ERROR, + PJPG_NOTENOUGHMEM, + PJPG_UNSUPPORTED_COMP_IDENT, + PJPG_UNSUPPORTED_QUANT_TABLE, + PJPG_UNSUPPORTED_MODE, // picojpeg doesn't support progressive JPEG's + }; + +// Scan types + typedef enum + { + PJPG_GRAYSCALE, + PJPG_YH1V1, + PJPG_YH2V1, + PJPG_YH1V2, + PJPG_YH2V2 + } pjpeg_scan_type_t; + + typedef struct + { + // Image resolution + int m_width; + int m_height; + + // Number of components (1 or 3) + int m_comps; + + // Total number of minimum coded units (MCU's) per row/col. + int m_MCUSPerRow; + int m_MCUSPerCol; + + // Scan type + pjpeg_scan_type_t m_scanType; + + // MCU width/height in pixels (each is either 8 or 16 depending on the scan type) + int m_MCUWidth; + int m_MCUHeight; + + // m_pMCUBufR, m_pMCUBufG, and m_pMCUBufB are pointers to internal MCU Y or RGB pixel component buffers. + // Each time pjpegDecodeMCU() is called successfully these buffers will be filled with 8x8 pixel blocks of Y or RGB pixels. + // Each MCU consists of (m_MCUWidth/8)*(m_MCUHeight/8) Y/RGB blocks: 1 for greyscale/no subsampling, 2 for H1V2/H2V1, or 4 blocks for H2V2 sampling factors. + // Each block is a contiguous array of 64 (8x8) bytes of a single component: either Y for grayscale images, or R, G or B components for color images. + // + // The 8x8 pixel blocks are organized in these byte arrays like this: + // + // PJPG_GRAYSCALE: Each MCU is decoded to a single block of 8x8 grayscale pixels. + // Only the values in m_pMCUBufR are valid. Each 8 bytes is a row of pixels (raster order: left to right, top to bottom) from the 8x8 block. + // + // PJPG_H1V1: Each MCU contains is decoded to a single block of 8x8 RGB pixels. + // + // PJPG_YH2V1: Each MCU is decoded to 2 blocks, or 16x8 pixels. + // The 2 RGB blocks are at byte offsets: 0, 64 + // + // PJPG_YH1V2: Each MCU is decoded to 2 blocks, or 8x16 pixels. + // The 2 RGB blocks are at byte offsets: 0, + // 128 + // + // PJPG_YH2V2: Each MCU is decoded to 4 blocks, or 16x16 pixels. + // The 2x2 block array is organized at byte offsets: 0, 64, + // 128, 192 + // + // It is up to the caller to copy or blit these pixels from these buffers into the destination bitmap. + unsigned char *m_pMCUBufR; + unsigned char *m_pMCUBufG; + unsigned char *m_pMCUBufB; + } pjpeg_image_info_t; + + typedef unsigned char (*pjpeg_need_bytes_callback_t) (unsigned char *pBuf, + unsigned char + buf_size, + unsigned char + *pBytes_actually_read, + void *pCallback_data); + +// Initializes the decompressor. Returns 0 on success, or one of the above error codes on failure. +// pNeed_bytes_callback will be called to fill the decompressor's internal input buffer. +// If reduce is 1, only the first pixel of each block will be decoded. This mode is much faster because it skips the AC dequantization, IDCT and chroma upsampling of every image pixel. +// Not thread safe. + unsigned char pjpeg_decode_init (pjpeg_image_info_t * pInfo, + pjpeg_need_bytes_callback_t + pNeed_bytes_callback, void *pCallback_data, + unsigned char reduce); + +// Decompresses the file's next MCU. Returns 0 on success, PJPG_NO_MORE_BLOCKS if no more blocks are available, or an error code. +// Must be called a total of m_MCUSPerRow*m_MCUSPerCol times to completely decompress the image. +// Not thread safe. + unsigned char pjpeg_decode_mcu (void); + +#ifdef __cplusplus +} +#endif + +#endif // PICOJPEG_H diff --git a/benchies/embench/benchemarks/picojpeg/picojpeg_test.c b/benchies/embench/benchemarks/picojpeg/picojpeg_test.c new file mode 100644 index 0000000000..595257dfc6 --- /dev/null +++ b/benchies/embench/benchemarks/picojpeg/picojpeg_test.c @@ -0,0 +1,214 @@ +/* BEEBS picobenchmark benchmark + + This version, copyright (C) 2014-2019 Embecosm Limited and University of + Bristol + + Contributor James Pallister + Contributor Jeremy Bennett + + This file is part of Embench and was formerly part of the Bristol/Embecosm + Embedded Benchmark Suite. + + SPDX-License-Identifier: GPL-3.0-or-later */ + +#include "../../src/support.h" +#include "picojpeg.h" + +#include + +/* This scale factor will be changed to equalise the runtime of the + benchmarks. */ +#define LOCAL_SCALE_FACTOR 6 + +const unsigned char jpeg_data[] = { + 0xff, 0xd8, 0xff, 0xe0, 0x00, 0x10, 0x4a, 0x46, + 0x49, 0x46, 0x00, 0x01, 0x01, 0x01, 0x00, 0x48, + 0x00, 0x48, 0x00, 0x00, 0xff, 0xdb, 0x00, 0x43, + 0x00, 0x50, 0x37, 0x3c, 0x46, 0x3c, 0x32, 0x50, + 0x46, 0x41, 0x46, 0x5a, 0x55, 0x50, 0x5f, 0x78, + 0xc8, 0x82, 0x78, 0x6e, 0x6e, 0x78, 0xf5, 0xaf, + 0xb9, 0x91, 0xc8, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xdb, 0x00, 0x43, 0x01, 0x55, 0x5a, + 0x5a, 0x78, 0x69, 0x78, 0xeb, 0x82, 0x82, 0xeb, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0x00, 0x11, 0x08, 0x00, 0x40, 0x00, 0x33, 0x03, + 0x01, 0x11, 0x00, 0x02, 0x11, 0x01, 0x03, 0x11, + 0x01, 0xff, 0xc4, 0x00, 0x18, 0x00, 0x00, 0x03, + 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x03, 0x00, 0x04, 0xff, 0xc4, 0x00, 0x26, 0x10, + 0x00, 0x02, 0x02, 0x01, 0x03, 0x03, 0x04, 0x03, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x02, 0x00, 0x11, 0x03, 0x12, 0x21, 0x31, + 0x41, 0x61, 0x71, 0x04, 0x22, 0x53, 0x91, 0x13, + 0x23, 0x51, 0x62, 0xff, 0xc4, 0x00, 0x15, 0x01, + 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0xff, 0xc4, 0x00, 0x14, 0x11, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xda, 0x00, 0x0c, 0x03, 0x01, 0x00, 0x02, + 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00, 0xc7, 0x88, + 0x0b, 0x28, 0x4d, 0x66, 0xe1, 0x02, 0xcf, 0x58, + 0x05, 0x45, 0x88, 0x00, 0xa9, 0x10, 0x34, 0x0e, + 0xaf, 0x6f, 0x68, 0x54, 0x33, 0x64, 0x03, 0x61, + 0x02, 0x6a, 0x49, 0xdb, 0x49, 0x84, 0x59, 0x50, + 0x91, 0x50, 0xa0, 0x3d, 0xa4, 0x80, 0x7c, 0x88, + 0x18, 0xd5, 0x48, 0x05, 0x09, 0x43, 0xeb, 0xff, + 0x00, 0x2b, 0xf5, 0x02, 0x78, 0xd4, 0x1c, 0xac, + 0x48, 0x10, 0x8e, 0xb5, 0x55, 0xa8, 0x0c, 0xa5, + 0x2f, 0xdb, 0x52, 0x2a, 0x19, 0x53, 0xf6, 0x82, + 0x04, 0xa1, 0x0e, 0x45, 0xf8, 0x84, 0x0d, 0xad, + 0x7e, 0x21, 0x20, 0xd0, 0x30, 0x04, 0x93, 0x5c, + 0x99, 0x43, 0xe2, 0xc6, 0x57, 0x20, 0xd4, 0xd7, + 0x7d, 0x20, 0x3a, 0xe1, 0x40, 0xf6, 0x49, 0xf1, + 0x20, 0xa3, 0x8b, 0x17, 0xc5, 0x09, 0x47, 0x26, + 0x35, 0x05, 0xb5, 0x1e, 0x20, 0x75, 0x02, 0x95, + 0xc0, 0xfa, 0x81, 0xcf, 0x52, 0x0c, 0x6c, 0x0d, + 0xa0, 0x25, 0xbd, 0xdd, 0xd1, 0xf3, 0x2a, 0x28, + 0x43, 0xb0, 0x04, 0x0e, 0x3a, 0xdc, 0x29, 0xb2, + 0x13, 0xf8, 0x6a, 0x11, 0x25, 0x53, 0x22, 0xa9, + 0x7d, 0xe0, 0x2e, 0xa8, 0x06, 0xc1, 0xda, 0xa0, + 0x29, 0x21, 0x4d, 0x30, 0x35, 0x2a, 0x28, 0xb9, + 0x17, 0x85, 0x06, 0x15, 0x50, 0x97, 0x8c, 0xd8, + 0xef, 0x20, 0xe5, 0x01, 0xf9, 0xd3, 0x52, 0xa1, + 0xb5, 0x0e, 0xb0, 0x14, 0x90, 0x39, 0x32, 0x28, + 0xe2, 0x60, 0xd9, 0x17, 0xcc, 0xa2, 0xd9, 0xb1, + 0x02, 0x35, 0x58, 0x1e, 0x60, 0x0c, 0x58, 0x95, + 0x06, 0xa6, 0x20, 0xf8, 0x90, 0x3b, 0x67, 0x41, + 0xb0, 0xb3, 0x02, 0x4f, 0x9c, 0x55, 0x40, 0x8e, + 0xb5, 0xfe, 0x09, 0x51, 0x12, 0xd7, 0x01, 0xfd, + 0x3b, 0x11, 0x99, 0x7b, 0x98, 0x55, 0x7d, 0x4b, + 0xbb, 0x64, 0x00, 0xec, 0xbd, 0x04, 0x05, 0x45, + 0x62, 0x36, 0xb2, 0x3b, 0x42, 0x1b, 0x2a, 0x1c, + 0x40, 0x74, 0xb8, 0x11, 0x06, 0x00, 0xb8, 0x1f, + 0xff, 0xd9 +}; + +unsigned jpeg_off = 0; + +#define MIN(a,b) ((a)<(b)?(a):(b)) + +unsigned char +pjpeg_need_bytes_callback (unsigned char *pBuf, + unsigned char buf_size, + unsigned char *pBytes_actually_read, + void *pCallback_data) +{ + unsigned n = MIN (sizeof (jpeg_data) - jpeg_off, buf_size); + + memcpy (pBuf, &jpeg_data[jpeg_off], n); + *pBytes_actually_read = (unsigned char) n; + jpeg_off += n; + return 0; +} + + +pjpeg_image_info_t pInfo; + +int +verify_benchmark (int res __attribute ((unused))) +{ + static const unsigned char r_ref[64] = { + 33, 33, 33, 33, 33, 33, 33, 33, + 32, 32, 32, 32, 32, 32, 32, 32, + 29, 29, 29, 29, 29, 29, 29, 29, + 25, 25, 25, 25, 25, 25, 25, 25, + 21, 21, 21, 21, 21, 21, 21, 21, + 17, 17, 17, 17, 17, 17, 17, 17, + 14, 14, 14, 14, 14, 14, 14, 14, + 13, 13, 13, 13, 13, 13, 13, 13 + }; + static const unsigned char g_ref[64] = { + 53, 53, 53, 53, 53, 53, 53, 53, + 52, 52, 52, 52, 52, 52, 52, 52, + 49, 49, 49, 49, 49, 49, 49, 49, + 45, 45, 45, 45, 45, 45, 45, 45, + 41, 41, 41, 41, 41, 41, 41, 41, + 37, 37, 37, 37, 37, 37, 37, 37, + 34, 34, 34, 34, 34, 34, 34, 34, + 33, 33, 33, 33, 33, 33, 33, 33 + }; + static const unsigned char b_ref[64] = { + 67, 67, 67, 67, 67, 67, 67, 67, + 66, 66, 66, 66, 66, 66, 66, 66, + 63, 63, 63, 63, 63, 63, 63, 63, + 59, 59, 59, 59, 59, 59, 59, 59, + 55, 55, 55, 55, 55, 55, 55, 55, + 51, 51, 51, 51, 51, 51, 51, 51, + 48, 48, 48, 48, 48, 48, 48, 48, + 47, 47, 47, 47, 47, 47, 47, 47 + }; + + return (0 == memcmp (pInfo.m_pMCUBufR, r_ref, 64)) + && (0 == memcmp (pInfo.m_pMCUBufG, g_ref, 64)) + && (0 == memcmp (pInfo.m_pMCUBufB, b_ref, 64)); +} + + +void +initialise_benchmark (void) +{ +} + + +static int benchmark_body (int rpt); + +void +warm_caches (int heat) +{ + int res = benchmark_body (heat); + + return; +} + + +int +benchmark (void) +{ + return benchmark_body (LOCAL_SCALE_FACTOR * CPU_MHZ); +} + + +static int __attribute__ ((noinline)) +benchmark_body (int rpt) +{ + int i; + + for (i = 0; i < rpt; i++) + { + unsigned char status; + + jpeg_off = 0; + + status = pjpeg_decode_init (&pInfo, pjpeg_need_bytes_callback, 0, 0); + + for (;;) + { + status = pjpeg_decode_mcu (); + + if (status == PJPG_NO_MORE_BLOCKS) + break; + } + } + + return 0; +} + + +/* + Local Variables: + mode: C + c-file-style: "gnu" + End: +*/ diff --git a/benchies/embench/benchemarks/primecount/primecount.c b/benchies/embench/benchemarks/primecount/primecount.c new file mode 100644 index 0000000000..05a40255d9 --- /dev/null +++ b/benchies/embench/benchemarks/primecount/primecount.c @@ -0,0 +1,181 @@ +/* This version, copyright (C) 2014-2021 Embecosm Limited and University of + Bristol + + Contributor Paolo Savini + + This file is part of Embench. + + SPDX-License-Identifier: GPL-3.0-or-later + + The original version by Bruce Hoult can be found here: + + http://hoult.org/primes.txt + + and was released under the following license, disclaimers, and copyright: + + Copyright 2016-2021 Bruce hoult bruce@hoult.org + + Permission is hereby granted, free of charge, to any person obtaining a copy of + this software and associated documentation files (the "Software"), to deal in + the Software without restriction, including without limitation the rights to + use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is furnished to do + so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Program to count primes. I wanted something that could run in 16 KB but took enough + time to measure on a modern x86 and is not susceptible to optimizer tricks. + Code size is for just the countPrimes() function with gcc -O. + + Original x86&ARM data 2016, received user contributions 2019&2020 from eevblog members. + + WARNING: These results have not been calculated with the Embench infrastructure. + The value of the parameter SZ and the methodolgy to calculate size and execution + time are different in Embench, therefore these numbers aren't suitable for a direct + comparison with the Embench results for the same architectures. + + SZ = 1000 -> 3713160 primes, all primes up to 7919^2 = 62710561 + 2.735 sec i7 8650U @ 4.2 GHz 242 bytes 11.5 billion clocks + 2.795 sec Mac Mini M1 @ 3.2 GHz 212 bytes 8.9 billion clocks + 2.810 sec Mac Mini M1 arm64 Ubuntu in VM 280 bytes 9.0 billion clocks + 2.872 sec i7 6700K @ 4.2 GHz 240 bytes 12.1 billion clocks + 2.925 sec Mac Mini M1 @ 3.2 GHz Rosetta 208 bytes 9.4 billion clocks + 3.448 sec Ryzen 5 4500U @ 4.0 GHz WSL2 242 bytes 13.8 billion clocks + 3.505 sec Xeon Plat 8151 @ 4.0 GHz (AWS z1d) 244 bytes 14.0 billion clocks + 3.515 sec Threadripper 2990WX @ 4.2 GHz 242 bytes 14.8 billion clocks + 3.836 sec i7 4700MQ @ 3.4 GHz 258 bytes 13.0 billion clocks + 3.972 sec i7 8650U @ 4.2 GHz webasm 277 bytes 16.7 billion clocks + 4.868 sec i7 3770 @ 3.9 GHz 240 bytes 19.0 billion clocks + 6.377 sec AWS C6g graviton2 A64 @ 2.5 GHz 276 bytes 15.9 billion clocks + 6.757 sec M1 Mini, qemu-riscv64 in UbuntuVM 216 bytes 23.0 billion clocks + 8.538 sec NXP LX2160A A72 @ 2 GHz 260 bytes 17.1 billion clocks + 9.692 sec RISC-V Fedora in qemu in VM on M1 208 bytes 31.0 billion clocks + 9.740 sec i7 6700K qemu-riscv32 178 bytes 40.9 billion clocks + 10.046 sec i7 8650U @ 4.2 GHz qemu-riscv32 190 bytes 42.2 billion clocks + 11.190 sec Pi4 Cortex A72 @ 1.5 GHz T32 232 bytes 16.8 billion clocks + 11.445 sec Odroid XU4 A15 @ 2 GHz T32 204 bytes 22.9 billion clocks + 12.115 sec Pi4 Cortex A72 @ 1.5 GHz A64 300 bytes 18.2 billion clocks + 12.605 sec Pi4 Cortex A72 @ 1.5 GHz A32 300 bytes 18.9 billion clocks + 13.721 sec RISC-V Fedora in qemu on 2990wx 208 bytes 57.6 billion clocks + 14.111 sec Beagle-X15 A15 @ 1.5 GHz A32 348 bytes 21.2 billion clocks + 14.341 sec Beagle-X15 A15 @ 1.5 GHz T32 224 bytes 21.5 billion clocks + 19.500 sec Odroid C2 A53 @ 1.536 GHz A64 276 bytes 30.0 billion clocks + 22.719 sec BeagleV Starlight RISCV U74 @ 1.0 GHz 208 bytes 22.7 billion clocks + 23.940 sec Odroid C2 A53 @ 1.536 GHz T32 204 bytes 36.8 billion clocks + 24.636 sec i7 6700K qemu-arm 204 bytes 103.5 billion clocks + 25.060 sec i7 6700K qemu-aarch64 276 bytes 105.3 billion clocks + 27.196 sec Teensy 4.0 Cortex M7 @ 960 MHz 228 bytes 26.1 billion clocks + 27.480 sec HiFive Unleashed RISCV U54 @ 1.45 GHz 228 bytes 39.8 billion clocks + 30.420 sec Pi3 Cortex A53 @ 1.2 GHz T32 204 bytes 36.5 billion clocks + 36.652 sec Allwinner N1 C906 RV64 @ 1.008 GHz 224 bytes 36.9 billion clocks + 39.840 sec HiFive Unl RISCV U54 @ 1.0 GHz 228 bytes 39.8 billion clocks + 43.516 sec Teensy 4.0 Cortex M7 @ 600 MHz 228 bytes 26.1 billion clocks + 47.910 sec Pi2 Cortex A7 @ 900 MHz T32 204 bytes 42.1 billion clocks + 48.206 sec Zynq-7010 Cortex A9 @ 650MHz 248 bytes 31.3 billion clocks + 112.163 sec HiFive1 RISCV E31 @ 320 MHz 178 bytes 35.9 billion clocks + 261.068 sec esp32/Arduino @ 240 MHz ??? bytes 62.7 billion clocks + 294.749 sec chipKIT Pro MZ pic32 @ 200 MHz ??? bytes 58.9 billion clocks + 306.988 sec esp8266 @ 160 MHz ??? bytes 49.1 billion clocks + 309.251 sec BlackPill Cortex M4F @ 168 MHz 228 bytes 52.0 billion clocks + 927.547 sec BluePill Cortex M3 @ 72 MHz 228 bytes 66.8 billion clocks + 13449.513 sec AVR ATmega2560 @ 20 MHz 318 bytes 269.0 billion clocks */ + +#include "../../src/support.h" + +#define LOCAL_SCALE_FACTOR 1 + +#include +#include +#include + +/* We reduced the quantity of prime numbers to find in order to have an + * execution time as close as possible to 4000 ms for the baseline */ +#define SZ 42 +/* Number of prime numbers we expect to find */ +#define NPRIMES 3512 + +int32_t countPrimes(){ + int32_t primes[SZ], sieve[SZ]; + int nSieve = 0; + primes[0] = 2; sieve[0] = 4; ++nSieve; + int32_t nPrimes = 1, trial = 3, sqr=2; + while (1){ + while (sqr*sqr <= trial) ++sqr; + --sqr; + for (int i=0; i sqr) goto found_prime; + while (sieve[i] < trial) sieve[i] += primes[i]; + if (sieve[i] == trial) goto try_next; + } + break; + found_prime: + if (nSieve < SZ){ + primes[nSieve] = trial; + sieve[nSieve] = trial*trial; + ++nSieve; + } + ++nPrimes; + try_next: + trial+=1; + } + return nPrimes; +} + +static int benchmark_body (int rpt); + +void +warm_caches (int heat) +{ + int res = benchmark_body (heat); + + return; +} + +int +benchmark (void) +{ + return benchmark_body (LOCAL_SCALE_FACTOR * CPU_MHZ); +} + +static int __attribute__ ((noinline)) +benchmark_body (int rpt) +{ + int i, r = 0; + + for (i = 0; i < rpt; ++i) + { + r = countPrimes(); + } + + return r; +} + +int verify_benchmark (int result); + +void +initialise_benchmark (void) +{ +} + +int +verify_benchmark (int r) +{ + return NPRIMES == r; +} + + +/* + Local Variables: + mode: C + c-file-style: "gnu" + End: +*/ diff --git a/benchies/embench/benchemarks/qrduino/ecctable.h b/benchies/embench/benchemarks/qrduino/ecctable.h new file mode 100644 index 0000000000..04ac03a9fb --- /dev/null +++ b/benchies/embench/benchemarks/qrduino/ecctable.h @@ -0,0 +1,65 @@ +/* BEEBS qrduino benchmark + + This version, copyright (C) 2014-2019 Embecosm Limited and University of + Bristol + + Contributor James Pallister + Contributor Jeremy Bennett + + This file is part of Embench and was formerly part of the Bristol/Embecosm + Embedded Benchmark Suite. + + SPDX-License-Identifier: GPL-3.0-or-later + + Original code from: https://github.com/tz1/qrduino */ + +static const unsigned char eccblocks[] PROGMEM = { + 1, 0, 19, 7, 1, 0, 16, 10, 1, 0, 13, 13, 1, 0, 9, 17, + 1, 0, 34, 10, 1, 0, 28, 16, 1, 0, 22, 22, 1, 0, 16, 28, + 1, 0, 55, 15, 1, 0, 44, 26, 2, 0, 17, 18, 2, 0, 13, 22, + 1, 0, 80, 20, 2, 0, 32, 18, 2, 0, 24, 26, 4, 0, 9, 16, + 1, 0, 108, 26, 2, 0, 43, 24, 2, 2, 15, 18, 2, 2, 11, 22, + 2, 0, 68, 18, 4, 0, 27, 16, 4, 0, 19, 24, 4, 0, 15, 28, + 2, 0, 78, 20, 4, 0, 31, 18, 2, 4, 14, 18, 4, 1, 13, 26, + 2, 0, 97, 24, 2, 2, 38, 22, 4, 2, 18, 22, 4, 2, 14, 26, + 2, 0, 116, 30, 3, 2, 36, 22, 4, 4, 16, 20, 4, 4, 12, 24, + 2, 2, 68, 18, 4, 1, 43, 26, 6, 2, 19, 24, 6, 2, 15, 28, + 4, 0, 81, 20, 1, 4, 50, 30, 4, 4, 22, 28, 3, 8, 12, 24, + 2, 2, 92, 24, 6, 2, 36, 22, 4, 6, 20, 26, 7, 4, 14, 28, + 4, 0, 107, 26, 8, 1, 37, 22, 8, 4, 20, 24, 12, 4, 11, 22, + 3, 1, 115, 30, 4, 5, 40, 24, 11, 5, 16, 20, 11, 5, 12, 24, + 5, 1, 87, 22, 5, 5, 41, 24, 5, 7, 24, 30, 11, 7, 12, 24, + 5, 1, 98, 24, 7, 3, 45, 28, 15, 2, 19, 24, 3, 13, 15, 30, + 1, 5, 107, 28, 10, 1, 46, 28, 1, 15, 22, 28, 2, 17, 14, 28, + 5, 1, 120, 30, 9, 4, 43, 26, 17, 1, 22, 28, 2, 19, 14, 28, + 3, 4, 113, 28, 3, 11, 44, 26, 17, 4, 21, 26, 9, 16, 13, 26, + 3, 5, 107, 28, 3, 13, 41, 26, 15, 5, 24, 30, 15, 10, 15, 28, + 4, 4, 116, 28, 17, 0, 42, 26, 17, 6, 22, 28, 19, 6, 16, 30, + 2, 7, 111, 28, 17, 0, 46, 28, 7, 16, 24, 30, 34, 0, 13, 24, + 4, 5, 121, 30, 4, 14, 47, 28, 11, 14, 24, 30, 16, 14, 15, 30, + 6, 4, 117, 30, 6, 14, 45, 28, 11, 16, 24, 30, 30, 2, 16, 30, + 8, 4, 106, 26, 8, 13, 47, 28, 7, 22, 24, 30, 22, 13, 15, 30, + 10, 2, 114, 28, 19, 4, 46, 28, 28, 6, 22, 28, 33, 4, 16, 30, + 8, 4, 122, 30, 22, 3, 45, 28, 8, 26, 23, 30, 12, 28, 15, 30, + 3, 10, 117, 30, 3, 23, 45, 28, 4, 31, 24, 30, 11, 31, 15, 30, + 7, 7, 116, 30, 21, 7, 45, 28, 1, 37, 23, 30, 19, 26, 15, 30, + 5, 10, 115, 30, 19, 10, 47, 28, 15, 25, 24, 30, 23, 25, 15, 30, + 13, 3, 115, 30, 2, 29, 46, 28, 42, 1, 24, 30, 23, 28, 15, 30, + 17, 0, 115, 30, 10, 23, 46, 28, 10, 35, 24, 30, 19, 35, 15, 30, + 17, 1, 115, 30, 14, 21, 46, 28, 29, 19, 24, 30, 11, 46, 15, 30, + 13, 6, 115, 30, 14, 23, 46, 28, 44, 7, 24, 30, 59, 1, 16, 30, + 12, 7, 121, 30, 12, 26, 47, 28, 39, 14, 24, 30, 22, 41, 15, 30, + 6, 14, 121, 30, 6, 34, 47, 28, 46, 10, 24, 30, 2, 64, 15, 30, + 17, 4, 122, 30, 29, 14, 46, 28, 49, 10, 24, 30, 24, 46, 15, 30, + 4, 18, 122, 30, 13, 32, 46, 28, 48, 14, 24, 30, 42, 32, 15, 30, + 20, 4, 117, 30, 40, 7, 47, 28, 43, 22, 24, 30, 10, 67, 15, 30, + 19, 6, 118, 30, 18, 31, 47, 28, 34, 34, 24, 30, 20, 61, 15, 30, +}; + + +/* + Local Variables: + mode: C + c-file-style: "gnu" + End: +*/ diff --git a/benchies/embench/benchemarks/qrduino/qrbits.h b/benchies/embench/benchemarks/qrduino/qrbits.h new file mode 100644 index 0000000000..c2ce216c25 --- /dev/null +++ b/benchies/embench/benchemarks/qrduino/qrbits.h @@ -0,0 +1,26 @@ +/* BEEBS qrduino benchmark + + This version, copyright (C) 2014-2019 Embecosm Limited and University of + Bristol + + Contributor James Pallister + Contributor Jeremy Bennett + + This file is part of Embench and was formerly part of the Bristol/Embecosm + Embedded Benchmark Suite. + + SPDX-License-Identifier: GPL-3.0-or-later + + Original code from: https://github.com/tz1/qrduino */ + +#define QRBIT(x,y) ( ( qrframe[((x)>>3) + (y) * WDB] >> (7-((x) & 7 ))) & 1 ) +#define SETQRBIT(x,y) qrframe[((x)>>3) + (y) * WDB] |= 0x80 >> ((x) & 7) +#define TOGQRBIT(x,y) qrframe[((x)>>3) + (y) * WDB] ^= 0x80 >> ((x) & 7) + + +/* + Local Variables: + mode: C + c-file-style: "gnu" + End: +*/ diff --git a/benchies/embench/benchemarks/qrduino/qrencode.c b/benchies/embench/benchemarks/qrduino/qrencode.c new file mode 100644 index 0000000000..e03e8308dc --- /dev/null +++ b/benchies/embench/benchemarks/qrduino/qrencode.c @@ -0,0 +1,645 @@ +/* BEEBS qrduino benchmark + + This version, copyright (C) 2014-2019 Embecosm Limited and University of + Bristol + + Contributor James Pallister + Contributor Jeremy Bennett + + This file is part of Embench and was formerly part of the Bristol/Embecosm + Embedded Benchmark Suite. + + SPDX-License-Identifier: GPL-3.0-or-later + + Original code from: https://github.com/tz1/qrduino */ + +#include + +#include "qrencode.h" + +extern unsigned char neccblk1; +extern unsigned char neccblk2; +extern unsigned char datablkw; +extern unsigned char eccblkwid; +extern unsigned char VERSION; +extern unsigned char ECCLEVEL; +extern unsigned char WD, WDB; +#ifndef USEPRECALC +// These are malloced by initframe +extern unsigned char *rlens; +extern unsigned char *framebase; +extern unsigned char *framask; +#else +extern unsigned char rlens[]; +extern unsigned char framebase[] PROGMEM; +extern unsigned char framask[] PROGMEM; +#endif + +//======================================================================== +// Reed Solomon error correction +static unsigned +modnn (unsigned x) +{ + while (x >= 255) + { + x -= 255; + x = (x >> 8) + (x & 255); + } + return x; +} + +#ifndef RTGENEXPLOG +static const unsigned char g0log[256] PROGMEM = { + 0xff, 0x00, 0x01, 0x19, 0x02, 0x32, 0x1a, 0xc6, 0x03, 0xdf, 0x33, 0xee, + 0x1b, 0x68, 0xc7, 0x4b, + 0x04, 0x64, 0xe0, 0x0e, 0x34, 0x8d, 0xef, 0x81, 0x1c, 0xc1, 0x69, 0xf8, + 0xc8, 0x08, 0x4c, 0x71, + 0x05, 0x8a, 0x65, 0x2f, 0xe1, 0x24, 0x0f, 0x21, 0x35, 0x93, 0x8e, 0xda, + 0xf0, 0x12, 0x82, 0x45, + 0x1d, 0xb5, 0xc2, 0x7d, 0x6a, 0x27, 0xf9, 0xb9, 0xc9, 0x9a, 0x09, 0x78, + 0x4d, 0xe4, 0x72, 0xa6, + 0x06, 0xbf, 0x8b, 0x62, 0x66, 0xdd, 0x30, 0xfd, 0xe2, 0x98, 0x25, 0xb3, + 0x10, 0x91, 0x22, 0x88, + 0x36, 0xd0, 0x94, 0xce, 0x8f, 0x96, 0xdb, 0xbd, 0xf1, 0xd2, 0x13, 0x5c, + 0x83, 0x38, 0x46, 0x40, + 0x1e, 0x42, 0xb6, 0xa3, 0xc3, 0x48, 0x7e, 0x6e, 0x6b, 0x3a, 0x28, 0x54, + 0xfa, 0x85, 0xba, 0x3d, + 0xca, 0x5e, 0x9b, 0x9f, 0x0a, 0x15, 0x79, 0x2b, 0x4e, 0xd4, 0xe5, 0xac, + 0x73, 0xf3, 0xa7, 0x57, + 0x07, 0x70, 0xc0, 0xf7, 0x8c, 0x80, 0x63, 0x0d, 0x67, 0x4a, 0xde, 0xed, + 0x31, 0xc5, 0xfe, 0x18, + 0xe3, 0xa5, 0x99, 0x77, 0x26, 0xb8, 0xb4, 0x7c, 0x11, 0x44, 0x92, 0xd9, + 0x23, 0x20, 0x89, 0x2e, + 0x37, 0x3f, 0xd1, 0x5b, 0x95, 0xbc, 0xcf, 0xcd, 0x90, 0x87, 0x97, 0xb2, + 0xdc, 0xfc, 0xbe, 0x61, + 0xf2, 0x56, 0xd3, 0xab, 0x14, 0x2a, 0x5d, 0x9e, 0x84, 0x3c, 0x39, 0x53, + 0x47, 0x6d, 0x41, 0xa2, + 0x1f, 0x2d, 0x43, 0xd8, 0xb7, 0x7b, 0xa4, 0x76, 0xc4, 0x17, 0x49, 0xec, + 0x7f, 0x0c, 0x6f, 0xf6, + 0x6c, 0xa1, 0x3b, 0x52, 0x29, 0x9d, 0x55, 0xaa, 0xfb, 0x60, 0x86, 0xb1, + 0xbb, 0xcc, 0x3e, 0x5a, + 0xcb, 0x59, 0x5f, 0xb0, 0x9c, 0xa9, 0xa0, 0x51, 0x0b, 0xf5, 0x16, 0xeb, + 0x7a, 0x75, 0x2c, 0xd7, + 0x4f, 0xae, 0xd5, 0xe9, 0xe6, 0xe7, 0xad, 0xe8, 0x74, 0xd6, 0xf4, 0xea, + 0xa8, 0x50, 0x58, 0xaf, +}; + +static const unsigned char g0exp[256] PROGMEM = { + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1d, 0x3a, 0x74, 0xe8, + 0xcd, 0x87, 0x13, 0x26, + 0x4c, 0x98, 0x2d, 0x5a, 0xb4, 0x75, 0xea, 0xc9, 0x8f, 0x03, 0x06, 0x0c, + 0x18, 0x30, 0x60, 0xc0, + 0x9d, 0x27, 0x4e, 0x9c, 0x25, 0x4a, 0x94, 0x35, 0x6a, 0xd4, 0xb5, 0x77, + 0xee, 0xc1, 0x9f, 0x23, + 0x46, 0x8c, 0x05, 0x0a, 0x14, 0x28, 0x50, 0xa0, 0x5d, 0xba, 0x69, 0xd2, + 0xb9, 0x6f, 0xde, 0xa1, + 0x5f, 0xbe, 0x61, 0xc2, 0x99, 0x2f, 0x5e, 0xbc, 0x65, 0xca, 0x89, 0x0f, + 0x1e, 0x3c, 0x78, 0xf0, + 0xfd, 0xe7, 0xd3, 0xbb, 0x6b, 0xd6, 0xb1, 0x7f, 0xfe, 0xe1, 0xdf, 0xa3, + 0x5b, 0xb6, 0x71, 0xe2, + 0xd9, 0xaf, 0x43, 0x86, 0x11, 0x22, 0x44, 0x88, 0x0d, 0x1a, 0x34, 0x68, + 0xd0, 0xbd, 0x67, 0xce, + 0x81, 0x1f, 0x3e, 0x7c, 0xf8, 0xed, 0xc7, 0x93, 0x3b, 0x76, 0xec, 0xc5, + 0x97, 0x33, 0x66, 0xcc, + 0x85, 0x17, 0x2e, 0x5c, 0xb8, 0x6d, 0xda, 0xa9, 0x4f, 0x9e, 0x21, 0x42, + 0x84, 0x15, 0x2a, 0x54, + 0xa8, 0x4d, 0x9a, 0x29, 0x52, 0xa4, 0x55, 0xaa, 0x49, 0x92, 0x39, 0x72, + 0xe4, 0xd5, 0xb7, 0x73, + 0xe6, 0xd1, 0xbf, 0x63, 0xc6, 0x91, 0x3f, 0x7e, 0xfc, 0xe5, 0xd7, 0xb3, + 0x7b, 0xf6, 0xf1, 0xff, + 0xe3, 0xdb, 0xab, 0x4b, 0x96, 0x31, 0x62, 0xc4, 0x95, 0x37, 0x6e, 0xdc, + 0xa5, 0x57, 0xae, 0x41, + 0x82, 0x19, 0x32, 0x64, 0xc8, 0x8d, 0x07, 0x0e, 0x1c, 0x38, 0x70, 0xe0, + 0xdd, 0xa7, 0x53, 0xa6, + 0x51, 0xa2, 0x59, 0xb2, 0x79, 0xf2, 0xf9, 0xef, 0xc3, 0x9b, 0x2b, 0x56, + 0xac, 0x45, 0x8a, 0x09, + 0x12, 0x24, 0x48, 0x90, 0x3d, 0x7a, 0xf4, 0xf5, 0xf7, 0xf3, 0xfb, 0xeb, + 0xcb, 0x8b, 0x0b, 0x16, + 0x2c, 0x58, 0xb0, 0x7d, 0xfa, 0xe9, 0xcf, 0x83, 0x1b, 0x36, 0x6c, 0xd8, + 0xad, 0x47, 0x8e, 0x00, +}; + +#define glog(x) __LPM(&g0log[x]) +#define gexp(x) __LPM(&g0exp[x]) + +#else // generate the log and exp tables - some CPU, much less flash, +512 bytes ram which can be shared + +unsigned char g0log[256], g0exp[256]; +#define glog(x) (g0log[x]) +#define gexp(x) (g0exp[x]) +static void +gentables () +{ +#define GFPOLY (0x11d) + unsigned char i, j; + g0log[0] = 255; + g0exp[255] = 0; + j = 1; + for (i = 0; i < 255; i++) + { + g0log[j] = i; + g0exp[i] = j; + j <<= 1; + if (j & 256) + j ^= GFPOLY; + j &= 255; + } +} +#endif + +static void +initrspoly (unsigned char eclen, unsigned char *genpoly) +{ + unsigned char i, j; + +#ifdef RTGENEXPLOG + gentables (); +#endif + + genpoly[0] = 1; + for (i = 0; i < eclen; i++) + { + genpoly[i + 1] = 1; + for (j = i; j > 0; j--) + genpoly[j] = genpoly[j] + ? genpoly[j - + 1] ^ gexp (modnn (glog (genpoly[j]) + i)) : genpoly[j - + 1]; + genpoly[0] = gexp (modnn (glog (genpoly[0]) + i)); + } + for (i = 0; i <= eclen; i++) + genpoly[i] = glog (genpoly[i]); // use logs for genpoly[] +} + +static void +appendrs (unsigned char *data, unsigned char dlen, + unsigned char *ecbuf, unsigned char eclen, unsigned char *genpoly) +{ + unsigned char i, j, fb; + + memset (ecbuf, 0, eclen); + for (i = 0; i < dlen; i++) + { + fb = glog (data[i] ^ ecbuf[0]); + if (fb != 255) /* fb term is non-zero */ + for (j = 1; j < eclen; j++) + ecbuf[j - 1] = ecbuf[j] ^ gexp (modnn (fb + genpoly[eclen - j])); + else + memmove (ecbuf, ecbuf + 1, eclen - 1); + ecbuf[eclen - 1] = fb == 255 ? 0 : gexp (modnn (fb + genpoly[0])); + } +} + +//======================================================================== +// 8 bit data to QR-coded 8 bit data +static void +stringtoqr (void) +{ + unsigned i; + unsigned size, max; + size = strlen ((char *) strinbuf); + + max = datablkw * (neccblk1 + neccblk2) + neccblk2; + if (size >= max - 2) + { + size = max - 2; + if (VERSION > 9) + size--; + } + + i = size; + if (VERSION > 9) + { + strinbuf[i + 2] = 0; + while (i--) + { + strinbuf[i + 3] |= strinbuf[i] << 4; + strinbuf[i + 2] = strinbuf[i] >> 4; + } + strinbuf[2] |= size << 4; + strinbuf[1] = size >> 4; + strinbuf[0] = 0x40 | (size >> 12); + } + else + { + strinbuf[i + 1] = 0; + while (i--) + { + strinbuf[i + 2] |= strinbuf[i] << 4; + strinbuf[i + 1] = strinbuf[i] >> 4; + } + strinbuf[1] |= size << 4; + strinbuf[0] = 0x40 | (size >> 4); + } + i = size + 3 - (VERSION < 10); + while (i < max) + { + strinbuf[i++] = 0xec; + // buffer has room if (i == max) break; + strinbuf[i++] = 0x11; + } + + // calculate and append ECC + unsigned char *ecc = &strinbuf[max]; + unsigned char *dat = strinbuf; + initrspoly (eccblkwid, qrframe); + + for (i = 0; i < neccblk1; i++) + { + appendrs (dat, datablkw, ecc, eccblkwid, qrframe); + dat += datablkw; + ecc += eccblkwid; + } + for (i = 0; i < neccblk2; i++) + { + appendrs (dat, datablkw + 1, ecc, eccblkwid, qrframe); + dat += datablkw + 1; + ecc += eccblkwid; + } + unsigned j; + dat = qrframe; + for (i = 0; i < datablkw; i++) + { + for (j = 0; j < neccblk1; j++) + *dat++ = strinbuf[i + j * datablkw]; + for (j = 0; j < neccblk2; j++) + *dat++ = strinbuf[(neccblk1 * datablkw) + i + (j * (datablkw + 1))]; + } + for (j = 0; j < neccblk2; j++) + *dat++ = strinbuf[(neccblk1 * datablkw) + i + (j * (datablkw + 1))]; + for (i = 0; i < eccblkwid; i++) + for (j = 0; j < neccblk1 + neccblk2; j++) + *dat++ = strinbuf[max + i + j * eccblkwid]; + memcpy (strinbuf, qrframe, max + eccblkwid * (neccblk1 + neccblk2)); + +} + +//======================================================================== +// Frame data insert following the path rules +static unsigned char +ismasked (unsigned char x, unsigned char y) +{ + unsigned bt; + if (x > y) + { + bt = x; + x = y; + y = bt; + } + bt = y; + bt += y * y; +#if 0 + // bt += y*y; + unsigned s = 1; + while (y--) + { + bt += s; + s += 2; + } +#endif + bt >>= 1; + bt += x; + return (__LPM (&framask[bt >> 3]) >> (7 - (bt & 7))) & 1; +} + +static void +fillframe (void) +{ + int i; + unsigned char d, j; + unsigned char x, y, ffdecy, ffgohv; + + memcpy_P (qrframe, framebase, WDB * WD); + x = y = WD - 1; + ffdecy = 1; // up, minus + ffgohv = 1; + + /* inteleaved data and ecc codes */ + for (i = 0; i < ((datablkw + eccblkwid) * (neccblk1 + neccblk2) + neccblk2); + i++) + { + d = strinbuf[i]; + for (j = 0; j < 8; j++, d <<= 1) + { + if (0x80 & d) + SETQRBIT (x, y); + do + { // find next fill position + if (ffgohv) + x--; + else + { + x++; + if (ffdecy) + { + if (y != 0) + y--; + else + { + x -= 2; + ffdecy = !ffdecy; + if (x == 6) + { + x--; + y = 9; + } + } + } + else + { + if (y != WD - 1) + y++; + else + { + x -= 2; + ffdecy = !ffdecy; + if (x == 6) + { + x--; + y -= 8; + } + } + } + } + ffgohv = !ffgohv; + } + while (ismasked (x, y)); + } + } + +} + +//======================================================================== +// Masking +static void +applymask (unsigned char m) +{ + unsigned char x, y, r3x, r3y; + + switch (m) + { + case 0: + for (y = 0; y < WD; y++) + for (x = 0; x < WD; x++) + if (!((x + y) & 1) && !ismasked (x, y)) + TOGQRBIT (x, y); + break; + case 1: + for (y = 0; y < WD; y++) + for (x = 0; x < WD; x++) + if (!(y & 1) && !ismasked (x, y)) + TOGQRBIT (x, y); + break; + case 2: + for (y = 0; y < WD; y++) + for (r3x = 0, x = 0; x < WD; x++, r3x++) + { + if (r3x == 3) + r3x = 0; + if (!r3x && !ismasked (x, y)) + TOGQRBIT (x, y); + } + break; + case 3: + for (r3y = 0, y = 0; y < WD; y++, r3y++) + { + if (r3y == 3) + r3y = 0; + for (r3x = r3y, x = 0; x < WD; x++, r3x++) + { + if (r3x == 3) + r3x = 0; + if (!r3x && !ismasked (x, y)) + TOGQRBIT (x, y); + } + } + break; + case 4: + for (y = 0; y < WD; y++) + for (r3x = 0, r3y = ((y >> 1) & 1), x = 0; x < WD; x++, r3x++) + { + if (r3x == 3) + { + r3x = 0; + r3y = !r3y; + } + if (!r3y && !ismasked (x, y)) + TOGQRBIT (x, y); + } + break; + case 5: + for (r3y = 0, y = 0; y < WD; y++, r3y++) + { + if (r3y == 3) + r3y = 0; + for (r3x = 0, x = 0; x < WD; x++, r3x++) + { + if (r3x == 3) + r3x = 0; + if (!((x & y & 1) + !(!r3x | !r3y)) && !ismasked (x, y)) + TOGQRBIT (x, y); + } + } + break; + case 6: + for (r3y = 0, y = 0; y < WD; y++, r3y++) + { + if (r3y == 3) + r3y = 0; + for (r3x = 0, x = 0; x < WD; x++, r3x++) + { + if (r3x == 3) + r3x = 0; + if (!(((x & y & 1) + (r3x && (r3x == r3y))) & 1) + && !ismasked (x, y)) + TOGQRBIT (x, y); + } + } + break; + case 7: + for (r3y = 0, y = 0; y < WD; y++, r3y++) + { + if (r3y == 3) + r3y = 0; + for (r3x = 0, x = 0; x < WD; x++, r3x++) + { + if (r3x == 3) + r3x = 0; + if (!(((r3x && (r3x == r3y)) + ((x + y) & 1)) & 1) + && !ismasked (x, y)) + TOGQRBIT (x, y); + } + } + break; + } + return; +} + +// Badness coefficients. +static const unsigned char N1 = 3; +static const unsigned char N2 = 3; +static const unsigned char N3 = 40; +static const unsigned char N4 = 10; + +static unsigned +badruns (unsigned char length) +{ + unsigned char i; + unsigned runsbad = 0; + for (i = 0; i <= length; i++) + if (rlens[i] >= 5) + runsbad += N1 + rlens[i] - 5; + // BwBBBwB + for (i = 3; i < length - 1; i += 2) + if (rlens[i - 2] == rlens[i + 2] + && rlens[i + 2] == rlens[i - 1] + && rlens[i - 1] == rlens[i + 1] && rlens[i - 1] * 3 == rlens[i] + // white around the black pattern? Not part of spec + && (rlens[i - 3] == 0 // beginning + || i + 3 > length // end + || rlens[i - 3] * 3 >= rlens[i] * 4 + || rlens[i + 3] * 3 >= rlens[i] * 4)) + runsbad += N3; + return runsbad; +} + +static int +badcheck () +{ + unsigned char x, y, h, b, b1; + unsigned thisbad = 0; + int bw = 0; + + // blocks of same color. + for (y = 0; y < WD - 1; y++) + for (x = 0; x < WD - 1; x++) + if ((QRBIT (x, y) && QRBIT (x + 1, y) && QRBIT (x, y + 1) && QRBIT (x + 1, y + 1)) // all black + || !(QRBIT (x, y) || QRBIT (x + 1, y) || QRBIT (x, y + 1) || QRBIT (x + 1, y + 1))) // all white + thisbad += N2; + + // X runs + for (y = 0; y < WD; y++) + { + rlens[0] = 0; + for (h = b = x = 0; x < WD; x++) + { + if ((b1 = QRBIT (x, y)) == b) + rlens[h]++; + else + rlens[++h] = 1; + b = b1; + bw += b ? 1 : -1; + } + thisbad += badruns (h); + } + + // black/white imbalance + if (bw < 0) + bw = -bw; + + unsigned long big = bw; + unsigned count = 0; + big += big << 2; + big <<= 1; + while (big > WD * WD) + big -= WD * WD, count++; + thisbad += count * N4; + + // Y runs + for (x = 0; x < WD; x++) + { + rlens[0] = 0; + for (h = b = y = 0; y < WD; y++) + { + if ((b1 = QRBIT (x, y)) == b) + rlens[h]++; + else + rlens[++h] = 1; + b = b1; + } + thisbad += badruns (h); + } + return thisbad; +} + +// final format bits with mask +// level << 3 | mask +static const unsigned fmtword[] PROGMEM = { + 0x77c4, 0x72f3, 0x7daa, 0x789d, 0x662f, 0x6318, 0x6c41, 0x6976, //L + 0x5412, 0x5125, 0x5e7c, 0x5b4b, 0x45f9, 0x40ce, 0x4f97, 0x4aa0, //M + 0x355f, 0x3068, 0x3f31, 0x3a06, 0x24b4, 0x2183, 0x2eda, 0x2bed, //Q + 0x1689, 0x13be, 0x1ce7, 0x19d0, 0x0762, 0x0255, 0x0d0c, 0x083b, //H +}; + +static void +addfmt (unsigned char masknum) +{ + unsigned fmtbits; + unsigned char i, lvl = ECCLEVEL - 1; + + fmtbits = pgm_read_word (&fmtword[masknum + (lvl << 3)]); + // low byte + for (i = 0; i < 8; i++, fmtbits >>= 1) + if (fmtbits & 1) + { + SETQRBIT (WD - 1 - i, 8); + if (i < 6) + SETQRBIT (8, i); + else + SETQRBIT (8, i + 1); + } + // high byte + for (i = 0; i < 7; i++, fmtbits >>= 1) + if (fmtbits & 1) + { + SETQRBIT (8, WD - 7 + i); + if (i) + SETQRBIT (6 - i, 8); + else + SETQRBIT (7, 8); + } +} + +void +qrencode () +{ + unsigned mindem = 30000; + unsigned char best = 0; + unsigned char i; + unsigned badness; + + stringtoqr (); + fillframe (); // Inisde loop to avoid having separate mask buffer + memcpy (strinbuf, qrframe, WD * WDB); + for (i = 0; i < 8; i++) + { + applymask (i); // returns black-white imbalance + badness = badcheck (); +#if 0 //ndef PUREBAD + if (badness < WD * WD * 5 / 4) + { // good enough - masks grow in compute complexity + best = i; + break; + } +#endif + if (badness < mindem) + { + mindem = badness; + best = i; + } + if (best == 7) + break; // don't increment i to avoid redoing mask + memcpy (qrframe, strinbuf, WD * WDB); // reset filled frame + } + if (best != i) // redo best mask - none good enough, last wasn't best + applymask (best); + addfmt (best); // add in final format bytes +} + + +/* + Local Variables: + mode: C + c-file-style: "gnu" + End: +*/ diff --git a/benchies/embench/benchemarks/qrduino/qrencode.h b/benchies/embench/benchemarks/qrduino/qrencode.h new file mode 100644 index 0000000000..8d30b775b7 --- /dev/null +++ b/benchies/embench/benchemarks/qrduino/qrencode.h @@ -0,0 +1,46 @@ +/* BEEBS qrduino benchmark + + This version, copyright (C) 2014-2019 Embecosm Limited and University of + Bristol + + Contributor James Pallister + Contributor Jeremy Bennett + + This file is part of Embench and was formerly part of the Bristol/Embecosm + Embedded Benchmark Suite. + + SPDX-License-Identifier: GPL-3.0-or-later + + Original code from: https://github.com/tz1/qrduino */ + +#define PROGMEM +#define memcpy_P memcpy +#define __LPM(x) *x +#define pgm_read_word(x) *x + +// malloc-ed by initframe, free manually +extern unsigned char *strinbuf; // string iput buffer +extern unsigned char *qrframe; +// setup the base frame structure - can be reused +void initframe (void); +// free the basic frame malloced structures +void freeframe (void); +// these resturn maximum string size to send in +unsigned initeccsize (unsigned char ecc, unsigned size); +unsigned initecc (unsigned char level, unsigned char version); + +extern unsigned char WD, WDB; +#include "qrbits.h" + +// strinbuf in, qrframe out +void qrencode (void); + +void freeecc (); + + +/* + Local Variables: + mode: C + c-file-style: "gnu" + End: +*/ diff --git a/benchies/embench/benchemarks/qrduino/qrframe.c b/benchies/embench/benchemarks/qrduino/qrframe.c new file mode 100644 index 0000000000..ba91e9494b --- /dev/null +++ b/benchies/embench/benchemarks/qrduino/qrframe.c @@ -0,0 +1,325 @@ +/* BEEBS qrduino benchmark + + This version, copyright (C) 2014-2019 Embecosm Limited and University of + Bristol + + Contributor James Pallister + Contributor Jeremy Bennett + + This file is part of Embench and was formerly part of the Bristol/Embecosm + Embedded Benchmark Suite. + + SPDX-License-Identifier: GPL-3.0-or-later + + Original code from: https://github.com/tz1/qrduino */ + +#include +#include + +/* Header for BEEBS library calls */ + +#include "beebsc.h" + +#ifndef __AVR__ +#define PROGMEM +#define memcpy_P memcpy +#define __LPM(x) *x +#define pgm_read_word(x) *x +#else +#include +#endif + +unsigned char *framebase; +unsigned char *framask; +unsigned char *rlens; +unsigned char VERSION; +unsigned char WD, WDB; // filled in from verison by initframe + +#define QRBIT(x,y) ( ( framebase[((x)>>3) + (y) * WDB] >> (7-((x) & 7 ))) & 1 ) +#define SETQRBIT(x,y) framebase[((x)>>3) + (y) * WDB] |= 0x80 >> ((x) & 7) + +static void +setmask (unsigned char x, unsigned char y) +{ + unsigned bt; + if (x > y) + { + bt = x; + x = y; + y = bt; + } + // y*y = 1+3+5... + bt = y; + bt *= y; + bt += y; + bt >>= 1; + bt += x; + framask[bt >> 3] |= 0x80 >> (bt & 7); +} + +static void +putfind () +{ + unsigned char j, i, k, t; + for (t = 0; t < 3; t++) + { + k = 0; + i = 0; + if (t == 1) + k = (WD - 7); + if (t == 2) + i = (WD - 7); + SETQRBIT (i + 3, k + 3); + for (j = 0; j < 6; j++) + { + SETQRBIT (i + j, k); + SETQRBIT (i, k + j + 1); + SETQRBIT (i + 6, k + j); + SETQRBIT (i + j + 1, k + 6); + } + for (j = 1; j < 5; j++) + { + setmask (i + j, k + 1); + setmask (i + 1, k + j + 1); + setmask (i + 5, k + j); + setmask (i + j + 1, k + 5); + } + for (j = 2; j < 4; j++) + { + SETQRBIT (i + j, k + 2); + SETQRBIT (i + 2, k + j + 1); + SETQRBIT (i + 4, k + j); + SETQRBIT (i + j + 1, k + 4); + } + } +} + +static void +putalign (int x, int y) +{ + int j; + + SETQRBIT (x, y); + for (j = -2; j < 2; j++) + { + SETQRBIT (x + j, y - 2); + SETQRBIT (x - 2, y + j + 1); + SETQRBIT (x + 2, y + j); + SETQRBIT (x + j + 1, y + 2); + } + for (j = 0; j < 2; j++) + { + setmask (x - 1, y + j); + setmask (x + 1, y - j); + setmask (x - j, y - 1); + setmask (x + j, y + 1); + } +} + +static const unsigned char adelta[41] PROGMEM = { + 0, 11, 15, 19, 23, 27, 31, // force 1 pat + 16, 18, 20, 22, 24, 26, 28, 20, 22, 24, 24, 26, 28, 28, 22, 24, 24, + 26, 26, 28, 28, 24, 24, 26, 26, 26, 28, 28, 24, 26, 26, 26, 28, 28, +}; + +static void +doaligns (void) +{ + unsigned char delta, x, y; + if (VERSION < 2) + return; + delta = __LPM (&adelta[VERSION]); + y = WD - 7; + for (;;) + { + x = WD - 7; + while (x > delta - 3U) + { + putalign (x, y); + if (x < delta) + break; + x -= delta; + } + if (y <= delta + 9U) + break; + y -= delta; + putalign (6, y); + putalign (y, 6); + } +} + +static const unsigned vpat[] PROGMEM = { + 0xc94, 0x5bc, 0xa99, 0x4d3, 0xbf6, 0x762, 0x847, 0x60d, + 0x928, 0xb78, 0x45d, 0xa17, 0x532, 0x9a6, 0x683, 0x8c9, + 0x7ec, 0xec4, 0x1e1, 0xfab, 0x08e, 0xc1a, 0x33f, 0xd75, + 0x250, 0x9d5, 0x6f0, 0x8ba, 0x79f, 0xb0b, 0x42e, 0xa64, + 0x541, 0xc69 +}; + +static void +putvpat (void) +{ + unsigned char vers = VERSION; + unsigned char x, y, bc; + unsigned verinfo; + if (vers < 7) + return; + verinfo = pgm_read_word (&vpat[vers - 7]); + + bc = 17; + for (x = 0; x < 6; x++) + for (y = 0; y < 3; y++, bc--) + if (1 & (bc > 11 ? (unsigned) vers >> (bc - 12) : verinfo >> bc)) + { + SETQRBIT (5 - x, 2 - y + WD - 11); + SETQRBIT (2 - y + WD - 11, 5 - x); + } + else + { + setmask (5 - x, 2 - y + WD - 11); + setmask (2 - y + WD - 11, 5 - x); + } +} + +void +initframe () +{ + unsigned x, y; + + framebase = calloc_beebs (WDB * WD, 1); + framask = calloc_beebs (((WD * (WD + 1) / 2) + 7) / 8, 1); + rlens = malloc_beebs (WD + 1); + // finders + putfind (); + // alignment blocks + doaligns (); + // single black + SETQRBIT (8, WD - 8); + // timing gap - masks only + for (y = 0; y < 7; y++) + { + setmask (7, y); + setmask (WD - 8, y); + setmask (7, y + WD - 7); + } + for (x = 0; x < 8; x++) + { + setmask (x, 7); + setmask (x + WD - 8, 7); + setmask (x, WD - 8); + } + // reserve mask-format area + for (x = 0; x < 9; x++) + setmask (x, 8); + for (x = 0; x < 8; x++) + { + setmask (x + WD - 8, 8); + setmask (8, x); + } + for (y = 0; y < 7; y++) + setmask (8, y + WD - 7); + // timing + for (x = 0; x < (unsigned) WD - 14; x++) + if (x & 1) + { + setmask (8 + x, 6); + setmask (6, 8 + x); + } + else + { + SETQRBIT (8 + x, 6); + SETQRBIT (6, 8 + x); + } + + // version block + putvpat (); + for (y = 0; y < WD; y++) + for (x = 0; x <= y; x++) + if (QRBIT (x, y)) + setmask (x, y); +} + +void +freeframe () +{ + free_beebs (framebase); + free_beebs (framask); + free_beebs (rlens); +} + +unsigned char *strinbuf; +unsigned char *qrframe; +unsigned char ECCLEVEL; +unsigned char neccblk1; +unsigned char neccblk2; +unsigned char datablkw; +unsigned char eccblkwid; + +#ifndef __AVR__ +#define PROGMEM +#define memcpy_P memcpy +#define __LPM(x) *x +#endif + +#include "ecctable.h" + +unsigned +initecc (unsigned char ecc, unsigned char vers) +{ + VERSION = vers; + WD = 17 + 4 * vers; + WDB = (WD + 7) / 8; + + unsigned fsz = WD * WDB; + if (fsz < 768) // for ECC math buffers + fsz = 768; + qrframe = malloc_beebs (fsz); + + ECCLEVEL = ecc; + unsigned eccindex = (ecc - 1) * 4 + (vers - 1) * 16; + + neccblk1 = eccblocks[eccindex++]; + neccblk2 = eccblocks[eccindex++]; + datablkw = eccblocks[eccindex++]; + eccblkwid = eccblocks[eccindex++]; + + if (fsz < + (unsigned) (datablkw + (datablkw + eccblkwid) * (neccblk1 + neccblk2) + + neccblk2)) + fsz = + datablkw + (datablkw + eccblkwid) * (neccblk1 + neccblk2) + neccblk2; + strinbuf = malloc_beebs (fsz); + return datablkw * (neccblk1 + neccblk2) + neccblk2 - 3; //-2 if vers <= 9! +} + +unsigned +initeccsize (unsigned char ecc, unsigned size) +{ + unsigned eccindex; + unsigned char vers; + for (vers = 1; vers < 40; vers++) + { + eccindex = (ecc - 1) * 4 + (vers - 1) * 16; + neccblk1 = eccblocks[eccindex++]; + neccblk2 = eccblocks[eccindex++]; + datablkw = eccblocks[eccindex++]; + if (size < (unsigned) (datablkw * (neccblk1 + neccblk2) + neccblk2 - 3)) + break; + } + return initecc (ecc, vers); +} + +void +freeecc () +{ + free_beebs (qrframe); + free_beebs (strinbuf); +} + + +/* + Local Variables: + mode: C + c-file-style: "gnu" + End: +*/ diff --git a/benchies/embench/benchemarks/qrduino/qrtest.c b/benchies/embench/benchemarks/qrduino/qrtest.c new file mode 100644 index 0000000000..957fbe5c74 --- /dev/null +++ b/benchies/embench/benchemarks/qrduino/qrtest.c @@ -0,0 +1,99 @@ +/* BEEBS qrduino benchmark + + This version, copyright (C) 2014-2019 Embecosm Limited and University of + Bristol + + Contributor James Pallister + Contributor Jeremy Bennett + + This file is part of Embench and was formerly part of the Bristol/Embecosm + Embedded Benchmark Suite. + + SPDX-License-Identifier: GPL-3.0-or-later + + Original code from: https://github.com/tz1/qrduino */ + +#include "../../src/support.h" +#include "qrencode.h" + +#include + +/* This scale factor will be changed to equalise the runtime of the + benchmarks. */ +#define LOCAL_SCALE_FACTOR 5 + +/* BEEBS heap is just an array */ + +#define HEAP_SIZE 8192 +static char heap[HEAP_SIZE]; + +static const char *encode; +static int size; + +static int benchmark_body (int rpt); + +void +warm_caches (int heat) +{ + int res = benchmark_body (heat); + + return; +} + + +int +benchmark (void) +{ + return benchmark_body (LOCAL_SCALE_FACTOR * CPU_MHZ); +} + + +static int __attribute__ ((noinline)) +benchmark_body (int rpt) +{ + static const char *in_encode = "http://www.mageec.com"; + int i; + + for (i = 0; i < rpt; i++) + { + encode = in_encode; + size = 22; + init_heap_beebs ((void *) heap, HEAP_SIZE); + + initeccsize (1, size); + + memcpy (strinbuf, encode, size); + + initframe (); + qrencode (); + freeframe (); + freeecc (); + } + + return 0; +} + +void +initialise_benchmark () +{ +} + +int +verify_benchmark (int unused) +{ + unsigned char expected[22] = { + 254, 101, 63, 128, 130, 110, 160, 128, 186, 65, 46, + 128, 186, 38, 46, 128, 186, 9, 174, 128, 130, 20 + }; + + return (0 == memcmp (strinbuf, expected, 22 * sizeof (strinbuf[0]))) + && check_heap_beebs ((void *) heap); +} + + +/* + Local Variables: + mode: C + c-file-style: "gnu" + End: +*/ diff --git a/benchies/embench/benchemarks/sglib-combined/combined.c b/benchies/embench/benchemarks/sglib-combined/combined.c new file mode 100644 index 0000000000..b95e8317d0 --- /dev/null +++ b/benchies/embench/benchemarks/sglib-combined/combined.c @@ -0,0 +1,313 @@ +/* BEEBS arraysort benchmark + + This version, copyright (C) 2014-2019 Embecosm Limited and University of + Bristol + + Contributor James Pallister + Contributor Jeremy Bennett + + This file is part of Embench and was formerly part of the Bristol/Embecosm + Embedded Benchmark Suite. + + SPDX-License-Identifier: GPL-3.0-or-later */ + +#include +#include "../../src/support.h" +#include "sglib.h" + +/* This scale factor will be changed to equalise the runtime of the + benchmarks. */ +#define LOCAL_SCALE_FACTOR 29 + +/* BEEBS heap is just an array */ + +#define HEAP_SIZE 8192 +static char heap[HEAP_SIZE] __attribute__((aligned)); + +/* General array to sort for all ops */ + +static const int array[100] = { + 14, 66, 12, 41, 86, 69, 19, 77, 68, 38, + 26, 42, 37, 23, 17, 29, 55, 13, 90, 92, + 76, 99, 10, 54, 57, 83, 40, 44, 75, 33, + 24, 28, 80, 18, 78, 32, 93, 89, 52, 11, + 21, 96, 50, 15, 48, 63, 87, 20, 8, 85, + 43, 16, 94, 88, 53, 84, 74, 91, 67, 36, + 95, 61, 64, 5, 30, 82, 72, 46, 59, 9, + 7, 3, 39, 31, 4, 73, 70, 60, 58, 81, + 56, 51, 45, 1, 6, 49, 27, 47, 34, 35, + 62, 97, 2, 79, 98, 25, 22, 65, 71, 0 +}; + +/* Array quicksort declarations */ + +int array2[100]; + +/* Doubly linked list declarations */ + +typedef struct dllist +{ + int i; + struct dllist *ptr_to_next; + struct dllist *ptr_to_previous; +} dllist; + +#define DLLIST_COMPARATOR(e1, e2) (e1->i - e2->i) + +SGLIB_DEFINE_DL_LIST_PROTOTYPES (dllist, DLLIST_COMPARATOR, ptr_to_previous, + ptr_to_next) +SGLIB_DEFINE_DL_LIST_FUNCTIONS (dllist, DLLIST_COMPARATOR, ptr_to_previous, + ptr_to_next) + +dllist *the_list; + +/* Hash table declarations */ + +#define HASH_TAB_SIZE 20 + +typedef struct ilist +{ + int i; + struct ilist *next; +} ilist; + +ilist *htab[HASH_TAB_SIZE]; + +#define ILIST_COMPARATOR(e1, e2) (e1->i - e2->i) + +unsigned int +ilist_hash_function (ilist * e) +{ + return (e->i); +} + +SGLIB_DEFINE_LIST_PROTOTYPES (ilist, ILIST_COMPARATOR, next) +SGLIB_DEFINE_LIST_FUNCTIONS (ilist, ILIST_COMPARATOR, next) +SGLIB_DEFINE_HASHED_CONTAINER_PROTOTYPES (ilist, HASH_TAB_SIZE, + ilist_hash_function) +SGLIB_DEFINE_HASHED_CONTAINER_FUNCTIONS (ilist, HASH_TAB_SIZE, + ilist_hash_function) + +/* Queue declarations */ + +#define MAX_PARAMS 101 + +typedef struct iq +{ + int a[MAX_PARAMS]; + int i, j; +} iq; + +SGLIB_DEFINE_QUEUE_FUNCTIONS (iq, int, a, i, j, MAX_PARAMS) + +/* RB Tree declarations */ + +typedef struct rbtree +{ + int n; + char color_field; + struct rbtree *left; + struct rbtree *right; +} rbtree; + +#define CMPARATOR(x,y) ((x->n)-(y->n)) + +SGLIB_DEFINE_RBTREE_PROTOTYPES (rbtree, left, right, color_field, CMPARATOR) +SGLIB_DEFINE_RBTREE_FUNCTIONS (rbtree, left, right, color_field, CMPARATOR) + + +int +verify_benchmark (int res) +{ + static const int array_exp[100] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, 93, 94, 95, 96, 97, 98, 99 + }; + + int i = 0; + dllist *l; + struct ilist ii, *nn; + + /* Doubly linked list check */ + + for (l = sglib_dllist_get_first (the_list); l != NULL; l = l->ptr_to_next) + { + if (l->i != i) + return 0; + i++; + } + + /* Hashtable check */ + + for (i = 0; i < 100; i++) + { + ii.i = array[i]; + nn = sglib_hashed_ilist_find_member (htab, &ii); + + if ((nn == NULL) || (nn->i != array[i])) + return 0; + } + + return (15050 == res) && check_heap_beebs ((void *) heap) + && (0 == memcmp (array2, array_exp, 100 * sizeof (array[0]))); +} + + +void +initialise_benchmark (void) +{ +} + + + +static int benchmark_body (int rpt); + +void +warm_caches (int heat) +{ + int res = benchmark_body (heat); + + return; +} + + +int +benchmark (void) +{ + return benchmark_body (LOCAL_SCALE_FACTOR * CPU_MHZ); +} + + +static int __attribute__ ((noinline)) +benchmark_body (int rpt) +{ + volatile int cnt; + int i; + + for (i = 0; i < rpt; i++) + { + int i; + dllist *l; + struct ilist ii, *nn, *ll; + struct sglib_hashed_ilist_iterator it; + int ai, aj, n; + int a[MAX_PARAMS]; + struct rbtree e, *t, *the_tree, *te; + struct sglib_rbtree_iterator it2; + + /* Array quicksort */ + + memcpy (array2, array, 100 * sizeof (array[0])); + SGLIB_ARRAY_SINGLE_QUICK_SORT (int, array2, 100, + SGLIB_NUMERIC_COMPARATOR); + + /* Doubly linked list */ + + init_heap_beebs ((void *) heap, HEAP_SIZE); + the_list = NULL; + + for (i = 0; i < 100; ++i) + { + l = malloc_beebs (sizeof (dllist)); + l->i = array[i]; + sglib_dllist_add (&the_list, l); + } + + sglib_dllist_sort (&the_list); + + cnt = 0; + + for (l = sglib_dllist_get_first (the_list); l != NULL; + l = l->ptr_to_next) + cnt++; + + /* Hash table */ + + sglib_hashed_ilist_init (htab); + + for (i = 0; i < 100; i++) + { + ii.i = array[i]; + if (sglib_hashed_ilist_find_member (htab, &ii) == NULL) + { + nn = malloc_beebs (sizeof (struct ilist)); + nn->i = array[i]; + sglib_hashed_ilist_add (htab, nn); + } + } + + for (ll = sglib_hashed_ilist_it_init (&it, htab); + ll != NULL; ll = sglib_hashed_ilist_it_next (&it)) + { + cnt++; + } + + /* Queue */ + + // echo parameters using a queue + SGLIB_QUEUE_INIT (int, a, ai, aj); + for (i = 0; i < 100; i++) + { + n = array[i]; + SGLIB_QUEUE_ADD (int, a, n, ai, aj, MAX_PARAMS); + } + while (!SGLIB_QUEUE_IS_EMPTY (int, a, ai, aj)) + { + cnt += SGLIB_QUEUE_FIRST_ELEMENT (int, a, ai, aj); + SGLIB_QUEUE_DELETE (int, a, ai, aj, MAX_PARAMS); + } + + // print parameters in descending order + SGLIB_HEAP_INIT (int, a, ai); + for (i = 0; i < 100; i++) + { + n = array[i]; + SGLIB_HEAP_ADD (int, a, n, ai, MAX_PARAMS, + SGLIB_NUMERIC_COMPARATOR); + } + while (!SGLIB_HEAP_IS_EMPTY (int, a, ai)) + { + cnt += SGLIB_HEAP_FIRST_ELEMENT (int, a, ai); + SGLIB_HEAP_DELETE (int, a, ai, MAX_PARAMS, + SGLIB_NUMERIC_COMPARATOR); + } + + /* RB Tree */ + + the_tree = NULL; + for (i = 0; i < 100; i++) + { + e.n = array[i]; + if (sglib_rbtree_find_member (the_tree, &e) == NULL) + { + t = malloc_beebs (sizeof (struct rbtree)); + t->n = array[i]; + sglib_rbtree_add (&the_tree, t); + } + } + + for (te = sglib_rbtree_it_init_inorder (&it2, the_tree); + te != NULL; te = sglib_rbtree_it_next (&it2)) + { + cnt += te->n; + } + } + + return cnt; +} + + +/* + Local Variables: + mode: C + c-file-style: "gnu" + End: +*/ diff --git a/benchies/embench/benchemarks/sglib-combined/sglib.h b/benchies/embench/benchemarks/sglib-combined/sglib.h new file mode 100644 index 0000000000..2990f4cbc4 --- /dev/null +++ b/benchies/embench/benchemarks/sglib-combined/sglib.h @@ -0,0 +1,1968 @@ +/* This file is part of the Bristol/Embecosm Embedded Benchmark Suite. + + This version, copyright (C) 2014-2019 Embecosm Limited and University of + Bristol + + Contributor James Pallister + Contributor Jeremy Bennett + + This file is part of Embench and was formerly part of the Bristol/Embecosm + Embedded Benchmark Suite. + + SPDX-License-Identifier: GPL-3.0-or-later + + Original header: + + This is SGLIB version 1.0.3 + + (C) by Marian Vittek, Bratislava, http://www.xref-tech.com/sglib, 2003-5 + + License Conditions: You can use a verbatim copy (including this copyright + notice) of sglib freely in any project, commercial or not. You can also + use derivative forms freely under terms of Open Source Software license or + under terms of GNU Public License. If you need to use a derivative form in + a commercial project, or you need sglib under any other license conditions, + contact the author. */ + + +#ifndef _SGLIB__h_ +#define _SGLIB__h_ + +/* the assert is used exclusively to write unexpected error messages */ +#define assert(a) + + +/* ---------------------------------------------------------------------------- */ +/* ---------------------------------------------------------------------------- */ +/* - LEVEL - 0 INTERFACE - */ +/* ---------------------------------------------------------------------------- */ +/* ---------------------------------------------------------------------------- */ + + +/* ---------------------------------------------------------------------------- */ +/* ------------------------------ STATIC ARRAYS ------------------------------- */ +/* ---------------------------------------------------------------------------- */ + +/* + + Basic algorithms for sorting arrays. Multiple depending arrays can + be rearranged using user defined 'elem_exchangers' + +*/ + +/* HEAP - SORT (level 0) */ + +#define SGLIB_ARRAY_SINGLE_HEAP_SORT(type, a, max, comparator) {\ + SGLIB_ARRAY_HEAP_SORT(type, a, max, comparator, SGLIB_ARRAY_ELEMENTS_EXCHANGER);\ +} + +#define SGLIB_ARRAY_HEAP_SORT(type, a, max, comparator, elem_exchanger) {\ + int _k_;\ + for(_k_=(max)/2; _k_>=0; _k_--) {\ + SGLIB___ARRAY_HEAP_DOWN(type, a, _k_, max, comparator, elem_exchanger);\ + }\ + for(_k_=(max)-1; _k_>=0; _k_--) {\ + elem_exchanger(type, a, 0, _k_);\ + SGLIB___ARRAY_HEAP_DOWN(type, a, 0, _k_, comparator, elem_exchanger);\ + }\ +} + +#define SGLIB___ARRAY_HEAP_DOWN(type, a, ind, max, comparator, elem_exchanger) {\ + int _m_, _l_, _r_, _i_;\ + _i_ = (ind);\ + _m_ = _i_;\ + do {\ + _i_ = _m_; \ + _l_ = 2*_i_+1;\ + _r_ = _l_+1;\ + if (_l_ < (max)){\ + if (comparator(((a)[_m_]), ((a)[_l_])) < 0) _m_ = _l_;\ + if (_r_ < (max)) {\ + if (comparator(((a)[_m_]), ((a)[_r_])) < 0) _m_ = _r_;\ + }\ + }\ + if (_m_ != _i_) {\ + elem_exchanger(type, a, _i_, _m_);\ + }\ + } while (_m_ != _i_);\ +} + + +/* QUICK - SORT (level 0) */ + +#define SGLIB_ARRAY_SINGLE_QUICK_SORT(type, a, max, comparator) {\ + SGLIB_ARRAY_QUICK_SORT(type, a, max, comparator, SGLIB_ARRAY_ELEMENTS_EXCHANGER);\ +} + +#define SGLIB_ARRAY_QUICK_SORT(type, a, max, comparator, elem_exchanger) {\ + int _i_, _j_, _p_, _stacki_, _start_, _end_;\ + /* can sort up to 2^64 elements */\ + int _startStack_[64]; \ + int _endStack_[64];\ + type _tmp_;\ + _startStack_[0] = 0;\ + _endStack_[0] = (max);\ + _stacki_ = 1;\ + while (_stacki_ > 0) {\ + _stacki_ --;\ + _start_ = _startStack_[_stacki_];\ + _end_ = _endStack_[_stacki_];\ + while (_end_ - _start_ > 2) {\ + _p_ = _start_;\ + _i_ = _start_ + 1;\ + _j_ = _end_ - 1;\ + while (_i_<_j_) {\ + for(; _i_<=_j_ && comparator(((a)[_i_]),((a)[_p_]))<=0; _i_++) ;\ + if (_i_ > _j_) {\ + /* all remaining elements lesseq than pivot */\ + elem_exchanger(type, a, _j_, _p_);\ + _i_ = _j_;\ + } else {\ + for(; _i_<=_j_ && comparator(((a)[_j_]),((a)[_p_]))>=0; _j_--) ;\ + if (_i_ > _j_) {\ + /* all remaining elements greater than pivot */\ + elem_exchanger(type, a, _j_, _p_);\ + _i_ = _j_;\ + } else if (_i_ < _j_) {\ + elem_exchanger(type, a, _i_, _j_);\ + if (_i_+2 < _j_) {_i_++; _j_--;}\ + else if (_i_+1 < _j_) _i_++;\ + }\ + }\ + }\ + /* O.K. i==j and pivot is on a[i] == a[j] */\ + /* handle recursive calls without recursion */\ + if (_i_-_start_ > 1 && _end_-_j_ > 1) {\ + /* two recursive calls, use array-stack */\ + if (_i_-_start_ < _end_-_j_-1) {\ + _startStack_[_stacki_] = _j_+1;\ + _endStack_[_stacki_] = _end_;\ + _stacki_ ++;\ + _end_ = _i_;\ + } else {\ + _startStack_[_stacki_] = _start_;\ + _endStack_[_stacki_] = _i_;\ + _stacki_ ++;\ + _start_ = _j_+1;\ + }\ + } else {\ + if (_i_-_start_ > 1) {\ + _end_ = _i_;\ + } else {\ + _start_ = _j_+1;\ + }\ + }\ + }\ + if (_end_ - _start_ == 2) {\ + if (comparator(((a)[_start_]),((a)[_end_-1])) > 0) {\ + elem_exchanger(type, a, _start_, _end_-1);\ + }\ + }\ + }\ +} + +/* BINARY SEARCH (level 0) */ + +#define SGLIB_ARRAY_BINARY_SEARCH(type, a, start_index, end_index, key, comparator, found, result_index) {\ + int _kk_, _cc_, _ii_, _jj_, _ff_;\ + _ii_ = (start_index); \ + _jj_ = (end_index);\ + _ff_ = 0;\ + while (_ii_ <= _jj_ && _ff_==0) {\ + _kk_ = (_jj_+_ii_)/2;\ + _cc_ = comparator(((a)[_kk_]), (key));\ + if (_cc_ == 0) {\ + (result_index) = _kk_; \ + _ff_ = 1;\ + } else if (_cc_ < 0) {\ + _ii_ = _kk_+1;\ + } else {\ + _jj_ = _kk_-1;\ + }\ + }\ + if (_ff_ == 0) {\ + /* not found, but set its resulting place in the array */\ + (result_index) = _jj_+1;\ + }\ + (found) = _ff_;\ +} + +/* -------------------------------- queue (in an array) ------------------ */ +/* queue is a quadruple (a,i,j,dim) such that: */ +/* a is the array storing values */ +/* i is the index of the first used element in the array */ +/* j is the index of the first free element in the array */ +/* dim is the size of the array a */ +/* !!!!!!! This data structure is NOT documented, do not use it !!!!!!!!!! */ + +#define SGLIB_QUEUE_INIT(type, a, i, j) { i = j = 0; } +#define SGLIB_QUEUE_IS_EMPTY(type, a, i, j) ((i)==(j)) +#define SGLIB_QUEUE_IS_FULL(type, a, i, j, dim) ((i)==((j)+1)%(dim)) +#define SGLIB_QUEUE_FIRST_ELEMENT(type, a, i, j) (a[i]) +#define SGLIB_QUEUE_ADD_NEXT(type, a, i, j, dim) {\ + if (SGLIB_QUEUE_IS_FULL(type, a, i, j, dim)) {assert(0 && "the queue is full");} \ + (j) = ((j)+1) % (dim);\ +} +#define SGLIB_QUEUE_ADD(type, a, elem, i, j, dim) {\ + a[j] = (elem);\ + SGLIB_QUEUE_ADD_NEXT(type, a, i, j, dim);\ +} +#define SGLIB_QUEUE_DELETE_FIRST(type, a, i, j, dim) {\ + if (SGLIB_QUEUE_IS_EMPTY(type, a, i, j)) {assert(0 && "the queue is empty");} \ + (i) = ((i)+1) % (dim);\ +} +#define SGLIB_QUEUE_DELETE(type, a, i, j, dim) {\ + SGLIB_QUEUE_DELETE_FIRST(type, a, i, j, dim);\ +} + +/* ----------------- priority queue (heap) (in an array) -------------------- */ +/* heap is a triple (a,i,dim) such that: */ +/* a is the array storing values */ +/* i is the index of the first free element in the array */ +/* dim is the size of the array a */ +/* !!!!!!! This data structure is NOT documented, do not use it !!!!!!!!!! */ + +#define SGLIB_HEAP_INIT(type, a, i) { i = 0; } +#define SGLIB_HEAP_IS_EMPTY(type, a, i) ((i)==0) +#define SGLIB_HEAP_IS_FULL(type, a, i, dim) ((i)==(dim)) +#define SGLIB_HEAP_FIRST_ELEMENT(type, a, i) (a[0]) +#define SGLIB_HEAP_ADD_NEXT(type, a, i, dim, comparator, elem_exchanger) {\ + int _i_;\ + if (SGLIB_HEAP_IS_FULL(type, a, i, dim)) {assert(0 && "the heap is full");}\ + _i_ = (i)++;\ + while (_i_ > 0 && comparator(a[_i_/2], a[_i_]) < 0) {\ + elem_exchanger(type, a, (_i_/2), _i_);\ + _i_ = _i_/2;\ + }\ +} +#define SGLIB_HEAP_ADD(type, a, elem, i, dim, comparator) {\ + if (SGLIB_HEAP_IS_FULL(type, a, i, dim)) {assert(0 && "the heap is full");}\ + a[i] = (elem);\ + SGLIB_HEAP_ADD_NEXT(type, a, i, dim, comparator, SGLIB_ARRAY_ELEMENTS_EXCHANGER);\ +} +#define SGLIB_HEAP_DELETE_FIRST(type, a, i, dim, comparator, elem_exchanger) {\ + if (SGLIB_HEAP_IS_EMPTY(type, a, i)) {assert(0 && "the heap is empty");}\ + (i)--;\ + a[0] = a[i];\ + SGLIB___ARRAY_HEAP_DOWN(type, a, 0, i, comparator, elem_exchanger);\ +} +#define SGLIB_HEAP_DELETE(type, a, i, dim, comparator) {\ + SGLIB_HEAP_DELETE_FIRST(type, a, i, dim, comparator, SGLIB_ARRAY_ELEMENTS_EXCHANGER);\ +} + + +/* ----------------- hashed table of pointers (in an array) -------------------- */ + +/* + + This hashed table is storing pointers to objects (not containers). + In this table there is a one-to-one mapping between 'objects' stored + in the table and indexes where they are placed. Each index is + pointing to exactly one 'object' and each 'object' stored in the + table occurs on exactly one index. Once an object is stored in the + table, it can be represented via its index. + + In case of collision while adding an object the index shifted + by SGLIB_HASH_TAB_SHIFT_CONSTANT (constant can be redefined) + + You can NOT delete an element from such hash table. The only + justification (I can see) for this data structure is an exchange + file format, having an index table at the beginning and then + refering objects via indexes. + + !!!!!!! This data structure is NOT documented, do not use it !!!!!!!!!! + +*/ + +#define SGLIB_HASH_TAB_INIT(type, table, dim) {\ + int _i_;\ + for(_i_ = 0; _i_ < (dim); _i_++) (table)[_i_] = NULL;\ +} + +#define SGLIB_HASH_TAB_ADD_IF_NOT_MEMBER(type, table, dim, elem, hash_function, comparator, member){\ + unsigned _pos_;\ + type *_elem_;\ + SGLIB_HASH_TAB_FIND_MEMBER(type, table, dim, elem, _pos_, _elem_);\ + (member) = (table)[_pos_];\ + if (_elem_ == NULL) {\ + if ((table)[_pos_] != NULL) {assert(0 && "the hash table is full");}\ + (table)[_pos_] = (elem);\ + }\ +} + +#define SGLIB_HASH_TAB_FIND_MEMBER(type, table, dim, elem, hash_function, comparator, resultIndex, resultMember) {\ + unsigned _i_;\ + int _count_;\ + type *_e_;\ + _count = 0;\ + _i_ = hash_function(elem);\ + _i_ %= (dim);\ + while ((_e_=(table)[_i_])!=NULL && comparator(_e_, (elem))!=0 && _count_<(dim)) {\ + _count_ ++;\ + _i_ = (_i_ + SGLIB_HASH_TAB_SHIFT_CONSTANT) % (dim);\ + }\ + (resultIndex) = _i_;\ + if (_count_ < (dim)) (resultMember) = _e_;\ + else (resultMember) = NULL;\ +} + +#define SGLIB_HASH_TAB_IS_MEMBER(type, table, dim, elem, hash_function, resultIndex) {\ + unsigned _i_;\ + int _c_;\ + type *_e_;\ + _count = 0;\ + _i_ = hash_function(elem);\ + _i_ %= (dim);\ + while ((_e_=(table)[_i_])!=NULL && _e_!=(elem) && _c_<(dim)) {\ + _c_ ++;\ + _i_ = (_i_ + SGLIB_HASH_TAB_SHIFT_CONSTANT) % (dim);\ + }\ + if (_e_==(elem)) (resultIndex) = _i_;\ + else (resultIndex) = -1;\ +} + +#define SGLIB_HASH_TAB_MAP_ON_ELEMENTS(type, table, dim, iteratedIndex, iteratedVariable, command) {\ + unsigned iteratedIndex;\ + type *iteratedVariable;\ + for(iteratedIndex=0; iteratedIndex < (dim); iteratedIndex++) {\ + iteratedVariable = (table)[iteratedIndex];\ + if (iteratedVariable != NULL) {command;}\ + }\ +} + + +/* ---------------------------------------------------------------------------- */ +/* ------------------------- DYNAMIC DATA STRUCTURES -------------------------- */ +/* ---------------------------------------------------------------------------- */ + +/* ------------------------------------ lists (level 0) --------------------- */ + +#define SGLIB_LIST_ADD(type, list, elem, next) {\ + (elem)->next = (list);\ + (list) = (elem);\ +} + +#define SGLIB_LIST_CONCAT(type, first, second, next) {\ + if ((first)==NULL) {\ + (first) = (second);\ + } else {\ + type *_p_;\ + for(_p_ = (first); _p_->next!=NULL; _p_=_p_->next) ;\ + _p_->next = (second);\ + }\ +} + +#define SGLIB_LIST_DELETE(type, list, elem, next) {\ + type **_p_;\ + for(_p_ = &(list); *_p_!=NULL && *_p_!=(elem); _p_= &(*_p_)->next) ;\ + assert(*_p_!=NULL && "element is not member of the container, use DELETE_IF_MEMBER instead"!=NULL);\ + *_p_ = (*_p_)->next;\ +} + +#define SGLIB_LIST_ADD_IF_NOT_MEMBER(type, list, elem, comparator, next, member) {\ + type *_p_;\ + for(_p_ = (list); _p_!=NULL && comparator(_p_, (elem)) != 0; _p_= _p_->next) ;\ + (member) = _p_;\ + if (_p_ == NULL) {\ + SGLIB_LIST_ADD(type, list, elem, next);\ + }\ +} + +#define SGLIB_LIST_DELETE_IF_MEMBER(type, list, elem, comparator, next, member) {\ + type **_p_;\ + for(_p_ = &(list); *_p_!=NULL && comparator((*_p_), (elem)) != 0; _p_= &(*_p_)->next) ;\ + (member) = *_p_;\ + if (*_p_ != NULL) {\ + *_p_ = (*_p_)->next;\ + }\ +} + +#define SGLIB_LIST_IS_MEMBER(type, list, elem, next, result) {\ + type *_p_;\ + for(_p_ = (list); _p_!=NULL && _p_ != (elem); _p_= _p_->next) ;\ + (result) = (_p_!=NULL);\ +} + +#define SGLIB_LIST_FIND_MEMBER(type, list, elem, comparator, next, member) {\ + type *_p_;\ + for(_p_ = (list); _p_!=NULL && comparator(_p_, (elem)) != 0; _p_= _p_->next) ;\ + (member) = _p_;\ +} + +#define SGLIB_LIST_MAP_ON_ELEMENTS(type, list, iteratedVariable, next, command) {\ + type *_ne_;\ + type *iteratedVariable;\ + (iteratedVariable) = (list); \ + while ((iteratedVariable)!=NULL) {\ + _ne_ = (iteratedVariable)->next;\ + {command;};\ + (iteratedVariable) = _ne_;\ + }\ +} + +#define SGLIB_LIST_LEN(type, list, next, result) {\ + type *_ce_;\ + (result) = 0;\ + SGLIB_LIST_MAP_ON_ELEMENTS(type, list, _ce_, next, (result)++);\ +} + +#define SGLIB_LIST_REVERSE(type, list, next) {\ + type *_list_,*_tmp_,*_res_;\ + _list_ = (list);\ + _res_ = NULL;\ + while (_list_!=NULL) {\ + _tmp_ = _list_->next; _list_->next = _res_;\ + _res_ = _list_; _list_ = _tmp_;\ + }\ + (list) = _res_;\ +} + +#define SGLIB_LIST_SORT(type, list, comparator, next) {\ + /* a non-recursive merge sort on lists */\ + type *_r_;\ + type *_a_, *_b_, *_todo_, *_t_, **_restail_;\ + int _i_, _n_, _contFlag_;\ + _r_ = (list);\ + _contFlag_ = 1;\ + for(_n_ = 1; _contFlag_; _n_ = _n_+_n_) {\ + _todo_ = _r_; _r_ = NULL; _restail_ = &_r_; _contFlag_ =0;\ + while (_todo_!=NULL) {\ + _a_ = _todo_;\ + for(_i_ = 1, _t_ = _a_; _i_ < _n_ && _t_!=NULL; _i_++, _t_ = _t_->next) ;\ + if (_t_ ==NULL) {\ + *_restail_ = _a_;\ + break;\ + }\ + _b_ = _t_->next; _t_->next=NULL;\ + for(_i_ =1, _t_ = _b_; _i_<_n_ && _t_!=NULL; _i_++, _t_ = _t_->next) ;\ + if (_t_ ==NULL) {\ + _todo_ =NULL;\ + } else {\ + _todo_ = _t_->next; _t_->next=NULL;\ + }\ + /* merge */\ + while (_a_!=NULL && _b_!=NULL) {\ + if (comparator(_a_, _b_) < 0) {\ + *_restail_ = _a_; _restail_ = &(_a_->next); _a_ = _a_->next;\ + } else {\ + *_restail_ = _b_; _restail_ = &(_b_->next); _b_ = _b_->next;\ + }\ + }\ + if (_a_!=NULL) *_restail_ = _a_;\ + else *_restail_ = _b_;\ + while (*_restail_!=NULL) _restail_ = &((*_restail_)->next);\ + _contFlag_ =1;\ + }\ + }\ + (list) = _r_;\ +} + +/* --------------------------------- sorted list (level 0) --------------------- */ +/* + All operations suppose that the list is sorted and they preserve + this property. +*/ + + +#define SGLIB_SORTED_LIST_ADD(type, list, elem, comparator, next) {\ + type **_e_;\ + int _cmpres_;\ + SGLIB_SORTED_LIST_FIND_MEMBER_OR_PLACE(type, list, elem, comparator, next, _cmpres_, _e_);\ + (elem)->next = *_e_;\ + *_e_ = (elem);\ +} + +#define SGLIB_SORTED_LIST_ADD_IF_NOT_MEMBER(type, list, elem, comparator, next, member) {\ + type **_e_;\ + int _cmp_res_;\ + SGLIB_SORTED_LIST_FIND_MEMBER_OR_PLACE(type, list, elem, comparator, next, _cmp_res_, _e_);\ + if (_cmp_res_ != 0) {\ + (elem)->next = *_e_;\ + *_e_ = (elem);\ + (member) = NULL;\ + } else {\ + (member) = *_e_;\ + }\ +} + +#define SGLIB_SORTED_LIST_DELETE(type, list, elem, next) {\ + SGLIB_LIST_DELETE(type, list, elem, next);\ +} + +#define SGLIB_SORTED_LIST_DELETE_IF_MEMBER(type, list, elem, comparator, next, member) {\ + type **_e_;\ + int _cmp_res_;\ + SGLIB_SORTED_LIST_FIND_MEMBER_OR_PLACE(type, list, elem, comparator, next, _cmp_res_, _e_);\ + if (_cmp_res_ == 0) {\ + (member) = *_e_;\ + *_e_ = (*_e_)->next;\ + } else {\ + (member) = NULL;\ + }\ +} + +#define SGLIB_SORTED_LIST_FIND_MEMBER(type, list, elem, comparator, next, member) {\ + type *_p_;\ + int _cmpres_ = 1;\ + for(_p_ = (list); _p_!=NULL && (_cmpres_=comparator(_p_, (elem))) < 0; _p_=_p_->next) ;\ + if (_cmpres_ != 0) (member) = NULL;\ + else (member) = _p_;\ +} + +#define SGLIB_SORTED_LIST_IS_MEMBER(type, list, elem, comparator, next, result) {\ + type *_p_;\ + for(_p_ = (list); _p_!=NULL && comparator(_p_, (elem)) < 0; _p_=_p_->next) ;\ + while (_p_ != NULL && _p_ != (elem) && comparator(_p_, (elem)) == 0) _p_=_p_->next;\ + (result) = (_p_ == (elem));\ +} + +#define SGLIB_SORTED_LIST_FIND_MEMBER_OR_PLACE(type, list, elem, comparator, next, comparator_result, member_ptr) {\ + (comparator_result) = -1;\ + for((member_ptr) = &(list); \ + *(member_ptr)!=NULL && ((comparator_result)=comparator((*member_ptr), (elem))) < 0; \ + (member_ptr) = &(*(member_ptr))->next) ;\ +} + +#define SGLIB_SORTED_LIST_LEN(type, list, next, result) {\ + SGLIB_LIST_LEN(type, list, next, result);\ +} + +#define SGLIB_SORTED_LIST_MAP_ON_ELEMENTS(type, list, iteratedVariable, next, command) {\ + SGLIB_LIST_MAP_ON_ELEMENTS(type, list, iteratedVariable, next, command);\ +} + + +/* ------------------------------- double linked list (level 0) ------------------------- */ +/* + Lists with back pointer to previous element. Those lists implements deletion + of an element in a constant time. +*/ + +#define SGLIB___DL_LIST_CREATE_SINGLETON(type, list, elem, previous, next) {\ + (list) = (elem);\ + (list)->next = (list)->previous = NULL;\ +} + +#define SGLIB_DL_LIST_ADD_AFTER(type, place, elem, previous, next) {\ + if ((place) == NULL) {\ + SGLIB___DL_LIST_CREATE_SINGLETON(type, place, elem, previous, next);\ + } else {\ + (elem)->next = (place)->next;\ + (elem)->previous = (place);\ + (place)->next = (elem);\ + if ((elem)->next != NULL) (elem)->next->previous = (elem);\ + }\ +} + +#define SGLIB_DL_LIST_ADD_BEFORE(type, place, elem, previous, next) {\ + if ((place) == NULL) {\ + SGLIB___DL_LIST_CREATE_SINGLETON(type, place, elem, previous, next);\ + } else {\ + (elem)->next = (place);\ + (elem)->previous = (place)->previous;\ + (place)->previous = (elem);\ + if ((elem)->previous != NULL) (elem)->previous->next = (elem);\ + }\ +} + +#define SGLIB_DL_LIST_ADD(type, list, elem, previous, next) {\ + SGLIB_DL_LIST_ADD_BEFORE(type, list, elem, previous, next)\ +} + +#define SGLIB___DL_LIST_GENERIC_ADD_IF_NOT_MEMBER(type, list, elem, comparator, previous, next, member, the_add_operation) {\ + type *_dlp_;\ + for(_dlp_ = (list); _dlp_!=NULL && comparator(_dlp_, (elem)) != 0; _dlp_= _dlp_->previous) ;\ + if (_dlp_ == NULL && (list) != NULL) {\ + for(_dlp_ = (list)->next; _dlp_!=NULL && comparator(_dlp_, (elem)) != 0; _dlp_= _dlp_->next) ;\ + }\ + (member) = _dlp_;\ + if (_dlp_ == NULL) {\ + the_add_operation(type, list, elem, previous, next);\ + }\ +} + +#define SGLIB_DL_LIST_ADD_BEFORE_IF_NOT_MEMBER(type, list, elem, comparator, previous, next, member) {\ + SGLIB___DL_LIST_GENERIC_ADD_IF_NOT_MEMBER(type, list, elem, comparator, previous, next, member, SGLIB_DL_LIST_ADD_BEFORE);\ +} + +#define SGLIB_DL_LIST_ADD_AFTER_IF_NOT_MEMBER(type, list, elem, comparator, previous, next, member) {\ + SGLIB___DL_LIST_GENERIC_ADD_IF_NOT_MEMBER(type, list, elem, comparator, previous, next, member, SGLIB_DL_LIST_ADD_AFTER);\ +} + +#define SGLIB_DL_LIST_ADD_IF_NOT_MEMBER(type, list, elem, comparator, previous, next, member) {\ + SGLIB___DL_LIST_GENERIC_ADD_IF_NOT_MEMBER(type, list, elem, comparator, previous, next, member, SGLIB_DL_LIST_ADD);\ +} + +#define SGLIB_DL_LIST_CONCAT(type, first, second, previous, next) {\ + if ((first)==NULL) {\ + (first) = (second);\ + } else if ((second)!=NULL) {\ + type *_dlp_;\ + for(_dlp_ = (first); _dlp_->next!=NULL; _dlp_=_dlp_->next) ;\ + SGLIB_DL_LIST_ADD_AFTER(type, _dlp_, second, previous, next);\ + }\ +} + +#define SGLIB_DL_LIST_DELETE(type, list, elem, previous, next) {\ + type *_l_;\ + _l_ = (list);\ + if (_l_ == (elem)) {\ + if ((elem)->previous != NULL) _l_ = (elem)->previous;\ + else _l_ = (elem)->next;\ + }\ + if ((elem)->next != NULL) (elem)->next->previous = (elem)->previous;\ + if ((elem)->previous != NULL) (elem)->previous->next = (elem)->next;\ + (list) = _l_;\ +} + +#define SGLIB_DL_LIST_DELETE_IF_MEMBER(type, list, elem, comparator, previous, next, member) {\ + type *_dlp_;\ + for(_dlp_ = (list); _dlp_!=NULL && comparator(_dlp_, (elem)) != 0; _dlp_= _dlp_->previous) ;\ + if (_dlp_ == NULL && (list) != NULL) {\ + for(_dlp_ = (list)->next; _dlp_!=NULL && comparator(_dlp_, (elem)) != 0; _dlp_= _dlp_->next) ;\ + }\ + (member) = _dlp_;\ + if (_dlp_ != NULL) {\ + SGLIB_DL_LIST_DELETE(type, list, _dlp_, previous, next);\ + }\ +} + +#define SGLIB_DL_LIST_IS_MEMBER(type, list, elem, previous, next, result) {\ + type *_dlp_;\ + SGLIB_LIST_IS_MEMBER(type, list, elem, previous, result);\ + if (result == 0 && (list) != NULL) {\ + _dlp_ = (list)->next;\ + SGLIB_LIST_IS_MEMBER(type, _dlp_, elem, next, result);\ + }\ +} + +#define SGLIB_DL_LIST_FIND_MEMBER(type, list, elem, comparator, previous, next, member) {\ + type *_dlp_;\ + SGLIB_LIST_FIND_MEMBER(type, list, elem, comparator, previous, member);\ + if ((member) == NULL && (list) != NULL) {\ + _dlp_ = (list)->next;\ + SGLIB_LIST_FIND_MEMBER(type, _dlp_, elem, comparator, next, member);\ + }\ +} + +#define SGLIB_DL_LIST_MAP_ON_ELEMENTS(type, list, iteratedVariable, previous, next, command) {\ + type *_dl_;\ + type *iteratedVariable;\ + if ((list)!=NULL) {\ + _dl_ = (list)->next;\ + SGLIB_LIST_MAP_ON_ELEMENTS(type, list, iteratedVariable, previous, command);\ + SGLIB_LIST_MAP_ON_ELEMENTS(type, _dl_, iteratedVariable, next, command);\ + }\ +} + +#define SGLIB_DL_LIST_SORT(type, list, comparator, previous, next) {\ + type *_dll_, *_dlp_, *_dlt_;\ + _dll_ = (list);\ + if (_dll_ != NULL) {\ + for(; _dll_->previous!=NULL; _dll_=_dll_->previous) ;\ + SGLIB_LIST_SORT(type, _dll_, comparator, next);\ + SGLIB___DL_LIST_CREATE_FROM_LIST(type, _dll_, previous, next);\ + (list) = _dll_;\ + }\ +} + +#define SGLIB_DL_LIST_GET_FIRST(type, list, previous, next, result) {\ + type *_dll_;\ + _dll_ = (list);\ + if (_dll_ != NULL) {\ + for(; _dll_->previous!=NULL; _dll_=_dll_->previous) ;\ + }\ + (result) = _dll_;\ +} + +#define SGLIB_DL_LIST_GET_LAST(type, list, previous, next, result) {\ + type *_dll_;\ + _dll_ = (list);\ + if (_dll_ != NULL) {\ + for(; _dll_->next!=NULL; _dll_=_dll_->next) ;\ + }\ + (result) = _dll_;\ +} + +#define SGLIB_DL_LIST_LEN(type, list, previous, next, result) {\ + type *_dl_;\ + int _r1_, _r2_;\ + if ((list)==NULL) {\ + (result) = 0;\ + } else {\ + SGLIB_LIST_LEN(type, list, previous, _r1_);\ + _dl_ = (list)->next;\ + SGLIB_LIST_LEN(type, _dl_, next, _r2_);\ + (result) = _r1_ + _r2_;\ + }\ +} + +#define SGLIB_DL_LIST_REVERSE(type, list, previous, next) {\ + type *_list_,*_nlist_,*_dlp_,*_dln_;\ + _list_ = (list);\ + if (_list_!=NULL) {\ + _nlist_ = _list_->next;\ + while (_list_!=NULL) {\ + _dln_ = _list_->next; \ + _dlp_ = _list_->previous; \ + _list_->next = _dlp_;\ + _list_->previous = _dln_;\ + _list_ = _dlp_;\ + }\ + while (_nlist_!=NULL) {\ + _dln_ = _nlist_->next; \ + _dlp_ = _nlist_->previous; \ + _nlist_->next = _dlp_;\ + _nlist_->previous = _dln_;\ + _nlist_ = _dln_;\ + }\ + }\ +} + +#define SGLIB___DL_LIST_CREATE_FROM_LIST(type, list, previous, next) {\ + type *_dlp_, *_dlt_;\ + _dlp_ = NULL;\ + for(_dlt_ = (list); _dlt_!=NULL; _dlt_ = _dlt_->next) {\ + _dlt_->previous = _dlp_;\ + _dlp_ = _dlt_;\ + }\ +} + + +/* ------------------------------- binary tree traversal (level 0) -------------------- */ + + +#define SGLIB___BIN_TREE_MAP_ON_ELEMENTS(type, tree, iteratedVariable, order, left, right, command) {\ + /* this is non-recursive implementation of tree traversal */\ + /* it maintains the path to the current node in the array '_path_' */\ + /* the _path_[0] contains the root of the tree; */\ + /* the _path_[_pathi_] contains the _current_element_ */\ + /* the macro does not use the _current_element_ after execution of command */\ + /* command can destroy it, it can free the element for example */\ + type *_path_[SGLIB_MAX_TREE_DEEP];\ + type *_right_[SGLIB_MAX_TREE_DEEP];\ + char _pass_[SGLIB_MAX_TREE_DEEP];\ + type *_cn_;\ + int _pathi_;\ + type *iteratedVariable;\ + _cn_ = (tree);\ + _pathi_ = 0;\ + while (_cn_!=NULL) {\ + /* push down to leftmost innermost element */\ + while(_cn_!=NULL) {\ + _path_[_pathi_] = _cn_;\ + _right_[_pathi_] = _cn_->right;\ + _pass_[_pathi_] = 0;\ + _cn_ = _cn_->left;\ + if (order == 0) {\ + iteratedVariable = _path_[_pathi_];\ + {command;}\ + }\ + _pathi_ ++;\ + if (_pathi_ >= SGLIB_MAX_TREE_DEEP) {assert(0 && "the binary_tree is too deep");}\ + }\ + do {\ + _pathi_ --;\ + if ((order==1 && _pass_[_pathi_] == 0)\ + || (order == 2 && (_pass_[_pathi_] == 1 || _right_[_pathi_]==NULL))) {\ + iteratedVariable = _path_[_pathi_];\ + {command;}\ + }\ + _pass_[_pathi_] ++;\ + } while (_pathi_>0 && _right_[_pathi_]==NULL) ;\ + _cn_ = _right_[_pathi_];\ + _right_[_pathi_] = NULL;\ + _pathi_ ++;\ + }\ +} + +#define SGLIB_BIN_TREE_MAP_ON_ELEMENTS(type, tree, _current_element_, left, right, command) {\ + SGLIB___BIN_TREE_MAP_ON_ELEMENTS(type, tree, _current_element_, 1, left, right, command);\ +} + +#define SGLIB_BIN_TREE_MAP_ON_ELEMENTS_PREORDER(type, tree, _current_element_, left, right, command) {\ + SGLIB___BIN_TREE_MAP_ON_ELEMENTS(type, tree, _current_element_, 0, left, right, command);\ +} + +#define SGLIB_BIN_TREE_MAP_ON_ELEMENTS_POSTORDER(type, tree, _current_element_, left, right, command) {\ + SGLIB___BIN_TREE_MAP_ON_ELEMENTS(type, tree, _current_element_, 2, left, right, command);\ +} + +#define SGLIB___BIN_TREE_FIND_MEMBER(type, tree, elem, left, right, comparator, res) {\ + type *_s_;\ + int _c_;\ + _s_ = (tree);\ + while (_s_!=NULL) {\ + _c_ = comparator((elem), _s_);\ + if (_c_ < 0) _s_ = _s_->left;\ + else if (_c_ > 0) _s_ = _s_->right;\ + else break;\ + }\ + (res) = _s_;\ +} + +/* ---------------------------------------------------------------------------- */ +/* ---------------------------------------------------------------------------- */ +/* - LEVEL - 1 INTERFACE - */ +/* ---------------------------------------------------------------------------- */ +/* ---------------------------------------------------------------------------- */ + + + +/* ---------------------------------------------------------------------------- */ +/* ------------------------------ STATIC ARRAYS ------------------------------- */ +/* ---------------------------------------------------------------------------- */ + +/* ----------------------------- array sorting (level 1) ---------------------- */ + +#define SGLIB_DEFINE_ARRAY_SORTING_PROTOTYPES(type, comparator) \ + extern void sglib_##type##_array_quick_sort(type *a, int max);\ + extern void sglib_##type##_array_heap_sort(type *a, int max);\ + + +#define SGLIB_DEFINE_ARRAY_SORTING_FUNCTIONS(type, comparator) \ + void sglib_##type##_array_quick_sort(type *a, int max) {\ + SGLIB_ARRAY_SINGLE_QUICK_SORT(type, a, max, comparator);\ + }\ + void sglib_##type##_array_heap_sort(type *a, int max) {\ + SGLIB_ARRAY_SINGLE_HEAP_SORT(type, a, max, comparator);\ + }\ + + +/* ----------------------------- array queue (level 1) ------------------- */ +/* sglib's queue is stored in a fixed sized array */ +/* queue_type MUST be a structure containing fields: */ +/* afield is the array storing elem_type */ +/* ifield is the index of the first element in the queue */ +/* jfield is the index of the first free element after the queue */ +/* dim is the size of the array afield */ +/* !!!!!!! This data structure is NOT documented, do not use it !!!!!!!!!! */ + + +#define SGLIB_DEFINE_QUEUE_PROTOTYPES(queue_type, elem_type, afield, ifield, jfield, dim) \ + extern void sglib_##queue_type##_init(queue_type *q); \ + extern int sglib_##queue_type##_is_empty(queue_type *q); \ + extern int sglib_##queue_type##_is_full(queue_type *q); \ + extern elem_type sglib_##queue_type##_first_element(queue_type *q); \ + extern elem_type *sglib_##queue_type##_first_element_ptr(queue_type *q); \ + extern void sglib_##queue_type##_add_next(queue_type *q); \ + extern void sglib_##queue_type##_add(queue_type *q, elem_type elem); \ + extern void sglib_##queue_type##_delete_first(queue_type *q); \ + extern void sglib_##queue_type##_delete(queue_type *q); + + +#define SGLIB_DEFINE_QUEUE_FUNCTIONS(queue_type, elem_type, afield, ifield, jfield, dim) \ + void sglib_##queue_type##_init(queue_type *q) {\ + SGLIB_QUEUE_INIT(elem_type, q->afield, q->ifield, q->jfield);\ + }\ + int sglib_##queue_type##_is_empty(queue_type *q) {\ + return(SGLIB_QUEUE_IS_EMPTY(elem_type, q->afield, q->ifield, q->jfield));\ + }\ + int sglib_##queue_type##_is_full(queue_type *q) {\ + return(SGLIB_QUEUE_IS_FULL(elem_type, q->afield, q->ifield, q->jfield, dim));\ + }\ + elem_type sglib_##queue_type##_first_element(queue_type *q) {\ + return(SGLIB_QUEUE_FIRST_ELEMENT(elem_type, q->afield, q->ifield, q->jfield));\ + }\ + elem_type *sglib_##queue_type##_first_element_ptr(queue_type *q) {\ + return(& SGLIB_QUEUE_FIRST_ELEMENT(elem_type, q->afield, q->ifield, q->jfield));\ + }\ + void sglib_##queue_type##_add_next(queue_type *q) {\ + SGLIB_QUEUE_ADD_NEXT(elem_type, q->afield, q->ifield, q->jfield, dim);\ + }\ + void sglib_##queue_type##_add(queue_type *q, elem_type elem) {\ + SGLIB_QUEUE_ADD(elem_type, q->afield, elem, q->ifield, q->jfield, dim);\ + }\ + void sglib_##queue_type##_delete_first(queue_type *q) {\ + SGLIB_QUEUE_DELETE_FIRST(elem_type, q->afield, q->ifield, q->jfield, dim);\ + }\ + void sglib_##queue_type##_delete(queue_type *q) {\ + SGLIB_QUEUE_DELETE_FIRST(elem_type, q->afield, q->ifield, q->jfield, dim);\ + } + + +/* ------------------------ array heap (level 1) ------------------------- */ +/* sglib's heap is a priority queue implemented in a fixed sized array */ +/* heap_type MUST be a structure containing fields: */ +/* afield is the array of size dim storing elem_type */ +/* ifield is the index of the first free element after the queue */ +/* !!!!!!! This data structure is NOT documented, do not use it !!!!!!!!!! */ + + +#define SGLIB_DEFINE_HEAP_PROTOTYPES(heap_type, elem_type, afield, ifield, dim, comparator, elem_exchanger) \ + extern void sglib_##heap_type##_init(heap_type *q); \ + extern int sglib_##heap_type##_is_empty(heap_type *q); \ + extern int sglib_##heap_type##_is_full(heap_type *q); \ + extern elem_type sglib_##heap_type##_first_element(heap_type *q); \ + extern elem_type *sglib_##heap_type##_first_element_ptr(heap_type *q); \ + extern void sglib_##heap_type##_add_next(heap_type *q); \ + extern void sglib_##heap_type##_add(heap_type *q, elem_type elem); \ + extern void sglib_##heap_type##_delete_first(heap_type *q); \ + extern void sglib_##heap_type##_delete(heap_type *q) + +#define SGLIB_DEFINE_HEAP_FUNCTIONS(heap_type, elem_type, afield, ifield, dim, comparator, elem_exchanger) \ + void sglib_##heap_type##_init(heap_type *q) {\ + SGLIB_HEAP_INIT(elem_type, q->afield, q->ifield);\ + }\ + int sglib_##heap_type##_is_empty(heap_type *q) {\ + return(SGLIB_HEAP_IS_EMPTY(elem_type, q->afield, q->ifield));\ + }\ + int sglib_##heap_type##_is_full(heap_type *q) {\ + return(SGLIB_HEAP_IS_FULL(elem_type, q->afield, q->ifield));\ + }\ + elem_type sglib_##heap_type##_first_element(heap_type *q) {\ + return(SGLIB_HEAP_FIRST_ELEMENT(elem_type, q->afield, q->ifield));\ + }\ + elem_type *sglib_##heap_type##_first_element_ptr(heap_type *q) {\ + return(& SGLIB_HEAP_FIRST_ELEMENT(elem_type, q->afield, q->ifield));\ + }\ + void sglib_##heap_type##_add_next(heap_type *q) {\ + SGLIB_HEAP_ADD_NEXT(elem_type, q->afield, q->ifield, dim, comparator, elem_exchanger);\ + }\ + void sglib_##heap_type##_add(heap_type *q, elem_type elem) {\ + SGLIB_HEAP_ADD(elem_type, q->afield, elem, q->ifield, dim, comparator, elem_exchanger);\ + }\ + void sglib_##heap_type##_delete_first(heap_type *q) {\ + SGLIB_HEAP_DELETE_FIRST(elem_type, q->afield, q->ifield, dim, comparator, elem_exchanger);\ + }\ + void sglib_##heap_type##_delete(heap_type *q) {\ + SGLIB_HEAP_DELETE_FIRST(elem_type, q->afield, q->ifield, dim, comparator, elem_exchanger);\ + } + + +/* ------------------------ hashed table (level 1) ------------------------- */ +/* + + sglib's hash table is an array storing directly pointers to objects (not containers). + In this table there is a one-to-one mapping between 'objects' stored + in the table and indexes where they are placed. Each index is + pointing to exactly one 'object' and each 'object' stored in the + table occurs on exactly one index. Once an object is stored in the + table, it can be represented via its index. + + type - is the type of elements + dim - is the size of the hash array + hash_function - is a hashing function mapping type* to unsigned + comparator - is a comparator on elements + + !!!!!!! This data structure is NOT documented, do not use it !!!!!!!!!! +*/ + +#define SGLIB_DEFINE_HASHED_TABLE_PROTOTYPES(type, dim, hash_function, comparator) \ + struct sglib_hashed_##type##_iterator {\ + int currentIndex;\ + int (*subcomparator)(type *, type *);\ + type *equalto;\ + };\ + extern void sglib_hashed_##type##_init(type *table[dim]);\ + extern int sglib_hashed_##type##_add_if_not_member(type *table[dim], type *elem, type **member);\ + extern int sglib_hashed_##type##_is_member(type *table[dim], type *elem);\ + extern type * sglib_hashed_##type##_find_member(type *table[dim], type *elem);\ + extern type *sglib_hashed_##type##_it_init(struct sglib_hashed_##type##_iterator *it, type *table[dim]); \ + extern type *sglib_hashed_##type##_it_init_on_equal(struct sglib_hashed_##type##_iterator *it, type *table[dim], int (*subcomparator)(type *, type *), type *equalto); \ + extern type *sglib_hashed_##type##_it_current(struct sglib_hashed_##type##_iterator *it); \ + extern type *sglib_hashed_##type##_it_next(struct sglib_hashed_##type##_iterator *it); + +#define SGLIB_DEFINE_HASHED_TABLE_FUNCTIONS(type, dim, hash_function, comparator) \ + struct sglib_hashed_##type##_iterator {\ + int currentIndex;\ + type **table;\ + int (*subcomparator)(type *, type *);\ + type *equalto;\ + };\ + void sglib_hashed_##type##_init(type *table[dim]) {\ + SGLIB_HASH_TAB_INIT(type, table, dim);\ + }\ + int sglib_hashed_##type##_add_if_not_member(type *table[dim], type *elem, type **member) {\ + SGLIB_HASH_TAB_ADD_IF_NOT_MEMBER(type, table, dim, elem, hash_function, comparator, *member);\ + }\ + int sglib_hashed_##type##_is_member(type *table[dim], type *elem) {\ + int ind;\ + SGLIB_HASH_TAB_IS_MEMBER(type, table, dim, elem, hash_function, ind);\ + return(ind != -1);\ + }\ + type * sglib_hashed_##type##_find_member(type *table[dim], type *elem) {\ + type *mmb;\ + int ind;\ + SGLIB_HASH_TAB_FIND_MEMBER(type, table, dim, elem, hash_function, comparator, ind, mmb);\ + return(mmb);\ + }\ + type *sglib_hashed_##type##_it_init_on_equal(struct sglib_hashed_##type##_iterator *it, type *table[dim], int (*subcomparator)(type *, type *), type *equalto) {\ + int i;\ + it->table = table;\ + it->subcomparator = subcomparator;\ + it->equalto = equalto;\ + for(i=0; i<(dim) && table[i]==NULL; i++) ;\ + it->currentIndex = i;\ + if (i<(dim)) return(table[i]);\ + return(NULL);\ + }\ + type *sglib_hashed_##type##_it_init(struct sglib_hashed_##type##_iterator *it, type *table[dim]) {\ + sglib_hashed_##type##_it_init_on_equal(it, table, NULL, NULL);\ + }\ + type *sglib_hashed_##type##_it_current(struct sglib_hashed_##type##_iterator *it) {\ + return(table[it->currentIndex]);\ + }\ + type *sglib_hashed_##type##_it_next(struct sglib_hashed_##type##_iterator *it) {\ + i=it->currentIndex;\ + if (i<(dim)) {\ + for(i++; i<(dim) && table[i]==NULL; i++) ;\ + }\ + it->currentIndex = i;\ + if (i<(dim)) return(table[i]);\ + return(NULL);\ + } + + +/* ------------------- hashed container (only for level 1) -------------------- */ +/* + hashed container is a table of given fixed size containing another + (dynamic) base container in each cell. Once an object should be + inserted into the hashed container, a hash function is used to + determine the cell where the object belongs and the object is + inserted into the base container stored in this cell. Usually the + base container is simply a list or a sorted list, but it can be a + red-black tree as well. + + parameters: + type - the type of the container stored in each cell. + dim - the size of the hashed array + hash_function - the hashing function hashing 'type *' to unsigned. + +*/ + +#define SGLIB_DEFINE_HASHED_CONTAINER_PROTOTYPES(type, dim, hash_function) \ + struct sglib_hashed_##type##_iterator {\ + struct sglib_##type##_iterator containerIt;\ + type **table;\ + int currentIndex;\ + int (*subcomparator)(type *, type *);\ + type *equalto;\ + };\ + extern void sglib_hashed_##type##_init(type *table[dim]);\ + extern void sglib_hashed_##type##_add(type *table[dim], type *elem);\ + extern int sglib_hashed_##type##_add_if_not_member(type *table[dim], type *elem, type **member);\ + extern void sglib_hashed_##type##_delete(type *table[dim], type *elem);\ + extern int sglib_hashed_##type##_delete_if_member(type *table[dim], type *elem, type **memb);\ + extern int sglib_hashed_##type##_is_member(type *table[dim], type *elem);\ + extern type * sglib_hashed_##type##_find_member(type *table[dim], type *elem);\ + extern type *sglib_hashed_##type##_it_init(struct sglib_hashed_##type##_iterator *it, type *table[dim]); \ + extern type *sglib_hashed_##type##_it_init_on_equal(struct sglib_hashed_##type##_iterator *it, type *table[dim], int (*subcomparator)(type *, type *), type *equalto); \ + extern type *sglib_hashed_##type##_it_current(struct sglib_hashed_##type##_iterator *it); \ + extern type *sglib_hashed_##type##_it_next(struct sglib_hashed_##type##_iterator *it); + +#define SGLIB_DEFINE_HASHED_CONTAINER_FUNCTIONS(type, dim, hash_function) \ + /*extern unsigned hash_function(type *elem);*/\ + void sglib_hashed_##type##_init(type *table[dim]) {\ + unsigned i;\ + for(i=0; i<(dim); i++) table[i] = NULL;\ + }\ + void sglib_hashed_##type##_add(type *table[dim], type *elem) {\ + unsigned i;\ + i = ((unsigned)hash_function(elem)) % (dim);\ + sglib_##type##_add(&(table)[i], elem);\ + }\ + int sglib_hashed_##type##_add_if_not_member(type *table[dim], type *elem, type **member) {\ + unsigned i;\ + i = ((unsigned)hash_function(elem)) % (dim);\ + return(sglib_##type##_add_if_not_member(&(table)[i], elem, member));\ + }\ + void sglib_hashed_##type##_delete(type *table[dim], type *elem) {\ + unsigned i;\ + i = ((unsigned)hash_function(elem)) % (dim);\ + sglib_##type##_delete(&(table)[i], elem);\ + }\ + int sglib_hashed_##type##_delete_if_member(type *table[dim], type *elem, type **memb) {\ + unsigned i;\ + i = ((unsigned)hash_function(elem)) % (dim);\ + return(sglib_##type##_delete_if_member(&(table)[i], elem, memb));\ + }\ + int sglib_hashed_##type##_is_member(type *table[dim], type *elem) {\ + unsigned i;\ + i = ((unsigned)hash_function(elem)) % (dim);\ + return(sglib_##type##_is_member((table)[i], elem));\ + }\ + type * sglib_hashed_##type##_find_member(type *table[dim], type *elem) {\ + unsigned i;\ + i = ((unsigned)hash_function(elem)) % (dim);\ + return(sglib_##type##_find_member((table)[i], elem));\ + }\ + type *sglib_hashed_##type##_it_init_on_equal(struct sglib_hashed_##type##_iterator *it, type *table[dim], int (*subcomparator)(type *, type *), type *equalto) {\ + type *e;\ + it->table = table;\ + it->currentIndex = 0;\ + it->subcomparator = subcomparator;\ + it->equalto = equalto;\ + e = sglib_##type##_it_init_on_equal(&it->containerIt, table[it->currentIndex], it->subcomparator, it->equalto);\ + if (e==NULL) e = sglib_hashed_##type##_it_next(it);\ + return(e);\ + }\ + type *sglib_hashed_##type##_it_init(struct sglib_hashed_##type##_iterator *it, type *table[dim]) {\ + return(sglib_hashed_##type##_it_init_on_equal(it, table, NULL, NULL));\ + }\ + type *sglib_hashed_##type##_it_current(struct sglib_hashed_##type##_iterator *it) {\ + return(sglib_##type##_it_current(&it->containerIt));\ + }\ + type *sglib_hashed_##type##_it_next(struct sglib_hashed_##type##_iterator *it) {\ + type *e;\ + e = sglib_##type##_it_next(&it->containerIt);\ + while (e==NULL && (++(it->currentIndex))<(dim)) {\ + e = sglib_##type##_it_init_on_equal(&it->containerIt, it->table[it->currentIndex], it->subcomparator, it->equalto);\ + }\ + return(e);\ + } + + + +/* ---------------------------------------------------------------------------- */ +/* ------------------------- DYNAMIC DATA STRUCTURES -------------------------- */ +/* ---------------------------------------------------------------------------- */ + + + +/* ------------------------------------ list (level 1) -------------------------------- */ + +#define SGLIB_DEFINE_LIST_PROTOTYPES(type, comparator, next) \ + struct sglib_##type##_iterator {\ + type *currentelem;\ + type *nextelem;\ + int (*subcomparator)(type *, type *);\ + type *equalto;\ + };\ + extern void sglib_##type##_add(type **list, type *elem);\ + extern int sglib_##type##_add_if_not_member(type **list, type *elem, type **member);\ + extern void sglib_##type##_concat(type **first, type *second);\ + extern void sglib_##type##_delete(type **list, type *elem);\ + extern int sglib_##type##_delete_if_member(type **list, type *elem, type **member);\ + extern int sglib_##type##_is_member(type *list, type *elem);\ + extern type *sglib_##type##_find_member(type *list, type *elem);\ + extern void sglib_##type##_sort(type **list);\ + extern int sglib_##type##_len(type *list);\ + extern void sglib_##type##_reverse(type **list);\ + extern type *sglib_##type##_it_init(struct sglib_##type##_iterator *it, type *list); \ + extern type *sglib_##type##_it_init_on_equal(struct sglib_##type##_iterator *it, type *list, int (*subcomparator)(type *, type *), type *equalto); \ + extern type *sglib_##type##_it_current(struct sglib_##type##_iterator *it); \ + extern type *sglib_##type##_it_next(struct sglib_##type##_iterator *it); + + +#define SGLIB_DEFINE_LIST_FUNCTIONS(type, comparator, next) \ + int sglib_##type##_is_member(type *list, type *elem) {\ + int result;\ + SGLIB_LIST_IS_MEMBER(type, list, elem, next, result);\ + return(result);\ + }\ + type *sglib_##type##_find_member(type *list, type *elem) {\ + type *result;\ + SGLIB_LIST_FIND_MEMBER(type, list, elem, comparator, next, result);\ + return(result);\ + }\ + int sglib_##type##_add_if_not_member(type **list, type *elem, type **member) {\ + SGLIB_LIST_ADD_IF_NOT_MEMBER(type, *list, elem, comparator, next, *member);\ + return(*member==NULL);\ + }\ + void sglib_##type##_add(type **list, type *elem) {\ + SGLIB_LIST_ADD(type, *list, elem, next);\ + }\ + void sglib_##type##_concat(type **first, type *second) {\ + SGLIB_LIST_CONCAT(type, *first, second, next);\ + }\ + void sglib_##type##_delete(type **list, type *elem) {\ + SGLIB_LIST_DELETE(type, *list, elem, next);\ + }\ + int sglib_##type##_delete_if_member(type **list, type *elem, type **member) {\ + SGLIB_LIST_DELETE_IF_MEMBER(type, *list, elem, comparator, next, *member);\ + return(*member!=NULL);\ + }\ + void sglib_##type##_sort(type **list) { \ + SGLIB_LIST_SORT(type, *list, comparator, next);\ + }\ + int sglib_##type##_len(type *list) {\ + int res;\ + SGLIB_LIST_LEN(type, list, next, res);\ + return(res);\ + }\ + void sglib_##type##_reverse(type **list) {\ + SGLIB_LIST_REVERSE(type, *list, next);\ + }\ + \ + type *sglib_##type##_it_init_on_equal(struct sglib_##type##_iterator *it, type *list, int (*subcomparator)(type *, type *), type *equalto) {\ + it->subcomparator = subcomparator;\ + it->equalto = equalto;\ + it->nextelem = list;\ + return(sglib_##type##_it_next(it));\ + }\ + type *sglib_##type##_it_init(struct sglib_##type##_iterator *it, type *list) {\ + return(sglib_##type##_it_init_on_equal(it, list, NULL, NULL));\ + }\ + type *sglib_##type##_it_current(struct sglib_##type##_iterator *it) {\ + return(it->currentelem);\ + }\ + type *sglib_##type##_it_next(struct sglib_##type##_iterator *it) {\ + type *ce, *eq;\ + int (*scp)(type *, type *);\ + ce = it->nextelem;\ + it->nextelem = NULL;\ + if (it->subcomparator != NULL) {\ + eq = it->equalto; \ + scp = it->subcomparator;\ + while (ce!=NULL && scp(ce, eq)!=0) ce = ce->next;\ + }\ + it->currentelem = ce;\ + if (ce != NULL) it->nextelem = ce->next;\ + return(ce);\ + } + +/* ----------------------------- sorted list (level 1) ----------------------------------- */ + + +#define SGLIB_DEFINE_SORTED_LIST_PROTOTYPES(type, comparator, next) \ + struct sglib_##type##_iterator {\ + type *currentelem;\ + type *nextelem;\ + int (*subcomparator)(type *, type *);\ + type *equalto;\ + };\ + extern void sglib_##type##_add(type **list, type *elem);\ + extern int sglib_##type##_add_if_not_member(type **list, type *elem, type **member);\ + extern void sglib_##type##_delete(type **list, type *elem);\ + extern int sglib_##type##_delete_if_member(type **list, type *elem, type **member);\ + extern int sglib_##type##_is_member(type *list, type *elem);\ + extern type *sglib_##type##_find_member(type *list, type *elem);\ + extern int sglib_##type##_len(type *list);\ + extern void sglib_##type##_sort(type **list);\ + extern type *sglib_##type##_it_init(struct sglib_##type##_iterator *it, type *list); \ + extern type *sglib_##type##_it_init_on_equal(struct sglib_##type##_iterator *it, type *list, int (*subcomparator)(type *, type *), type *equalto); \ + extern type *sglib_##type##_it_current(struct sglib_##type##_iterator *it); \ + extern type *sglib_##type##_it_next(struct sglib_##type##_iterator *it); + + +#define SGLIB_DEFINE_SORTED_LIST_FUNCTIONS(type, comparator, next) \ + int sglib_##type##_is_member(type *list, type *elem) {\ + int result;\ + SGLIB_SORTED_LIST_IS_MEMBER(type, list, elem, comparator, next, result);\ + return(result);\ + }\ + type *sglib_##type##_find_member(type *list, type *elem) {\ + type *result;\ + SGLIB_SORTED_LIST_FIND_MEMBER(type, list, elem, comparator, next, result);\ + return(result);\ + }\ + int sglib_##type##_add_if_not_member(type **list, type *elem, type **member) {\ + SGLIB_SORTED_LIST_ADD_IF_NOT_MEMBER(type, *list, elem, comparator, next, *member);\ + return(*member==NULL);\ + }\ + void sglib_##type##_add(type **list, type *elem) {\ + SGLIB_SORTED_LIST_ADD(type, *list, elem, comparator, next);\ + }\ + void sglib_##type##_delete(type **list, type *elem) {\ + SGLIB_SORTED_LIST_DELETE(type, *list, elem, next);\ + }\ + int sglib_##type##_delete_if_member(type **list, type *elem, type **member) {\ + SGLIB_SORTED_LIST_DELETE_IF_MEMBER(type, *list, elem, comparator, next, *member);\ + return(*member!=NULL);\ + }\ + int sglib_##type##_len(type *list) {\ + int res;\ + SGLIB_SORTED_LIST_LEN(type, list, next, res);\ + return(res);\ + }\ + void sglib_##type##_sort(type **list) { \ + SGLIB_LIST_SORT(type, *list, comparator, next);\ + }\ + \ + type *sglib_##type##_it_init_on_equal(struct sglib_##type##_iterator *it, type *list, int (*subcomparator)(type *, type *), type *equalto) {\ + it->subcomparator = subcomparator;\ + it->equalto = equalto;\ + it->nextelem = list;\ + return(sglib_##type##_it_next(it));\ + }\ + type *sglib_##type##_it_init(struct sglib_##type##_iterator *it, type *list) {\ + return(sglib_##type##_it_init_on_equal(it, list, NULL, NULL));\ + }\ + type *sglib_##type##_it_current(struct sglib_##type##_iterator *it) {\ + return(it->currentelem);\ + }\ + type *sglib_##type##_it_next(struct sglib_##type##_iterator *it) {\ + type *ce, *eq;\ + int (*scp)(type *, type *);\ + int c;\ + ce = it->nextelem;\ + it->nextelem = NULL;\ + if (it->subcomparator != NULL) {\ + eq = it->equalto; \ + scp = it->subcomparator;\ + while (ce!=NULL && (c=scp(ce, eq)) < 0) ce = ce->next;\ + if (ce != NULL && c > 0) ce = NULL;\ + }\ + it->currentelem = ce;\ + if (ce != NULL) it->nextelem = ce->next;\ + return(ce);\ + } + + +/* ----------------------------- double linked list (level 1) ------------------------------ */ + + +#define SGLIB_DEFINE_DL_LIST_PROTOTYPES(type, comparator, previous, next) \ + struct sglib_##type##_iterator {\ + type *currentelem;\ + type *prevelem;\ + type *nextelem;\ + int (*subcomparator)(type *, type *);\ + type *equalto;\ + };\ + extern void sglib_##type##_add(type **list, type *elem);\ + extern void sglib_##type##_add_before(type **list, type *elem);\ + extern void sglib_##type##_add_after(type **list, type *elem);\ + extern int sglib_##type##_add_if_not_member(type **list, type *elem, type **member);\ + extern int sglib_##type##_add_before_if_not_member(type **list, type *elem, type **member);\ + extern int sglib_##type##_add_after_if_not_member(type **list, type *elem, type **member);\ + extern void sglib_##type##_concat(type **first, type *second);\ + extern void sglib_##type##_delete(type **list, type *elem);\ + extern int sglib_##type##_delete_if_member(type **list, type *elem, type **member);\ + extern int sglib_##type##_is_member(type *list, type *elem);\ + extern type *sglib_##type##_find_member(type *list, type *elem);\ + extern type *sglib_##type##_get_first(type *list);\ + extern type *sglib_##type##_get_last(type *list);\ + extern void sglib_##type##_sort(type **list);\ + extern int sglib_##type##_len(type *list);\ + extern void sglib_##type##_reverse(type **list);\ + extern type *sglib_##type##_it_init(struct sglib_##type##_iterator *it, type *list); \ + extern type *sglib_##type##_it_init_on_equal(struct sglib_##type##_iterator *it, type *list, int (*subcomparator)(type *, type *), type *equalto); \ + extern type *sglib_##type##_it_current(struct sglib_##type##_iterator *it); \ + extern type *sglib_##type##_it_next(struct sglib_##type##_iterator *it); + + +#define SGLIB_DEFINE_DL_LIST_FUNCTIONS(type, comparator, previous, next) \ + void sglib_##type##_add(type **list, type *elem) {\ + SGLIB_DL_LIST_ADD(type, *list, elem, previous, next);\ + }\ + void sglib_##type##_add_after(type **list, type *elem) {\ + SGLIB_DL_LIST_ADD_AFTER(type, *list, elem, previous, next);\ + }\ + void sglib_##type##_add_before(type **list, type *elem) {\ + SGLIB_DL_LIST_ADD_BEFORE(type, *list, elem, previous, next);\ + }\ + int sglib_##type##_add_if_not_member(type **list, type *elem, type **member) {\ + SGLIB_DL_LIST_ADD_IF_NOT_MEMBER(type, *list, elem, comparator, previous, next, *member);\ + return(*member==NULL);\ + }\ + int sglib_##type##_add_after_if_not_member(type **list, type *elem, type **member) {\ + SGLIB_DL_LIST_ADD_AFTER_IF_NOT_MEMBER(type, *list, elem, comparator, previous, next, *member);\ + return(*member==NULL);\ + }\ + int sglib_##type##_add_before_if_not_member(type **list, type *elem, type **member) {\ + SGLIB_DL_LIST_ADD_BEFORE_IF_NOT_MEMBER(type, *list, elem, comparator, previous, next, *member);\ + return(*member==NULL);\ + }\ + void sglib_##type##_concat(type **first, type *second) {\ + SGLIB_DL_LIST_CONCAT(type, *first, second, previous, next);\ + }\ + void sglib_##type##_delete(type **list, type *elem) {\ + SGLIB_DL_LIST_DELETE(type, *list, elem, previous, next);\ + }\ + int sglib_##type##_delete_if_member(type **list, type *elem, type **member) {\ + SGLIB_DL_LIST_DELETE_IF_MEMBER(type, *list, elem, comparator, previous, next, *member);\ + return(*member!=NULL);\ + }\ + int sglib_##type##_is_member(type *list, type *elem) {\ + int result;\ + SGLIB_DL_LIST_IS_MEMBER(type, list, elem, previous, next, result);\ + return(result);\ + }\ + type *sglib_##type##_find_member(type *list, type *elem) {\ + type *result;\ + SGLIB_DL_LIST_FIND_MEMBER(type, list, elem, comparator, previous, next, result);\ + return(result);\ + }\ + type *sglib_##type##_get_first(type *list) {\ + type *result;\ + SGLIB_DL_LIST_GET_FIRST(type, list, previous, next, result);\ + return(result);\ + }\ + type *sglib_##type##_get_last(type *list) {\ + type *result;\ + SGLIB_DL_LIST_GET_LAST(type, list, previous, next, result);\ + return(result);\ + }\ + void sglib_##type##_sort(type **list) {\ + SGLIB_DL_LIST_SORT(type, *list, comparator, previous, next);\ + }\ + int sglib_##type##_len(type *list) {\ + int res;\ + SGLIB_DL_LIST_LEN(type, list, previous, next, res);\ + return(res);\ + }\ + void sglib_##type##_reverse(type **list) {\ + SGLIB_DL_LIST_REVERSE(type, *list, previous, next);\ + }\ + \ + type *sglib_##type##_it_init_on_equal(struct sglib_##type##_iterator *it, type *list, int (*subcomparator)(type *, type *), type *equalto) {\ + it->subcomparator = subcomparator;\ + it->equalto = equalto;\ + it->prevelem = list;\ + it->nextelem = list;\ + if (list != NULL) it->nextelem = list->next;\ + return(sglib_##type##_it_next(it));\ + }\ + type *sglib_##type##_it_init(struct sglib_##type##_iterator *it, type *list) {\ + return(sglib_##type##_it_init_on_equal(it, list, NULL, NULL));\ + }\ + type *sglib_##type##_it_current(struct sglib_##type##_iterator *it) {\ + return(it->currentelem);\ + }\ + type *sglib_##type##_it_next(struct sglib_##type##_iterator *it) {\ + type *ce, *eq;\ + int (*scp)(type *, type *);\ + ce = it->prevelem;\ + it->prevelem = NULL;\ + if (it->subcomparator != NULL) {\ + eq = it->equalto; \ + scp = it->subcomparator;\ + while (ce!=NULL && scp(eq, ce)!=0) ce = ce->previous;\ + }\ + if (ce != NULL) {\ + it->prevelem = ce->previous;\ + } else {\ + ce = it->nextelem;\ + it->nextelem = NULL;\ + if (it->subcomparator != NULL) {\ + eq = it->equalto; \ + scp = it->subcomparator;\ + while (ce!=NULL && scp(ce, eq)!=0) ce = ce->next;\ + }\ + if (ce != NULL) it->nextelem = ce->next;\ + }\ + it->currentelem = ce;\ + return(ce);\ + } + + +/* --------------------------------- red-black trees (level 1) -------------------------------- */ + +/* + +This implementation requires pointers to left and right sons (no +parent pointer is needed) and one bit of additional information +storing the color of the node. The implementation follows discrepancy +fixing rules from: +http://www.cis.ohio-state.edu/~gurari/course/cis680/cis680Ch11.html + +*/ + +#define SGLIB___RBTREE_FIX_INSERTION_DISCREPANCY(type, tree, leftt, rightt, bits, RED, BLACK) {\ + type *t, *tl, *a, *b, *c, *ar, *bl, *br, *cl, *cr;\ + t = *tree;\ + tl = t->leftt;\ + if (t->rightt!=NULL && SGLIB___GET_VALUE(t->rightt->bits)==RED) {\ + if (SGLIB___GET_VALUE(tl->bits)==RED) {\ + if ((tl->leftt!=NULL && SGLIB___GET_VALUE(tl->leftt->bits)==RED) \ + || (tl->rightt!=NULL && SGLIB___GET_VALUE(tl->rightt->bits)==RED)) {\ + SGLIB___SET_VALUE(t->leftt->bits,BLACK);\ + SGLIB___SET_VALUE(t->rightt->bits,BLACK);\ + SGLIB___SET_VALUE(t->bits,RED);\ + }\ + }\ + } else {\ + if (SGLIB___GET_VALUE(tl->bits)==RED) {\ + if (tl->leftt!=NULL && SGLIB___GET_VALUE(tl->leftt->bits)==RED) {\ + a = t; b = tl; c = tl->leftt;\ + br = b->rightt;\ + a->leftt = br;\ + b->leftt = c; b->rightt = a;\ + SGLIB___SET_VALUE(a->bits,RED);\ + SGLIB___SET_VALUE(b->bits,BLACK);\ + *tree = b;\ + } else if (tl->rightt!=NULL && SGLIB___GET_VALUE(tl->rightt->bits)==RED) {\ + a = t; b = tl; ar=a->rightt;\ + bl=b->leftt; c=b->rightt;\ + cl=c->leftt; cr=c->rightt;\ + b->rightt = cl;\ + a->leftt = cr;\ + c->leftt = b;\ + c->rightt = a;\ + SGLIB___SET_VALUE(c->bits,BLACK);\ + SGLIB___SET_VALUE(a->bits,RED);\ + *tree = c;\ + }\ + }\ + }\ +} + +#define SGLIB___RBTREE_FIX_DELETION_DISCREPANCY(type, tree, leftt, rightt, bits, RED, BLACK, res) {\ + type *t, *a, *b, *c, *d, *ar, *bl, *br, *cl, *cr, *dl, *dr;\ + t = a = *tree;\ + assert(t!=NULL);\ + ar = a->rightt;\ + b = t->leftt;\ + if (b==NULL) {\ + assert(SGLIB___GET_VALUE(t->bits)==RED);\ + SGLIB___SET_VALUE(t->bits,BLACK);\ + res = 0;\ + } else {\ + bl = b->leftt;\ + br = b->rightt;\ + if (SGLIB___GET_VALUE(b->bits)==RED) {\ + if (br==NULL) {\ + *tree = b;\ + SGLIB___SET_VALUE(b->bits,BLACK);\ + b->rightt = a;\ + a->leftt = br;\ + res = 0;\ + } else {\ + c = br;\ + assert(c!=NULL && SGLIB___GET_VALUE(c->bits)==BLACK);\ + cl = c->leftt;\ + cr = c->rightt;\ + if ((cl==NULL||SGLIB___GET_VALUE(cl->bits)==BLACK) && (cr==NULL||SGLIB___GET_VALUE(cr->bits)==BLACK)) {\ + *tree = b;\ + b->rightt = a;\ + SGLIB___SET_VALUE(b->bits,BLACK);\ + a->leftt = c;\ + SGLIB___SET_VALUE(c->bits,RED);\ + res = 0;\ + } else if (cl!=NULL && SGLIB___GET_VALUE(cl->bits)==RED) {\ + if (cr!=NULL && SGLIB___GET_VALUE(cr->bits)==RED) {\ + d = cr;\ + dl = d->leftt;\ + dr = d->rightt;\ + *tree = d;\ + SGLIB___SET_VALUE(d->bits,BLACK);\ + d->leftt = b;\ + c->rightt = dl;\ + d->rightt = a;\ + a->leftt = dr;\ + res = 0;\ + } else {\ + *tree = c;\ + c->leftt = b;\ + c->rightt = a;\ + b->leftt = bl;\ + b->rightt = cl;\ + a->leftt = cr;\ + SGLIB___SET_VALUE(cl->bits,BLACK);\ + res = 0;\ + }\ + } else if (cr!=NULL && SGLIB___GET_VALUE(cr->bits)==RED) {\ + assert(cl==NULL || SGLIB___GET_VALUE(cl->bits)==BLACK);\ + d = cr;\ + dl = d->leftt;\ + dr = d->rightt;\ + *tree = d;\ + SGLIB___SET_VALUE(d->bits,BLACK);\ + d->leftt = b;\ + c->rightt = dl;\ + d->rightt = a;\ + a->leftt = dr;\ + res = 0;\ + } else {\ + assert(0);\ + res = 0;\ + }\ + }\ + } else {\ + if ((bl==NULL || SGLIB___GET_VALUE(bl->bits)==BLACK) && (br==NULL || SGLIB___GET_VALUE(br->bits)==BLACK)) {\ + res = (SGLIB___GET_VALUE(a->bits)==BLACK);\ + SGLIB___SET_VALUE(a->bits,BLACK);\ + SGLIB___SET_VALUE(b->bits,RED);\ + } else if (bl!=NULL && SGLIB___GET_VALUE(bl->bits)==RED) {\ + if (br==NULL || SGLIB___GET_VALUE(br->bits)==BLACK) {\ + *tree = b;\ + SGLIB___SET_VALUE(b->bits,SGLIB___GET_VALUE(a->bits));\ + SGLIB___SET_VALUE(a->bits,BLACK);\ + b->rightt = a;\ + a->leftt = br;\ + SGLIB___SET_VALUE(bl->bits,BLACK);\ + res = 0;\ + } else {\ + assert(bl!=NULL);\ + assert(br!=NULL);\ + assert(SGLIB___GET_VALUE(bl->bits)==RED);\ + assert(SGLIB___GET_VALUE(br->bits)==RED);\ + c = br;\ + cl = c->leftt;\ + cr = c->rightt;\ + *tree = c;\ + SGLIB___SET_VALUE(c->bits,SGLIB___GET_VALUE(a->bits));\ + SGLIB___SET_VALUE(a->bits,BLACK);\ + c->leftt = b;\ + c->rightt = a;\ + b->rightt = cl;\ + a->leftt = cr;\ + res = 0;\ + }\ + } else {\ + assert(br!=NULL && SGLIB___GET_VALUE(br->bits)==RED);\ + c = br;\ + cl = c->leftt;\ + cr = c->rightt;\ + *tree = c;\ + SGLIB___SET_VALUE(c->bits,SGLIB___GET_VALUE(a->bits));\ + SGLIB___SET_VALUE(a->bits,BLACK);\ + c->leftt = b;\ + c->rightt = a;\ + b->rightt = cl;\ + a->leftt = cr;\ + res = 0;\ + }\ + }\ + }\ +} + + +#define SGLIB_DEFINE_RBTREE_FUNCTIONS_GENERAL(type, left, right, bits, comparator, RED, BLACK) \ +static void sglib___##type##_fix_left_insertion_discrepancy(type **tree) {\ + SGLIB___RBTREE_FIX_INSERTION_DISCREPANCY(type, tree, left, right, bits, RED, BLACK);\ +}\ +\ +static void sglib___##type##_fix_right_insertion_discrepancy(type **tree) {\ + SGLIB___RBTREE_FIX_INSERTION_DISCREPANCY(type, tree, right, left, bits, RED, BLACK);\ +}\ +\ +static int sglib___##type##_fix_left_deletion_discrepancy(type **tree) {\ + int res;\ + SGLIB___RBTREE_FIX_DELETION_DISCREPANCY(type, tree, right, left, bits, RED, BLACK, res);\ + return(res);\ +}\ +\ +static int sglib___##type##_fix_right_deletion_discrepancy(type **tree) {\ + int res;\ + SGLIB___RBTREE_FIX_DELETION_DISCREPANCY(type, tree, left, right, bits, RED, BLACK, res);\ + return(res);\ +}\ +\ +static void sglib___##type##_add_recursive(type **tree, type *elem) {\ + int cmp;\ + type *t;\ + t = *tree;\ + if (t == NULL) {\ + SGLIB___SET_VALUE(elem->bits,RED);\ + *tree =elem;\ + } else {\ + cmp = comparator(elem, t);\ + if (cmp < 0 || (cmp==0 && elemleft, elem);\ + if (SGLIB___GET_VALUE(t->bits)==BLACK) sglib___##type##_fix_left_insertion_discrepancy(tree);\ + } else {\ + sglib___##type##_add_recursive(&t->right, elem);\ + if (SGLIB___GET_VALUE(t->bits)==BLACK) sglib___##type##_fix_right_insertion_discrepancy(tree);\ + }\ + }\ +}\ +\ +static int sglib___##type##_delete_rightmost_leaf(type **tree, type **theLeaf) {\ + type *t;\ + int res, deepDecreased;\ + t = *tree;\ + res = 0;\ + assert(t!=NULL);\ + if (t->right == NULL) {\ + *theLeaf = t;\ + if (t->left!=NULL) {\ + if (SGLIB___GET_VALUE(t->bits)==BLACK && SGLIB___GET_VALUE(t->left->bits)==BLACK) res = 1;\ + SGLIB___SET_VALUE(t->left->bits,BLACK);\ + *tree = t->left;\ + } else {\ + *tree = NULL;\ + res = (SGLIB___GET_VALUE(t->bits)==BLACK);\ + }\ + } else {\ + deepDecreased = sglib___##type##_delete_rightmost_leaf(&t->right, theLeaf);\ + if (deepDecreased) res = sglib___##type##_fix_right_deletion_discrepancy(tree);\ + }\ + return(res);\ +}\ +\ +int sglib___##type##_delete_recursive(type **tree, type *elem) {\ + type *t, *theLeaf;\ + int cmp, res, deepDecreased;\ + t = *tree;\ + res = 0;\ + if (t==NULL) {\ + assert(0 && "The element to delete not found in the tree, use 'delete_if_member'"!=NULL);\ + } else {\ + cmp = comparator(elem, t);\ + if (cmp < 0 || (cmp==0 && elemleft, elem);\ + if (deepDecreased) {\ + res = sglib___##type##_fix_left_deletion_discrepancy(tree);\ + }\ + } else if (cmp > 0 || (cmp==0 && elem>t)) {\ + deepDecreased = sglib___##type##_delete_recursive(&t->right, elem);\ + if (deepDecreased) {\ + res = sglib___##type##_fix_right_deletion_discrepancy(tree);\ + }\ + } else {\ + assert(elem==t && "Deleting an element which is non member of the tree, use 'delete_if_member'"!=NULL);\ + if (t->left == NULL) {\ + if (t->right == NULL) {\ + /* a leaf, delete, it; */\ + *tree = NULL;\ + res = (SGLIB___GET_VALUE(t->bits)==BLACK);\ + } else {\ + if (SGLIB___GET_VALUE(t->bits)==0 && SGLIB___GET_VALUE(t->right->bits)==0) res = 1;\ + SGLIB___SET_VALUE(t->right->bits,BLACK);\ + *tree = t->right;\ + }\ + } else {\ + /* propagate deletion until righmost leaf of left subtree */\ + deepDecreased = sglib___##type##_delete_rightmost_leaf(&t->left, &theLeaf);\ + theLeaf->left = t->left;\ + theLeaf->right = t->right;\ + SGLIB___SET_VALUE(theLeaf->bits,SGLIB___GET_VALUE(t->bits));\ + *tree = theLeaf;\ + if (deepDecreased) res = sglib___##type##_fix_left_deletion_discrepancy(tree);\ + }\ + }\ + }\ + return(res);\ +}\ +\ +void sglib_##type##_add(type **tree, type *elem) {\ + elem->left = elem->right = NULL;\ + sglib___##type##_add_recursive(tree, elem);\ + SGLIB___SET_VALUE((*tree)->bits,BLACK);\ +}\ +\ +void sglib_##type##_delete(type **tree, type *elem) {\ + sglib___##type##_delete_recursive(tree, elem);\ + if (*tree!=NULL) SGLIB___SET_VALUE((*tree)->bits,BLACK);\ +}\ +\ +type *sglib_##type##_find_member(type *t, type *elem) {\ + type *res;\ + SGLIB___BIN_TREE_FIND_MEMBER(type, t, elem, left, right, comparator, res);\ + return(res);\ +}\ +\ +int sglib_##type##_is_member(type *t, type *elem) {\ + int cmp;\ + while (t!=NULL) {\ + cmp = comparator(elem, t);\ + if (cmp < 0 || (cmp==0 && elemleft;\ + } else if (cmp > 0 || (cmp==0 && elem>t)) {\ + t = t->right;\ + } else {\ + assert(t == elem);\ + return(1);\ + }\ + }\ + return(0);\ +}\ +\ +int sglib_##type##_delete_if_member(type **tree, type *elem, type **memb) {\ + if ((*memb=sglib_##type##_find_member(*tree, elem))!=NULL) {\ + sglib_##type##_delete(tree, *memb);\ + return(1);\ + } else {\ + return(0);\ + }\ +}\ +int sglib_##type##_add_if_not_member(type **tree, type *elem, type **memb) {\ + if ((*memb=sglib_##type##_find_member(*tree, elem))==NULL) {\ + sglib_##type##_add(tree, elem);\ + return(1);\ + } else {\ + return(0);\ + }\ +}\ +int sglib_##type##_len(type *t) {\ + int n;\ + type *e;\ + n = 0;\ + SGLIB_BIN_TREE_MAP_ON_ELEMENTS(type, t, e, left, right, n++);\ + return(n);\ +}\ +\ +void sglib__##type##_it_compute_current_elem(struct sglib_##type##_iterator *it) {\ + int i,j,cmp;\ + type *s, *eqt;\ + int (*subcomparator)(type *, type *);\ + eqt = it->equalto;\ + subcomparator = it->subcomparator;\ + it->currentelem = NULL;\ + while(it->pathi > 0 && it->currentelem==NULL) {\ + i = it->pathi-1;\ + if (i >= 0) {\ + if (it->pass[i] >= 2) {\ + /* goto up */\ + it->pathi --;\ + } else {\ + if (it->pass[i] == 0) {\ + /* goto left */\ + s = it->path[i]->left;\ + } else {\ + /* goto right */\ + s = it->path[i]->right;\ + }\ + if (eqt != NULL) {\ + if (subcomparator == NULL) {\ + SGLIB___BIN_TREE_FIND_MEMBER(type, s, eqt, left, right, comparator, s);\ + } else {\ + SGLIB___BIN_TREE_FIND_MEMBER(type, s, eqt, left, right, subcomparator, s);\ + }\ + }\ + if (s != NULL) {\ + j = i+1;\ + it->path[j] = s;\ + it->pass[j] = 0;\ + it->pathi ++;\ + }\ + it->pass[i] ++;\ + }\ + }\ + if (it->pathi>0 && it->order == it->pass[it->pathi-1]) {\ + it->currentelem = it->path[it->pathi-1];\ + }\ + }\ +}\ +type *sglib__##type##_it_init(struct sglib_##type##_iterator *it, type *tree, int order, int (*subcomparator)(type *, type *), type *equalto) {\ + type *t;\ + assert(it!=NULL);\ + it->order = order;\ + it->equalto = equalto;\ + it->subcomparator = subcomparator;\ + if (equalto == NULL) { \ + t = tree;\ + } else {\ + if (subcomparator == NULL) {\ + SGLIB___BIN_TREE_FIND_MEMBER(type, tree, equalto, left, right, comparator, t);\ + } else {\ + SGLIB___BIN_TREE_FIND_MEMBER(type, tree, equalto, left, right, subcomparator, t);\ + }\ + }\ + if (t == NULL) {\ + it->pathi = 0;\ + it->currentelem = NULL;\ + } else {\ + it->pathi = 1;\ + it->pass[0] = 0;\ + it->path[0] = t;\ + if (order == 0) {\ + it->currentelem = t;\ + } else {\ + sglib__##type##_it_compute_current_elem(it);\ + }\ + }\ + return(it->currentelem);\ +}\ +type *sglib_##type##_it_init(struct sglib_##type##_iterator *it, type *tree) {\ + return(sglib__##type##_it_init(it, tree, 2, NULL, NULL));\ +}\ +type *sglib_##type##_it_init_preorder(struct sglib_##type##_iterator *it, type *tree) {\ + return(sglib__##type##_it_init(it, tree, 0, NULL, NULL));\ +}\ +type *sglib_##type##_it_init_inorder(struct sglib_##type##_iterator *it, type *tree) {\ + return(sglib__##type##_it_init(it, tree, 1, NULL, NULL));\ +}\ +type *sglib_##type##_it_init_postorder(struct sglib_##type##_iterator *it, type *tree) {\ + return(sglib__##type##_it_init(it, tree, 2, NULL, NULL));\ +}\ +type *sglib_##type##_it_init_on_equal(struct sglib_##type##_iterator *it, type *tree, int (*subcomparator)(type *, type *), type *equalto) {\ + return(sglib__##type##_it_init(it, tree, 1, subcomparator, equalto));\ +}\ +type *sglib_##type##_it_current(struct sglib_##type##_iterator *it) {\ + return(it->currentelem);\ +}\ +type *sglib_##type##_it_next(struct sglib_##type##_iterator *it) {\ + sglib__##type##_it_compute_current_elem(it);\ + return(it->currentelem);\ +}\ +\ +static void sglib___##type##_consistency_check_recursive(type *t, int *pathdeep, int cdeep) {\ + if (t==NULL) {\ + if (*pathdeep < 0) *pathdeep = cdeep;\ + else {assert(*pathdeep == cdeep);}\ + } else {\ + if (t->left!=NULL) {assert(comparator(t->left, t) <= 0);}\ + if (t->right!=NULL) {assert(comparator(t, t->right) <= 0);}\ + if (SGLIB___GET_VALUE(t->bits) == RED) {\ + assert(t->left == NULL || SGLIB___GET_VALUE(t->left->bits)==BLACK);\ + assert(t->right == NULL || SGLIB___GET_VALUE(t->right->bits)==BLACK);\ + sglib___##type##_consistency_check_recursive(t->left, pathdeep, cdeep);\ + sglib___##type##_consistency_check_recursive(t->right, pathdeep, cdeep);\ + } else {\ + sglib___##type##_consistency_check_recursive(t->left, pathdeep, cdeep+1);\ + sglib___##type##_consistency_check_recursive(t->right, pathdeep, cdeep+1);\ + }\ + }\ +}\ +\ +void sglib___##type##_consistency_check(type *t) {\ + int pathDeep;\ + assert(t==NULL || SGLIB___GET_VALUE(t->bits) == BLACK);\ + pathDeep = -1;\ + sglib___##type##_consistency_check_recursive(t, &pathDeep, 0);\ +} + + +#define SGLIB_DEFINE_RBTREE_PROTOTYPES(type, left, right, colorbit, comparator) \ + struct sglib_##type##_iterator {\ + type *currentelem;\ + char pass[SGLIB_MAX_TREE_DEEP];\ + type *path[SGLIB_MAX_TREE_DEEP];\ + short int pathi;\ + short int order;\ + type *equalto;\ + int (*subcomparator)(type *, type *);\ + };\ + extern void sglib___##type##_consistency_check(type *t); \ + extern void sglib_##type##_add(type **tree, type *elem); \ + extern int sglib_##type##_add_if_not_member(type **tree, type *elem, type **memb); \ + extern void sglib_##type##_delete(type **tree, type *elem); \ + extern int sglib_##type##_delete_if_member(type **tree, type *elem, type **memb); \ + extern int sglib_##type##_is_member(type *t, type *elem); \ + extern type *sglib_##type##_find_member(type *t, type *elem); \ + extern int sglib_##type##_len(type *t); \ + extern type *sglib_##type##_it_init(struct sglib_##type##_iterator *it, type *tree); \ + extern type *sglib_##type##_it_init_preorder(struct sglib_##type##_iterator *it, type *tree); \ + extern type *sglib_##type##_it_init_inorder(struct sglib_##type##_iterator *it, type *tree); \ + extern type *sglib_##type##_it_init_postorder(struct sglib_##type##_iterator *it, type *tree); \ + extern type *sglib_##type##_it_init_on_equal(struct sglib_##type##_iterator *it, type *tree, int (*subcomparator)(type *, type *), type *equalto); \ + extern type *sglib_##type##_it_current(struct sglib_##type##_iterator *it); \ + extern type *sglib_##type##_it_next(struct sglib_##type##_iterator *it); \ + + +#define SGLIB_DEFINE_RBTREE_FUNCTIONS(type, left, right, colorbit, comparator) \ + SGLIB_DEFINE_RBTREE_FUNCTIONS_GENERAL(type, left, right, colorbit, comparator, 1, 0) + + + +/* ---------------------------------------------------------------------------- */ +/* ---------------------------------------------------------------------------- */ +/* - SUPPLEMENTARY DEFINITIONS - */ +/* ---------------------------------------------------------------------------- */ +/* ---------------------------------------------------------------------------- */ + + +#define SGLIB___GET_VALUE(x) (x) +#define SGLIB___SET_VALUE(x, value) {(x) = (value);} +#define SGLIB_ARRAY_ELEMENTS_EXCHANGER(type, a, i, j) {type _sgl_aee_tmp_; _sgl_aee_tmp_=(a)[(i)]; (a)[(i)]=(a)[(j)]; (a)[(j)]= _sgl_aee_tmp_;} + + +#define SGLIB_SAFE_NUMERIC_COMPARATOR(x, y) (((x)>(y)?1:((x)<(y)?-1:0))) +#define SGLIB_SAFE_REVERSE_NUMERIC_COMPARATOR(x, y) (((x)>(y)?-1:((x)<(y)?1:0))) +#define SGLIB_FAST_NUMERIC_COMPARATOR(x, y) ((int)((x) - (y))) +#define SGLIB_FAST_REVERSE_NUMERIC_COMPARATOR(x, y) ((int)((y) - (x))) +#define SGLIB_NUMERIC_COMPARATOR(x, y) SGLIB_SAFE_NUMERIC_COMPARATOR(x, y) +#define SGLIB_REVERSE_NUMERIC_COMPARATOR(x, y) SGLIB_SAFE_REVERSE_NUMERIC_COMPARATOR(x, y) + +#ifndef SGLIB_MAX_TREE_DEEP +#define SGLIB_MAX_TREE_DEEP 128 +#endif + +#ifndef SGLIB_HASH_TAB_SHIFT_CONSTANT +#define SGLIB_HASH_TAB_SHIFT_CONSTANT 16381 /* should be a prime */ + /* #define SGLIB_HASH_TAB_SHIFT_CONSTANT 536870912*//* for large tables :) */ +#endif + +#endif /* _SGLIB__h_ */ + + +/* + Local Variables: + mode: C + c-file-style: "gnu" + End: +*/ diff --git a/benchies/embench/benchemarks/slre/libslre.c b/benchies/embench/benchemarks/slre/libslre.c new file mode 100644 index 0000000000..3aa4e4a41e --- /dev/null +++ b/benchies/embench/benchemarks/slre/libslre.c @@ -0,0 +1,625 @@ +/* BEEBS slre benchmark + + Copyright (c) 2004-2013 Sergey Lyubka + Copyright (c) 2013 Cesanta Software Limited All rights reserved + + This version, copyright (C) 2014-2019 Embecosm Limited and University of + Bristol + + Contributor James Pallister + Contributor Jeremy Bennett + + This file is part of Embench and was formerly part of the Bristol/Embecosm + Embedded Benchmark Suite. + + SPDX-License-Identifier: GPL-3.0-or-later */ + +#include "../../src/support.h" + +/* This scale factor will be changed to equalise the runtime of the + benchmarks. */ +#define LOCAL_SCALE_FACTOR 110 + +#include +#include +#include + +#include "slre.h" + +#define MAX_BRANCHES 100 +#define MAX_BRACKETS 100 +#define ARRAY_SIZE(ar) (int) (sizeof(ar) / sizeof((ar)[0])) +#define FAIL_IF(condition, error_code) if (condition) return (error_code) + +#ifdef SLRE_DEBUG +#define DBG(x) printf x +#else +#define DBG(x) +#endif + +struct bracket_pair +{ + const char *ptr; /* Points to the first char after '(' in regex */ + int len; /* Length of the text between '(' and ')' */ + int branches; /* Index in the branches array for this pair */ + int num_branches; /* Number of '|' in this bracket pair */ +}; + +struct branch +{ + int bracket_index; /* index for 'struct bracket_pair brackets' */ + /* array defined below */ + const char *schlong; /* points to the '|' character in the regex */ +}; + +struct regex_info +{ + /* + * Describes all bracket pairs in the regular expression. + * First entry is always present, and grabs the whole regex. + */ + struct bracket_pair brackets[MAX_BRACKETS]; + int num_brackets; + + /* + * Describes alternations ('|' operators) in the regular expression. + * Each branch falls into a specific branch pair. + */ + struct branch branches[MAX_BRANCHES]; + int num_branches; + + /* Array of captures provided by the user */ + struct slre_cap *caps; + int num_caps; + + /* E.g. IGNORE_CASE. See enum below */ + int flags; +}; +enum +{ IGNORE_CASE = 1 }; + +static int +is_metacharacter (const unsigned char *s) +{ + static const char *metacharacters = "^$().[]*+?|\\Ssd"; + return strchr (metacharacters, *s) != NULL; +} + +static int +op_len (const char *re) +{ + return re[0] == '\\' && re[1] == 'x' ? 4 : re[0] == '\\' ? 2 : 1; +} + +static int +set_len (const char *re, int re_len) +{ + int len = 0; + + while (len < re_len && re[len] != ']') + { + len += op_len (re + len); + } + + return len <= re_len ? len + 1 : -1; +} + +static int +get_op_len (const char *re, int re_len) +{ + return re[0] == '[' ? set_len (re + 1, re_len - 1) + 1 : op_len (re); +} + +static int +is_quantifier (const char *re) +{ + return re[0] == '*' || re[0] == '+' || re[0] == '?'; +} + +static int +toi (int x) +{ + return isdigit (x) ? x - '0' : x - 'W'; +} + +static int +hextoi (const unsigned char *s) +{ + return (toi (tolower (s[0])) << 4) | toi (tolower (s[1])); +} + +static int +match_op (const unsigned char *re, const unsigned char *s, + struct regex_info *info) +{ + int result = 0; + switch (*re) + { + case '\\': + /* Metacharacters */ + switch (re[1]) + { + case 'S': + FAIL_IF (isspace (*s), SLRE_NO_MATCH); + result++; + break; + + case 's': + FAIL_IF (!isspace (*s), SLRE_NO_MATCH); + result++; + break; + + case 'd': + FAIL_IF (!isdigit (*s), SLRE_NO_MATCH); + result++; + break; + + case 'x': + /* Match byte, \xHH where HH is hexadecimal byte representaion */ + FAIL_IF (hextoi (re + 2) != *s, SLRE_NO_MATCH); + result++; + break; + + default: + /* Valid metacharacter check is done in bar() */ + FAIL_IF (re[1] != s[0], SLRE_NO_MATCH); + result++; + break; + } + break; + + case '|': + FAIL_IF (1, SLRE_INTERNAL_ERROR); + break; + case '$': + FAIL_IF (1, SLRE_NO_MATCH); + break; + case '.': + result++; + break; + + default: + if (info->flags & IGNORE_CASE) + { + FAIL_IF (tolower (*re) != tolower (*s), SLRE_NO_MATCH); + } + else + { + FAIL_IF (*re != *s, SLRE_NO_MATCH); + } + result++; + break; + } + + return result; +} + +static int +match_set (const char *re, int re_len, const char *s, struct regex_info *info) +{ + int len = 0, result = -1, invert = re[0] == '^'; + + if (invert) + re++, re_len--; + + while (len <= re_len && re[len] != ']' && result <= 0) + { + /* Support character range */ + if (re[len] != '-' && re[len + 1] == '-' && re[len + 2] != ']' && + re[len + 2] != '\0') + { + result = info->flags && IGNORE_CASE ? + *s >= re[len] && *s <= re[len + 2] : + tolower ((int) *s) >= tolower ((int) re[len]) + && tolower ((int) *s) <= tolower ((int) re[len + 2]); + len += 3; + } + else + { + result = + match_op ((unsigned char *) re + len, (unsigned char *) s, info); + len += op_len (re + len); + } + } + return (!invert && result > 0) || (invert && result <= 0) ? 1 : -1; +} + +static int doh (const char *s, int s_len, struct regex_info *info, int bi); + +static int +bar (const char *re, int re_len, const char *s, int s_len, + struct regex_info *info, int bi) +{ + /* i is offset in re, j is offset in s, bi is brackets index */ + int i, j, n, step; + + for (i = j = 0; i < re_len && j <= s_len; i += step) + { + + /* Handle quantifiers. Get the length of the chunk. */ + step = re[i] == '(' ? info->brackets[bi + 1].len + 2 : + get_op_len (re + i, re_len - i); + + DBG (("%s [%.*s] [%.*s] re_len=%d step=%d i=%d j=%d\n", __func__, + re_len - i, re + i, s_len - j, s + j, re_len, step, i, j)); + + FAIL_IF (is_quantifier (&re[i]), SLRE_UNEXPECTED_QUANTIFIER); + FAIL_IF (step <= 0, SLRE_INVALID_CHARACTER_SET); + + if (i + step < re_len && is_quantifier (re + i + step)) + { + DBG (("QUANTIFIER: [%.*s]%c [%.*s]\n", step, re + i, + re[i + step], s_len - j, s + j)); + if (re[i + step] == '?') + { + int result = bar (re + i, step, s + j, s_len - j, info, bi); + j += result > 0 ? result : 0; + i++; + } + else if (re[i + step] == '+' || re[i + step] == '*') + { + int j2 = j, nj = j, n1, n2 = -1, ni, non_greedy = 0; + + /* Points to the regexp code after the quantifier */ + ni = i + step + 1; + if (ni < re_len && re[ni] == '?') + { + non_greedy = 1; + ni++; + } + + do + { + if ((n1 = + bar (re + i, step, s + j2, s_len - j2, info, bi)) > 0) + { + j2 += n1; + } + if (re[i + step] == '+' && n1 < 0) + break; + + if (ni >= re_len) + { + /* After quantifier, there is nothing */ + nj = j2; + } + else if ((n2 = bar (re + ni, re_len - ni, s + j2, + s_len - j2, info, bi)) >= 0) + { + /* Regex after quantifier matched */ + nj = j2 + n2; + } + if (nj > j && non_greedy) + break; + } + while (n1 > 0); + + if (n1 < 0 && re[i + step] == '*' && + (n2 = + bar (re + ni, re_len - ni, s + j, s_len - j, info, + bi)) > 0) + { + nj = j + n2; + } + + DBG (("STAR/PLUS END: %d %d %d %d %d\n", j, nj, re_len - ni, n1, + n2)); + FAIL_IF (re[i + step] == '+' && nj == j, SLRE_NO_MATCH); + + /* If while loop body above was not executed for the * quantifier, */ + /* make sure the rest of the regex matches */ + FAIL_IF (nj == j && ni < re_len && n2 < 0, SLRE_NO_MATCH); + + /* Returning here cause we've matched the rest of RE already */ + return nj; + } + continue; + } + + if (re[i] == '[') + { + n = match_set (re + i + 1, re_len - (i + 2), s + j, info); + DBG (("SET %.*s [%.*s] -> %d\n", step, re + i, s_len - j, s + j, + n)); + FAIL_IF (n <= 0, SLRE_NO_MATCH); + j += n; + } + else if (re[i] == '(') + { + n = SLRE_NO_MATCH; + bi++; + FAIL_IF (bi >= info->num_brackets, SLRE_INTERNAL_ERROR); + DBG (("CAPTURING [%.*s] [%.*s] [%s]\n", + step, re + i, s_len - j, s + j, re + i + step)); + + if (re_len - (i + step) <= 0) + { + /* Nothing follows brackets */ + n = doh (s + j, s_len - j, info, bi); + } + else + { + int j2; + for (j2 = 0; j2 <= s_len - j; j2++) + { + if ((n = doh (s + j, s_len - (j + j2), info, bi)) >= 0 && + bar (re + i + step, re_len - (i + step), + s + j + n, s_len - (j + n), info, bi) >= 0) + break; + } + } + + DBG (("CAPTURED [%.*s] [%.*s]:%d\n", step, re + i, s_len - j, s + j, + n)); + FAIL_IF (n < 0, n); + if (info->caps != NULL) + { + info->caps[bi - 1].ptr = s + j; + info->caps[bi - 1].len = n; + } + j += n; + } + else if (re[i] == '^') + { + FAIL_IF (j != 0, SLRE_NO_MATCH); + } + else if (re[i] == '$') + { + FAIL_IF (j != s_len, SLRE_NO_MATCH); + } + else + { + FAIL_IF (j >= s_len, SLRE_NO_MATCH); + n = + match_op ((unsigned char *) (re + i), (unsigned char *) (s + j), + info); + FAIL_IF (n <= 0, n); + j += n; + } + } + + return j; +} + +/* Process branch points */ +static int +doh (const char *s, int s_len, struct regex_info *info, int bi) +{ + const struct bracket_pair *b = &info->brackets[bi]; + int i = 0, len, result; + const char *p; + + do + { + p = i == 0 ? b->ptr : info->branches[b->branches + i - 1].schlong + 1; + len = b->num_branches == 0 ? b->len : + i == b->num_branches ? b->ptr + b->len - p : + info->branches[b->branches + i].schlong - p; + DBG (("%s %d %d [%.*s] [%.*s]\n", __func__, bi, i, len, p, s_len, s)); + result = bar (p, len, s, s_len, info, bi); + DBG (("%s <- %d\n", __func__, result)); + } + while (result <= 0 && i++ < b->num_branches); /* At least 1 iteration */ + + return result; +} + +static int +baz (const char *s, int s_len, struct regex_info *info) +{ + int i, result = -1, is_anchored = info->brackets[0].ptr[0] == '^'; + + for (i = 0; i <= s_len; i++) + { + result = doh (s + i, s_len - i, info, 0); + if (result >= 0) + { + result += i; + break; + } + if (is_anchored) + break; + } + + return result; +} + +static void +setup_branch_points (struct regex_info *info) +{ + int i, j; + struct branch tmp; + + /* First, sort branches. Must be stable, no qsort. Use bubble algo. */ + for (i = 0; i < info->num_branches; i++) + { + for (j = i + 1; j < info->num_branches; j++) + { + if (info->branches[i].bracket_index > + info->branches[j].bracket_index) + { + tmp = info->branches[i]; + info->branches[i] = info->branches[j]; + info->branches[j] = tmp; + } + } + } + + /* + * For each bracket, set their branch points. This way, for every bracket + * (i.e. every chunk of regex) we know all branch points before matching. + */ + for (i = j = 0; i < info->num_brackets; i++) + { + info->brackets[i].num_branches = 0; + info->brackets[i].branches = j; + while (j < info->num_branches && info->branches[j].bracket_index == i) + { + info->brackets[i].num_branches++; + j++; + } + } +} + +static int +foo (const char *re, int re_len, const char *s, int s_len, + struct regex_info *info) +{ + int i, step, depth = 0; + + /* First bracket captures everything */ + info->brackets[0].ptr = re; + info->brackets[0].len = re_len; + info->num_brackets = 1; + + /* Make a single pass over regex string, memorize brackets and branches */ + for (i = 0; i < re_len; i += step) + { + step = get_op_len (re + i, re_len - i); + + if (re[i] == '|') + { + FAIL_IF (info->num_branches >= ARRAY_SIZE (info->branches), + SLRE_TOO_MANY_BRANCHES); + info->branches[info->num_branches].bracket_index = + info->brackets[info->num_brackets - 1].len == -1 ? + info->num_brackets - 1 : depth; + info->branches[info->num_branches].schlong = &re[i]; + info->num_branches++; + } + else if (re[i] == '\\') + { + FAIL_IF (i >= re_len - 1, SLRE_INVALID_METACHARACTER); + if (re[i + 1] == 'x') + { + /* Hex digit specification must follow */ + FAIL_IF (re[i + 1] == 'x' && i >= re_len - 3, + SLRE_INVALID_METACHARACTER); + FAIL_IF (re[i + 1] == 'x' + && !(isxdigit ((unsigned char) re[i + 2]) + && isxdigit ((unsigned char) re[i + 3])), + SLRE_INVALID_METACHARACTER); + } + else + { + FAIL_IF (!is_metacharacter ((unsigned char *) re + i + 1), + SLRE_INVALID_METACHARACTER); + } + } + else if (re[i] == '(') + { + FAIL_IF (info->num_brackets >= ARRAY_SIZE (info->brackets), + SLRE_TOO_MANY_BRACKETS); + depth++; /* Order is important here. Depth increments first. */ + info->brackets[info->num_brackets].ptr = re + i + 1; + info->brackets[info->num_brackets].len = -1; + info->num_brackets++; + FAIL_IF (info->num_caps > 0 + && info->num_brackets - 1 > info->num_caps, + SLRE_CAPS_ARRAY_TOO_SMALL); + } + else if (re[i] == ')') + { + int ind = info->brackets[info->num_brackets - 1].len == -1 ? + info->num_brackets - 1 : depth; + info->brackets[ind].len = &re[i] - info->brackets[ind].ptr; + DBG (("SETTING BRACKET %d [%.*s]\n", + ind, info->brackets[ind].len, info->brackets[ind].ptr)); + depth--; + FAIL_IF (depth < 0, SLRE_UNBALANCED_BRACKETS); + FAIL_IF (i > 0 && re[i - 1] == '(', SLRE_NO_MATCH); + } + } + + FAIL_IF (depth != 0, SLRE_UNBALANCED_BRACKETS); + setup_branch_points (info); + + return baz (s, s_len, info); +} + +int +slre_match (const char *regexp, const char *s, int s_len, + struct slre_cap *caps, int num_caps) +{ + struct regex_info info; + + /* Initialize info structure */ + info.flags = info.num_brackets = info.num_branches = 0; + info.num_caps = num_caps; + info.caps = caps; + + DBG (("========================> [%s] [%.*s]\n", regexp, s_len, s)); + + /* Handle regexp flags. At the moment, only 'i' is supported */ + if (memcmp (regexp, "(?i)", 4) == 0) + { + info.flags |= IGNORE_CASE; + regexp += 4; + } + + return foo (regexp, strlen (regexp), s, s_len, &info); +} + +char text[] = "abbbababaabccababcacbcbcbabbabcbabcabcbbcbbac"; +char *regexes[] = { "(ab)+", "(b.+)+", "a[ab]*", "([ab^c][ab^c])+" }; + +void +initialise_benchmark (void) +{ +} + + +static int benchmark_body (int rpt); + +void +warm_caches (int heat) +{ + int res = benchmark_body (heat); + + return; +} + + +int +benchmark (void) +{ + return benchmark_body (LOCAL_SCALE_FACTOR * CPU_MHZ); +} + + +static int __attribute__ ((noinline)) +benchmark_body (int rpt) +{ + volatile int ret; + int j; + + for (j = 0; j < rpt; j++) + { + int i; + int len = strlen (text); + struct slre_cap captures; + ret = 0; + + for (i = 0; i < 4; ++i) + { + ret += slre_match (regexes[i], text, len, &captures, 1); + } + } + + return ret; +} + + +int +verify_benchmark (int r) +{ + return 102 == r; +} + + +/* + Local Variables: + mode: C + c-file-style: "gnu" + End: +*/ diff --git a/benchies/embench/benchemarks/slre/slre.h b/benchies/embench/benchemarks/slre/slre.h new file mode 100644 index 0000000000..b09aea9fd4 --- /dev/null +++ b/benchies/embench/benchemarks/slre/slre.h @@ -0,0 +1,58 @@ +/* BEEBS slre benchmark + + Copyright (c) 2004-2013 Sergey Lyubka + Copyright (c) 2013 Cesanta Software Limited. All rights reserved + Copyright (C) 2014 Embecosm Limited and University of Bristol + + This version, copyright (C) 2014-2019 Embecosm Limited and University of + Bristol + + Contributor James Pallister + Contributor Jeremy Bennett + + This file is part of Embench and was formerly part of the Bristol/Embecosm + Embedded Benchmark Suite. + + SPDX-License-Identifier: GPL-3.0-or-later */ + +#ifndef SLRE_HEADER_DEFINED +#define SLRE_HEADER_DEFINED + +#ifdef __cplusplus +extern "C" +{ +#endif + + struct slre_cap + { + const char *ptr; + int len; + }; + + int slre_match (const char *regexp, const char *buf, int buf_len, + struct slre_cap *caps, int num_caps); + +/* slre_match() failure codes */ +#define SLRE_NO_MATCH -1 +#define SLRE_UNEXPECTED_QUANTIFIER -2 +#define SLRE_UNBALANCED_BRACKETS -3 +#define SLRE_INTERNAL_ERROR -4 +#define SLRE_INVALID_CHARACTER_SET -5 +#define SLRE_INVALID_METACHARACTER -6 +#define SLRE_CAPS_ARRAY_TOO_SMALL -7 +#define SLRE_TOO_MANY_BRANCHES -8 +#define SLRE_TOO_MANY_BRACKETS -9 + +#ifdef __cplusplus +} +#endif + +#endif /* SLRE_HEADER_DEFINED */ + + +/* + Local Variables: + mode: C + c-file-style: "gnu" + End: +*/ diff --git a/benchies/embench/benchemarks/st/libst.c b/benchies/embench/benchemarks/st/libst.c new file mode 100644 index 0000000000..5d3d44ba85 --- /dev/null +++ b/benchies/embench/benchemarks/st/libst.c @@ -0,0 +1,220 @@ +/* BEEBS st benchmark + + This version, copyright (C) 2014-2019 Embecosm Limited and University of + Bristol + + Contributor James Pallister + Contributor Jeremy Bennett + + This file is part of Embench and was formerly part of the Bristol/Embecosm + Embedded Benchmark Suite. + + SPDX-License-Identifier: GPL-3.0-or-later */ + +/* stats.c */ + +/* 2012/09/28, Jan Gustafsson + * Changes: + * - time is only enabled if the POUT flag is set + * - st.c:30:1: main () warning: type specifier missing, defaults to 'int': + * fixed + */ + + +/* 2011/10/18, Benedikt Huber + * Changes: + * - Measurement and Printing the Results is only enabled if the POUT flag is + * set + * - Added Prototypes for InitSeed and RandomInteger + * - Changed return type of InitSeed from 'missing (default int)' to 'void' + */ + +#include +#include "../../src/support.h" + +/* This scale factor will be changed to equalise the runtime of the + benchmarks. */ +#define LOCAL_SCALE_FACTOR 13 + +#define MAX 100 + +void InitSeed (void); +int RandomInteger (); +void Initialize (double[]); +void Calc_Sum_Mean (double[], double *, double *); +void Calc_Var_Stddev (double[], double, double *, double *); +void Calc_LinCorrCoef (double[], double[], double, double); + + +/* Statistics Program: + * This program computes for two arrays of numbers the sum, the + * mean, the variance, and standard deviation. It then determines the + * correlation coefficient between the two arrays. + */ + +int Seed; +double ArrayA[MAX], ArrayB[MAX]; +double SumA, SumB; +double Coef; + + +void +initialise_benchmark (void) +{ +} + + +static int benchmark_body (int rpt); + +void +warm_caches (int heat) +{ + int res = benchmark_body (heat); + + return; +} + + +int +benchmark (void) +{ + return benchmark_body (LOCAL_SCALE_FACTOR * CPU_MHZ); +} + + +static int __attribute__ ((noinline)) +benchmark_body (int rpt) +{ + int i; + + for (i = 0; i < rpt; i++) + { + double MeanA, MeanB, VarA, VarB, StddevA, StddevB /*, Coef */ ; + + InitSeed (); + + Initialize (ArrayA); + Calc_Sum_Mean (ArrayA, &SumA, &MeanA); + Calc_Var_Stddev (ArrayA, MeanA, &VarA, &StddevA); + + Initialize (ArrayB); + Calc_Sum_Mean (ArrayB, &SumB, &MeanB); + Calc_Var_Stddev (ArrayB, MeanB, &VarB, &StddevB); + + /* Coef will have to be used globally in Calc_LinCorrCoef since it would + be beyond the 6 registers used for passing parameters + */ + Calc_LinCorrCoef (ArrayA, ArrayB, MeanA, MeanB /*, &Coef */ ); + } + + return 0; +} + + +void +InitSeed () +/* + * Initializes the seed used in the random number generator. + */ +{ + Seed = 0; +} + + +void +Calc_Sum_Mean (double Array[], double *Sum, double *Mean) +{ + int i; + + *Sum = 0; + for (i = 0; i < MAX; i++) + *Sum += Array[i]; + *Mean = *Sum / MAX; +} + + +double +Square (double x) +{ + return x * x; +} + + +void +Calc_Var_Stddev (double Array[], double Mean, double *Var, double *Stddev) +{ + int i; + double diffs; + + diffs = 0.0; + for (i = 0; i < MAX; i++) + diffs += Square (Array[i] - Mean); + *Var = diffs / MAX; + *Stddev = sqrt (*Var); +} + + +void +Calc_LinCorrCoef (double ArrayA[], double ArrayB[], double MeanA, + double MeanB /*, Coef */ ) +{ + int i; + double numerator, Aterm, Bterm; + + numerator = 0.0; + Aterm = Bterm = 0.0; + for (i = 0; i < MAX; i++) + { + numerator += (ArrayA[i] - MeanA) * (ArrayB[i] - MeanB); + Aterm += Square (ArrayA[i] - MeanA); + Bterm += Square (ArrayB[i] - MeanB); + } + + /* Coef used globally */ + Coef = numerator / (sqrt (Aterm) * sqrt (Bterm)); +} + + + +void +Initialize (double Array[]) +/* + * Intializes the given array with random integers. + */ +{ + register int i; + + for (i = 0; i < MAX; i++) + Array[i] = i + RandomInteger () / 8095.0; +} + + +int +RandomInteger () +/* + * Generates random integers between 0 and 8095 + */ +{ + Seed = ((Seed * 133) + 81) % 8095; + return (Seed); +} + +int +verify_benchmark (int unused) +{ + double expSumA = 4999.00247066090196; + double expSumB = 4996.84311303273534; + double expCoef = 0.999900054853619324; + + return double_eq_beebs(expSumA, SumA) + && double_eq_beebs(expSumB, SumB) + && double_eq_beebs(expCoef, Coef); +} + + +/* + Local Variables: + mode: C + c-file-style: "gnu" + End: +*/ diff --git a/benchies/embench/benchemarks/statemate/libstatemate.c b/benchies/embench/benchemarks/statemate/libstatemate.c new file mode 100644 index 0000000000..05c69026e6 --- /dev/null +++ b/benchies/embench/benchemarks/statemate/libstatemate.c @@ -0,0 +1,1501 @@ +/* BEEBS statemate benchmark + + This version, copyright (C) 2014-2019 Embecosm Limited and University of + Bristol + + Contributor James Pallister + Contributor Jeremy Bennett + + This file is part of Embench and was formerly part of the Bristol/Embecosm + Embedded Benchmark Suite. + + SPDX-License-Identifier: GPL-3.0-or-later */ + +/* MDH WCET BENCHMARK SUITE. */ + +/* + *---------------------------------------------------------- + * + * statemate.c + * + * This code was automatically generated by + * the STAtechart Real-time-Code generator STARC + * which was developed at C-LAB. + * + * The original StateChart specifies an experimental + * car window lift control. + * + * Modified and maintained by + * Friedhelm Stappert + * C-LAB, Paderborn, Germany + * fst@c-lab.de + * + * Modifications: + * o '#define float int' so we don't need a + * floating point library. + * + * o modified the Bitlist functions. + * 'Bitlist is now just a array of char's + * so we don't need the BitList library. + * + *---------------------------------------------------------- + */ + +#include +#include "../../src/support.h" + +/* This scale factor will be changed to equalise the runtime of the + benchmarks. */ +#define LOCAL_SCALE_FACTOR 1964 + +/* +** actually, we don't really need floating point here +*/ +#define float int + +static char Bitlist[64]; +#define SYS_bit_get(a,b) (a)[(b)] +#define SYS_bit_clr(a,b) (a)[(b)] = 0 +#define SYS_bit_set(a,b) (a)[(b)] = 1 +#define SYS_bit_cpy(a1,i1,a2,i2) (a1)[(i1)] = (a2)[(i2)] + + +#define active_KINDERSICHERUNG_CTRL_IDX 10 +#define active_KINDERSICHERUNG_CTRL_copy_IDX 11 +#define active_KINDERSICHERUNG_CTRL_old_IDX 12 +#define active_FH_TUERMODUL_CTRL_IDX 13 +#define active_FH_TUERMODUL_CTRL_copy_IDX 14 +#define active_FH_TUERMODUL_CTRL_old_IDX 15 +#define active_EINKLEMMSCHUTZ_CTRL_IDX 16 +#define active_EINKLEMMSCHUTZ_CTRL_copy_IDX 17 +#define active_EINKLEMMSCHUTZ_CTRL_old_IDX 18 +#define active_BLOCK_ERKENNUNG_CTRL_IDX 19 +#define active_BLOCK_ERKENNUNG_CTRL_copy_IDX 20 +#define active_BLOCK_ERKENNUNG_CTRL_old_IDX 21 +#define entered_EINSCHALTSTROM_MESSEN_BLOCK_ERKENNUNG_CTRL_IDX 0 +#define entered_EINSCHALTSTROM_MESSEN_BLOCK_ERKENNUNG_CTRL_copy_IDX 1 +unsigned long + tm_entered_EINSCHALTSTROM_MESSEN_BLOCK_ERKENNUNG_CTRLch_BLOCK_ERKENNUNG_CTRL__N_copy; +#define entered_WIEDERHOLSPERRE_FH_TUERMODUL_CTRL_IDX 4 +#define entered_WIEDERHOLSPERRE_FH_TUERMODUL_CTRL_copy_IDX 5 +#define exited_BEREIT_FH_TUERMODUL_CTRL_IDX 6 +#define exited_BEREIT_FH_TUERMODUL_CTRL_copy_IDX 7 +unsigned long + tm_entered_WIEDERHOLSPERRE_FH_TUERMODUL_CTRLexited_BEREIT_FH_TUERMODUL_CTRL; +unsigned long tm_entered_WIEDERHOLSPERRE_FH_TUERMODUL_CTRL; +unsigned long sc_FH_TUERMODUL_CTRL_2375_2; +unsigned long sc_FH_TUERMODUL_CTRL_2352_1; +unsigned long sc_FH_TUERMODUL_CTRL_2329_1; +int FH_TUERMODUL_CTRL__N; +int FH_TUERMODUL_CTRL__N_copy; +int FH_TUERMODUL_CTRL__N_old; +unsigned long sc_FH_TUERMODUL_CTRL_1781_10; +unsigned long sc_FH_TUERMODUL_CTRL_1739_10; +float FH_TUERMODUL__POSITION; +float FH_TUERMODUL__I_EIN; +float FH_TUERMODUL__I_EIN_old; +int FH_DU__MFH; +int FH_DU__MFH_copy; +float FH_DU__POSITION; +float FH_DU__I_EIN; +float FH_DU__I_EIN_old; +float BLOCK_ERKENNUNG_CTRL__I_EIN_MAX; +float BLOCK_ERKENNUNG_CTRL__I_EIN_MAX_copy; +int BLOCK_ERKENNUNG_CTRL__N; +int BLOCK_ERKENNUNG_CTRL__N_copy; +int BLOCK_ERKENNUNG_CTRL__N_old; +char FH_TUERMODUL_CTRL__INREVERS2; +char FH_TUERMODUL_CTRL__INREVERS2_copy; +char FH_TUERMODUL_CTRL__INREVERS1; +char FH_TUERMODUL_CTRL__INREVERS1_copy; +char FH_TUERMODUL_CTRL__FT; +char FH_TUERMODUL__SFHZ_ZENTRAL; +char FH_TUERMODUL__SFHZ_ZENTRAL_old; +char FH_TUERMODUL__SFHZ_MEC; +char FH_TUERMODUL__SFHZ_MEC_old; +char FH_TUERMODUL__SFHA_ZENTRAL; +char FH_TUERMODUL__SFHA_ZENTRAL_old; +char FH_TUERMODUL__SFHA_MEC; +char FH_TUERMODUL__SFHA_MEC_old; +char FH_TUERMODUL__KL_50; +char FH_TUERMODUL__BLOCK; +char FH_TUERMODUL__BLOCK_copy; +char FH_TUERMODUL__BLOCK_old; +char FH_TUERMODUL__FT; +char FH_TUERMODUL__SFHZ; +char FH_TUERMODUL__SFHZ_copy; +char FH_TUERMODUL__SFHZ_old; +char FH_TUERMODUL__SFHA; +char FH_TUERMODUL__SFHA_copy; +char FH_TUERMODUL__SFHA_old; +char FH_TUERMODUL__MFHZ; +char FH_TUERMODUL__MFHZ_copy; +char FH_TUERMODUL__MFHZ_old; +char FH_TUERMODUL__MFHA; +char FH_TUERMODUL__MFHA_copy; +char FH_TUERMODUL__MFHA_old; +char FH_TUERMODUL__EKS_LEISTE_AKTIV; +char FH_TUERMODUL__EKS_LEISTE_AKTIV_old; +char FH_TUERMODUL__COM_OPEN; +char FH_TUERMODUL__COM_CLOSE; +char FH_DU__KL_50; +char FH_DU__S_FH_FTZU; +char FH_DU__S_FH_FTAUF; +char FH_DU__FT; +char FH_DU__EKS_LEISTE_AKTIV; +char FH_DU__EKS_LEISTE_AKTIV_old; +char FH_DU__S_FH_TMBFAUFCAN; +char FH_DU__S_FH_TMBFAUFCAN_copy; +char FH_DU__S_FH_TMBFAUFCAN_old; +char FH_DU__S_FH_TMBFZUCAN; +char FH_DU__S_FH_TMBFZUCAN_copy; +char FH_DU__S_FH_TMBFZUCAN_old; +char FH_DU__S_FH_TMBFZUDISC; +char FH_DU__S_FH_TMBFZUDISC_old; +char FH_DU__S_FH_TMBFAUFDISC; +char FH_DU__S_FH_TMBFAUFDISC_old; +char FH_DU__S_FH_ZUDISC; +char FH_DU__S_FH_AUFDISC; +char FH_DU__DOOR_ID; +char FH_DU__BLOCK; +char FH_DU__BLOCK_copy; +char FH_DU__BLOCK_old; +char FH_DU__MFHZ; +char FH_DU__MFHZ_copy; +char FH_DU__MFHZ_old; +char FH_DU__MFHA; +char FH_DU__MFHA_copy; +char FH_DU__MFHA_old; +#define FH_TUERMODUL_CTRL__END_REVERS_IDX 22 +#define FH_TUERMODUL_CTRL__END_REVERS_copy_IDX 23 +#define FH_TUERMODUL__EINKLEMMUNG_IDX 24 + +unsigned long time; +char stable; +char step; + +char NICHT_INITIALISIERT_NICHT_INITIALISIERT_next_state; /** 2 bits **/ +char ZENTRAL_KINDERSICHERUNG_CTRL_next_state; /** 1 bits **/ +char MEC_KINDERSICHERUNG_CTRL_next_state; /** 1 bits **/ +char KINDERSICHERUNG_CTRL_KINDERSICHERUNG_CTRL_next_state; /** 2 bits **/ +char B_FH_TUERMODUL_CTRL_next_state; /** 2 bits **/ +char A_FH_TUERMODUL_CTRL_next_state; /** 1 bits **/ +char WIEDERHOLSPERRE_FH_TUERMODUL_CTRL_next_state; /** 1 bits **/ +char INITIALISIERT_FH_TUERMODUL_CTRL_next_state; /** 2 bits **/ +char TIPP_SCHLIESSEN_FH_TUERMODUL_CTRL_next_state; /** 2 bits **/ +char MANUELL_SCHLIESSEN_FH_TUERMODUL_CTRL_next_state; /** 2 bits **/ +char OEFFNEN_FH_TUERMODUL_CTRL_next_state; /** 2 bits **/ +char SCHLIESSEN_FH_TUERMODUL_CTRL_next_state; /** 2 bits **/ +char FH_STEUERUNG_DUMMY_FH_STEUERUNG_DUMMY_next_state; /** 2 bits **/ +char EINKLEMMSCHUTZ_CTRL_EINKLEMMSCHUTZ_CTRL_next_state; /** 2 bits **/ +char BEWEGUNG_BLOCK_ERKENNUNG_CTRL_next_state; /** 2 bits **/ +char BLOCK_ERKENNUNG_CTRL_BLOCK_ERKENNUNG_CTRL_next_state; /** 2 bits **/ + + +void +interface (void) +{ + if (SYS_bit_get (Bitlist, entered_WIEDERHOLSPERRE_FH_TUERMODUL_CTRL_IDX)) + tm_entered_WIEDERHOLSPERRE_FH_TUERMODUL_CTRL = time; + if (SYS_bit_get (Bitlist, entered_WIEDERHOLSPERRE_FH_TUERMODUL_CTRL_IDX) + || SYS_bit_get (Bitlist, exited_BEREIT_FH_TUERMODUL_CTRL_IDX)) + tm_entered_WIEDERHOLSPERRE_FH_TUERMODUL_CTRLexited_BEREIT_FH_TUERMODUL_CTRL + = time; + if ((sc_FH_TUERMODUL_CTRL_2375_2 != 0) + && (time - sc_FH_TUERMODUL_CTRL_2375_2 >= 0.5)) + { + FH_TUERMODUL__MFHA_copy = 0; + sc_FH_TUERMODUL_CTRL_2375_2 = 0; + + } + if ((sc_FH_TUERMODUL_CTRL_2352_1 != 0) + && (time - sc_FH_TUERMODUL_CTRL_2352_1 >= 0.5)) + { + FH_TUERMODUL__MFHZ_copy = 0; + sc_FH_TUERMODUL_CTRL_2352_1 = 0; + + } + if ((sc_FH_TUERMODUL_CTRL_2329_1 != 0) + && (time - sc_FH_TUERMODUL_CTRL_2329_1 >= 0.5)) + { + FH_TUERMODUL__MFHZ_copy = 0; + sc_FH_TUERMODUL_CTRL_2329_1 = 0; + + } + if ((sc_FH_TUERMODUL_CTRL_1781_10 != 0) + && (time - sc_FH_TUERMODUL_CTRL_1781_10 >= 0.5)) + { + sc_FH_TUERMODUL_CTRL_1781_10 = 0; + + } + if ((sc_FH_TUERMODUL_CTRL_1739_10 != 0) + && (time - sc_FH_TUERMODUL_CTRL_1739_10 >= 0.5)) + { + sc_FH_TUERMODUL_CTRL_1739_10 = 0; + + } + if ((SYS_bit_get + (Bitlist, entered_EINSCHALTSTROM_MESSEN_BLOCK_ERKENNUNG_CTRL_IDX) + || BLOCK_ERKENNUNG_CTRL__N != BLOCK_ERKENNUNG_CTRL__N_old)) + tm_entered_EINSCHALTSTROM_MESSEN_BLOCK_ERKENNUNG_CTRLch_BLOCK_ERKENNUNG_CTRL__N_copy + = time; + + +}/** interface **/ + + +void +init (void) +{ + tm_entered_EINSCHALTSTROM_MESSEN_BLOCK_ERKENNUNG_CTRLch_BLOCK_ERKENNUNG_CTRL__N_copy + = 0; + tm_entered_WIEDERHOLSPERRE_FH_TUERMODUL_CTRLexited_BEREIT_FH_TUERMODUL_CTRL + = 0; + tm_entered_WIEDERHOLSPERRE_FH_TUERMODUL_CTRL = 0; + NICHT_INITIALISIERT_NICHT_INITIALISIERT_next_state = 0; + ZENTRAL_KINDERSICHERUNG_CTRL_next_state = 0; + MEC_KINDERSICHERUNG_CTRL_next_state = 0; + KINDERSICHERUNG_CTRL_KINDERSICHERUNG_CTRL_next_state = 0; + B_FH_TUERMODUL_CTRL_next_state = 0; + A_FH_TUERMODUL_CTRL_next_state = 0; + WIEDERHOLSPERRE_FH_TUERMODUL_CTRL_next_state = 0; + INITIALISIERT_FH_TUERMODUL_CTRL_next_state = 0; + TIPP_SCHLIESSEN_FH_TUERMODUL_CTRL_next_state = 0; + MANUELL_SCHLIESSEN_FH_TUERMODUL_CTRL_next_state = 0; + OEFFNEN_FH_TUERMODUL_CTRL_next_state = 0; + SCHLIESSEN_FH_TUERMODUL_CTRL_next_state = 0; + FH_STEUERUNG_DUMMY_FH_STEUERUNG_DUMMY_next_state = 0; + EINKLEMMSCHUTZ_CTRL_EINKLEMMSCHUTZ_CTRL_next_state = 0; + BEWEGUNG_BLOCK_ERKENNUNG_CTRL_next_state = 0; + BLOCK_ERKENNUNG_CTRL_BLOCK_ERKENNUNG_CTRL_next_state = 0; + + +}/** init **/ + + + +void +generic_KINDERSICHERUNG_CTRL (void) +{ + if (SYS_bit_get (Bitlist, active_KINDERSICHERUNG_CTRL_IDX)) + { + switch (KINDERSICHERUNG_CTRL_KINDERSICHERUNG_CTRL_next_state) + { + case 1: /** state ZENTRAL in chart KINDERSICHERUNG_CTRL **/ + { + if (!(FH_TUERMODUL__SFHA_ZENTRAL || FH_TUERMODUL__SFHZ_ZENTRAL)) + { + stable = 0; + FH_TUERMODUL__SFHZ_copy = 0; + FH_TUERMODUL__SFHA_copy = 0; + + KINDERSICHERUNG_CTRL_KINDERSICHERUNG_CTRL_next_state = 3; + ZENTRAL_KINDERSICHERUNG_CTRL_next_state = 0; + break; + } + switch (ZENTRAL_KINDERSICHERUNG_CTRL_next_state) + { + case 1: /** state IN_ZENTRAL in chart KINDERSICHERUNG_CTRL **/ + { + if ((FH_TUERMODUL__SFHA_ZENTRAL + && !(FH_TUERMODUL__SFHA_ZENTRAL_old))) + { + stable = 0; + FH_TUERMODUL__SFHA_copy = 1; + + ZENTRAL_KINDERSICHERUNG_CTRL_next_state = 1; + break; + } + if ((FH_TUERMODUL__SFHZ_ZENTRAL + && !(FH_TUERMODUL__SFHZ_ZENTRAL_old))) + { + stable = 0; + FH_TUERMODUL__SFHZ_copy = 1; + + ZENTRAL_KINDERSICHERUNG_CTRL_next_state = 1; + break; + } + if ((!(FH_TUERMODUL__SFHA_ZENTRAL) + && FH_TUERMODUL__SFHA_ZENTRAL_old)) + { + stable = 0; + FH_TUERMODUL__SFHA_copy = 0; + + ZENTRAL_KINDERSICHERUNG_CTRL_next_state = 1; + break; + } + if ((!(FH_TUERMODUL__SFHZ_ZENTRAL) + && FH_TUERMODUL__SFHZ_ZENTRAL_old)) + { + stable = 0; + FH_TUERMODUL__SFHZ_copy = 0; + + ZENTRAL_KINDERSICHERUNG_CTRL_next_state = 1; + break; + } + break; + } + default: + { + stable = 0; + break; + } + } + /** switch ZENTRAL_KINDERSICHERUNG_CTRL_next_state **/ + break; + } + case 2: /** state MEC in chart KINDERSICHERUNG_CTRL **/ + { + if (!(FH_TUERMODUL__SFHA_MEC || FH_TUERMODUL__SFHZ_MEC)) + { + stable = 0; + FH_TUERMODUL__SFHZ_copy = 0; + FH_TUERMODUL__SFHA_copy = 0; + + KINDERSICHERUNG_CTRL_KINDERSICHERUNG_CTRL_next_state = 3; + MEC_KINDERSICHERUNG_CTRL_next_state = 0; + break; + } + switch (MEC_KINDERSICHERUNG_CTRL_next_state) + { + case 1: /** state INMEC in chart KINDERSICHERUNG_CTRL **/ + { + if ((FH_TUERMODUL__SFHA_MEC + && !(FH_TUERMODUL__SFHA_MEC_old))) + { + stable = 0; + FH_TUERMODUL__SFHA_copy = 1; + + MEC_KINDERSICHERUNG_CTRL_next_state = 1; + break; + } + if ((FH_TUERMODUL__SFHZ_MEC + && !(FH_TUERMODUL__SFHZ_MEC_old))) + { + stable = 0; + FH_TUERMODUL__SFHZ_copy = 1; + + MEC_KINDERSICHERUNG_CTRL_next_state = 1; + break; + } + if ((!(FH_TUERMODUL__SFHA_MEC) + && FH_TUERMODUL__SFHA_MEC_old)) + { + stable = 0; + FH_TUERMODUL__SFHA_copy = 0; + + MEC_KINDERSICHERUNG_CTRL_next_state = 1; + break; + } + if ((!(FH_TUERMODUL__SFHZ_MEC) + && FH_TUERMODUL__SFHZ_MEC_old)) + { + stable = 0; + FH_TUERMODUL__SFHZ_copy = 0; + + MEC_KINDERSICHERUNG_CTRL_next_state = 1; + break; + } + break; + } + default: + { + stable = 0; + break; + } + } + /** switch MEC_KINDERSICHERUNG_CTRL_next_state **/ + break; + } + case 3: /** state WAITING in chart KINDERSICHERUNG_CTRL **/ + { + if ((!FH_TUERMODUL__KL_50) + && (FH_TUERMODUL__SFHZ_MEC && FH_TUERMODUL__SFHA_MEC)) + { + stable = 0; + FH_TUERMODUL__SFHZ_copy = 1; + FH_TUERMODUL__SFHA_copy = 1; + + KINDERSICHERUNG_CTRL_KINDERSICHERUNG_CTRL_next_state = 2; + break; + } + if ((!FH_TUERMODUL__KL_50) + && (FH_TUERMODUL__SFHZ_MEC && !FH_TUERMODUL__SFHA_MEC)) + { + stable = 0; + FH_TUERMODUL__SFHZ_copy = 1; + + KINDERSICHERUNG_CTRL_KINDERSICHERUNG_CTRL_next_state = 2; + break; + } + if ((!FH_TUERMODUL__KL_50) + && (!FH_TUERMODUL__SFHZ_MEC && FH_TUERMODUL__SFHA_MEC)) + { + stable = 0; + FH_TUERMODUL__SFHA_copy = 1; + + KINDERSICHERUNG_CTRL_KINDERSICHERUNG_CTRL_next_state = 2; + break; + } + if ((!FH_TUERMODUL__SFHZ_ZENTRAL && FH_TUERMODUL__SFHA_ZENTRAL + && !FH_TUERMODUL__KL_50)) + { + stable = 0; + FH_TUERMODUL__SFHA_copy = 1; + + KINDERSICHERUNG_CTRL_KINDERSICHERUNG_CTRL_next_state = 1; + break; + } + if ((FH_TUERMODUL__SFHZ_ZENTRAL && FH_TUERMODUL__SFHA_ZENTRAL)) + { + stable = 0; + FH_TUERMODUL__SFHA_copy = 1; + FH_TUERMODUL__SFHZ_copy = 1; + + KINDERSICHERUNG_CTRL_KINDERSICHERUNG_CTRL_next_state = 1; + break; + } + if ((FH_TUERMODUL__SFHZ_ZENTRAL && !FH_TUERMODUL__SFHA_ZENTRAL + && !FH_TUERMODUL__KL_50)) + { + stable = 0; + FH_TUERMODUL__SFHZ_copy = 1; + + KINDERSICHERUNG_CTRL_KINDERSICHERUNG_CTRL_next_state = 1; + break; + } + break; + } + default: + { + stable = 0; + KINDERSICHERUNG_CTRL_KINDERSICHERUNG_CTRL_next_state = 3; + break; + } + } + /** switch KINDERSICHERUNG_CTRL_KINDERSICHERUNG_CTRL_next_state **/ + } +} + +void +generic_FH_TUERMODUL_CTRL (void) +{ + if (!SYS_bit_get (Bitlist, active_FH_TUERMODUL_CTRL_IDX) + && SYS_bit_get (Bitlist, active_FH_TUERMODUL_CTRL_old_IDX) + && !SYS_bit_get (Bitlist, active_FH_TUERMODUL_CTRL_copy_IDX)) + { + SYS_bit_clr (Bitlist, entered_WIEDERHOLSPERRE_FH_TUERMODUL_CTRL_IDX); + SYS_bit_clr (Bitlist, exited_BEREIT_FH_TUERMODUL_CTRL_IDX); + } + if (SYS_bit_get (Bitlist, active_FH_TUERMODUL_CTRL_IDX)) + { + if (!SYS_bit_get (Bitlist, active_KINDERSICHERUNG_CTRL_IDX)) + { + KINDERSICHERUNG_CTRL_KINDERSICHERUNG_CTRL_next_state = 3; + } + SYS_bit_clr (Bitlist, active_KINDERSICHERUNG_CTRL_copy_IDX); + if (!SYS_bit_get (Bitlist, active_BLOCK_ERKENNUNG_CTRL_IDX)) + { + SYS_bit_clr (Bitlist, + entered_EINSCHALTSTROM_MESSEN_BLOCK_ERKENNUNG_CTRL_IDX); + BLOCK_ERKENNUNG_CTRL_BLOCK_ERKENNUNG_CTRL_next_state = 1; + } + SYS_bit_clr (Bitlist, active_BLOCK_ERKENNUNG_CTRL_copy_IDX); + SYS_bit_set (Bitlist, active_KINDERSICHERUNG_CTRL_copy_IDX); + SYS_bit_set (Bitlist, active_BLOCK_ERKENNUNG_CTRL_copy_IDX); + switch (B_FH_TUERMODUL_CTRL_next_state) + { + case 1: /** state ZAEHLER_WHSP_ZU_HOCH in chart FH_TUERMODUL_CTRL **/ + { + if ((FH_TUERMODUL_CTRL__N == 59 + && !(FH_TUERMODUL_CTRL__N_old == 59))) + { + stable = 0; + + B_FH_TUERMODUL_CTRL_next_state = 3; + INITIALISIERT_FH_TUERMODUL_CTRL_next_state = 3; + break; + } + break; + } + case 2: /** state NICHT_INITIALISIERT in chart FH_TUERMODUL_CTRL **/ + { + if (((FH_TUERMODUL__BLOCK && !(FH_TUERMODUL__BLOCK_old))) + && ((FH_TUERMODUL__MFHZ))) + { + stable = 0; + FH_TUERMODUL__MFHZ_copy = 0; + sc_FH_TUERMODUL_CTRL_2329_1 = time; + + B_FH_TUERMODUL_CTRL_next_state = 3; + INITIALISIERT_FH_TUERMODUL_CTRL_next_state = 3; + break; + } + switch (NICHT_INITIALISIERT_NICHT_INITIALISIERT_next_state) + { + case 1: /** state SCHLIESSEN in chart NICHT_INITIALISIERT **/ + { + if (!(FH_TUERMODUL__SFHZ)) + { + stable = 0; + FH_TUERMODUL__MFHZ_copy = 0; + + NICHT_INITIALISIERT_NICHT_INITIALISIERT_next_state = 3; + break; + } + break; + } + case 2: /** state OEFFNEN in chart NICHT_INITIALISIERT **/ + { + if (!(FH_TUERMODUL__SFHA)) + { + stable = 0; + FH_TUERMODUL__MFHA_copy = 0; + + NICHT_INITIALISIERT_NICHT_INITIALISIERT_next_state = 3; + break; + } + break; + } + case 3: /** state BEREIT in chart NICHT_INITIALISIERT **/ + { + if ((FH_TUERMODUL__SFHA)) + { + stable = 0; + FH_TUERMODUL__MFHA_copy = 1; + + NICHT_INITIALISIERT_NICHT_INITIALISIERT_next_state = 2; + break; + } + if ((FH_TUERMODUL__SFHZ)) + { + stable = 0; + FH_TUERMODUL__MFHZ_copy = 1; + + NICHT_INITIALISIERT_NICHT_INITIALISIERT_next_state = 1; + break; + } + break; + } + default: + { + stable = 0; + NICHT_INITIALISIERT_NICHT_INITIALISIERT_next_state = 3; + break; + } + } + /** switch NICHT_INITIALISIERT_NICHT_INITIALISIERT_next_state **/ + break; + } + case 3: /** state INITIALISIERT in chart FH_TUERMODUL_CTRL **/ + { + if (((FH_TUERMODUL_CTRL__N > 60 + && !(FH_TUERMODUL_CTRL__N_old > 60))) + && + ((!(FH_TUERMODUL_CTRL__INREVERS1 + || FH_TUERMODUL_CTRL__INREVERS2)))) + { + stable = 0; + FH_TUERMODUL__MFHZ_copy = 0; + FH_TUERMODUL__MFHA_copy = 0; + + B_FH_TUERMODUL_CTRL_next_state = 1; + break; + } + if (((FH_TUERMODUL__BLOCK && !(FH_TUERMODUL__BLOCK_old))) + && ((FH_TUERMODUL__MFHA))) + { + stable = 0; + FH_TUERMODUL__MFHA_copy = 0; + sc_FH_TUERMODUL_CTRL_2375_2 = time; + + B_FH_TUERMODUL_CTRL_next_state = 2; + NICHT_INITIALISIERT_NICHT_INITIALISIERT_next_state = 3; + break; + } + if (((FH_TUERMODUL__BLOCK && !(FH_TUERMODUL__BLOCK_old))) + && ((FH_TUERMODUL__MFHZ))) + { + stable = 0; + FH_TUERMODUL__MFHZ_copy = 0; + sc_FH_TUERMODUL_CTRL_2352_1 = time; + + B_FH_TUERMODUL_CTRL_next_state = 2; + NICHT_INITIALISIERT_NICHT_INITIALISIERT_next_state = 3; + break; + } + switch (INITIALISIERT_FH_TUERMODUL_CTRL_next_state) + { + case 1: /** state OEFFNEN in chart FH_TUERMODUL_CTRL **/ + { + if ((FH_TUERMODUL__POSITION >= 405)) + { + stable = 0; + FH_TUERMODUL__MFHA_copy = 0; + + INITIALISIERT_FH_TUERMODUL_CTRL_next_state = 3; + break; + } + switch (OEFFNEN_FH_TUERMODUL_CTRL_next_state) + { + case 1: /** state TIPP_OEFFNEN in chart FH_TUERMODUL_CTRL **/ + { + if ((FH_TUERMODUL__SFHZ && !(FH_TUERMODUL__SFHZ_old)) + || (FH_TUERMODUL__SFHA + && !(FH_TUERMODUL__SFHA_old))) + { + stable = 0; + FH_TUERMODUL__MFHA_copy = 0; + + INITIALISIERT_FH_TUERMODUL_CTRL_next_state = 3; + OEFFNEN_FH_TUERMODUL_CTRL_next_state = 0; + break; + } + break; + } + case 2: /** state MAN_OEFFNEN in chart FH_TUERMODUL_CTRL **/ + { + if ((FH_TUERMODUL__SFHZ && !(FH_TUERMODUL__SFHZ_old))) + { + stable = 0; + + OEFFNEN_FH_TUERMODUL_CTRL_next_state = 1; + break; + } + if ((!(FH_TUERMODUL__SFHA) && FH_TUERMODUL__SFHA_old)) + { + stable = 0; + FH_TUERMODUL__MFHA_copy = 0; + + INITIALISIERT_FH_TUERMODUL_CTRL_next_state = 3; + OEFFNEN_FH_TUERMODUL_CTRL_next_state = 0; + break; + } + break; + } + default: + { + stable = 0; + OEFFNEN_FH_TUERMODUL_CTRL_next_state = 2; + break; + } + } + /** switch OEFFNEN_FH_TUERMODUL_CTRL_next_state **/ + break; + } + case 2: /** state SCHLIESSEN in chart FH_TUERMODUL_CTRL **/ + { + if ((FH_TUERMODUL__POSITION <= 0)) + { + stable = 0; + FH_TUERMODUL__MFHZ_copy = 0; + + INITIALISIERT_FH_TUERMODUL_CTRL_next_state = 3; + break; + } + switch (SCHLIESSEN_FH_TUERMODUL_CTRL_next_state) + { + case 1: /** state TIPP_SCHLIESSEN in chart FH_TUERMODUL_CTRL **/ + { + if ((FH_TUERMODUL__SFHA && !(FH_TUERMODUL__SFHA_old)) + || (FH_TUERMODUL__SFHZ + && !(FH_TUERMODUL__SFHZ_old))) + { + stable = 0; + FH_TUERMODUL__MFHZ_copy = 0; + + INITIALISIERT_FH_TUERMODUL_CTRL_next_state = 3; + break; + } + switch (TIPP_SCHLIESSEN_FH_TUERMODUL_CTRL_next_state) + { + case 1: /** state REVERSIEREN2 in chart FH_TUERMODUL_CTRL **/ + { + SYS_bit_clr (Bitlist, + FH_TUERMODUL_CTRL__END_REVERS_copy_IDX); + if (SYS_bit_get + (Bitlist, + FH_TUERMODUL_CTRL__END_REVERS_IDX)) + { + stable = 0; + FH_TUERMODUL__MFHZ_copy = 1; + FH_TUERMODUL_CTRL__INREVERS2_copy = 0; + + TIPP_SCHLIESSEN_FH_TUERMODUL_CTRL_next_state + = 2; + FH_TUERMODUL__MFHA_copy = 0; + + SYS_bit_set (Bitlist, + active_EINKLEMMSCHUTZ_CTRL_copy_IDX); + break; + } + break; + } + case 2: /** state TIPP_SCHLIESSEN1 in chart FH_TUERMODUL_CTRL **/ + { + if (SYS_bit_get + (Bitlist, FH_TUERMODUL__EINKLEMMUNG_IDX)) + { + stable = 0; + FH_TUERMODUL_CTRL__INREVERS2_copy = 1; + + SYS_bit_set (Bitlist, + FH_TUERMODUL_CTRL__END_REVERS_copy_IDX); + TIPP_SCHLIESSEN_FH_TUERMODUL_CTRL_next_state + = 1; + SYS_bit_clr (Bitlist, + active_EINKLEMMSCHUTZ_CTRL_copy_IDX); + FH_TUERMODUL__MFHZ_copy = 0; + + sc_FH_TUERMODUL_CTRL_1781_10 = time; + FH_TUERMODUL__MFHA_copy = 1; + break; + } + break; + } + default: + { + stable = 0; + TIPP_SCHLIESSEN_FH_TUERMODUL_CTRL_next_state = + 2; + SYS_bit_set (Bitlist, + active_EINKLEMMSCHUTZ_CTRL_copy_IDX); + break; + } + } + /** switch TIPP_SCHLIESSEN_FH_TUERMODUL_CTRL_next_state **/ + break; + } + case 2: /** state MANUELL_SCHLIESSEN in chart FH_TUERMODUL_CTRL **/ + { + if ((!(FH_TUERMODUL__SFHZ) && FH_TUERMODUL__SFHZ_old)) + { + stable = 0; + FH_TUERMODUL__MFHZ_copy = 0; + + INITIALISIERT_FH_TUERMODUL_CTRL_next_state = 3; + break; + } + switch + (MANUELL_SCHLIESSEN_FH_TUERMODUL_CTRL_next_state) + { + case 1: /** state REVERSIEREN1 in chart FH_TUERMODUL_CTRL **/ + { + SYS_bit_clr (Bitlist, + FH_TUERMODUL_CTRL__END_REVERS_copy_IDX); + if (SYS_bit_get + (Bitlist, + FH_TUERMODUL_CTRL__END_REVERS_IDX)) + { + stable = 0; + FH_TUERMODUL_CTRL__INREVERS1_copy = 0; + + MANUELL_SCHLIESSEN_FH_TUERMODUL_CTRL_next_state + = 2; + FH_TUERMODUL__MFHA_copy = 0; + + SYS_bit_set (Bitlist, + active_EINKLEMMSCHUTZ_CTRL_copy_IDX); + FH_TUERMODUL__MFHZ_copy = 1; + break; + } + break; + } + case 2: /** state MAN_SCHLIESSEN in chart FH_TUERMODUL_CTRL **/ + { + if (SYS_bit_get + (Bitlist, FH_TUERMODUL__EINKLEMMUNG_IDX)) + { + stable = 0; + FH_TUERMODUL__MFHZ_copy = 0; + FH_TUERMODUL_CTRL__INREVERS1_copy = 1; + + SYS_bit_set (Bitlist, + FH_TUERMODUL_CTRL__END_REVERS_copy_IDX); + MANUELL_SCHLIESSEN_FH_TUERMODUL_CTRL_next_state + = 1; + SYS_bit_clr (Bitlist, + active_EINKLEMMSCHUTZ_CTRL_copy_IDX); + + sc_FH_TUERMODUL_CTRL_1739_10 = time; + FH_TUERMODUL__MFHA_copy = 1; + break; + } + if ((FH_TUERMODUL__SFHA + && !(FH_TUERMODUL__SFHA_old))) + { + stable = 0; + + SCHLIESSEN_FH_TUERMODUL_CTRL_next_state = 1; + MANUELL_SCHLIESSEN_FH_TUERMODUL_CTRL_next_state + = 0; + break; + } + break; + } + default: + { + stable = 0; + MANUELL_SCHLIESSEN_FH_TUERMODUL_CTRL_next_state + = 2; + SYS_bit_set (Bitlist, + active_EINKLEMMSCHUTZ_CTRL_copy_IDX); + FH_TUERMODUL__MFHZ_copy = 1; + break; + } + } + /** switch MANUELL_SCHLIESSEN_FH_TUERMODUL_CTRL_next_state **/ + break; + } + default: + { + stable = 0; + SCHLIESSEN_FH_TUERMODUL_CTRL_next_state = 2; + MANUELL_SCHLIESSEN_FH_TUERMODUL_CTRL_next_state = 2; + SYS_bit_set (Bitlist, + active_EINKLEMMSCHUTZ_CTRL_copy_IDX); + FH_TUERMODUL__MFHZ_copy = 1; + break; + } + } + /** switch SCHLIESSEN_FH_TUERMODUL_CTRL_next_state **/ + break; + } + case 3: /** state BEREIT in chart FH_TUERMODUL_CTRL **/ + { + if (((FH_TUERMODUL__SFHZ && !(FH_TUERMODUL__SFHZ_old))) + && ((FH_TUERMODUL__POSITION > 0))) + { + stable = 0; + + INITIALISIERT_FH_TUERMODUL_CTRL_next_state = 2; + SCHLIESSEN_FH_TUERMODUL_CTRL_next_state = 2; + MANUELL_SCHLIESSEN_FH_TUERMODUL_CTRL_next_state = 2; + SYS_bit_set (Bitlist, + active_EINKLEMMSCHUTZ_CTRL_copy_IDX); + FH_TUERMODUL__MFHZ_copy = 1; + break; + } + if (((FH_TUERMODUL__SFHA && !(FH_TUERMODUL__SFHA_old))) + && ((FH_TUERMODUL__POSITION < 405))) + { + stable = 0; + FH_TUERMODUL__MFHA_copy = 1; + + INITIALISIERT_FH_TUERMODUL_CTRL_next_state = 1; + OEFFNEN_FH_TUERMODUL_CTRL_next_state = 2; + break; + } + break; + } + default: + { + stable = 0; + INITIALISIERT_FH_TUERMODUL_CTRL_next_state = 3; + break; + } + } + /** switch INITIALISIERT_FH_TUERMODUL_CTRL_next_state **/ + break; + } + default: + { + stable = 0; + B_FH_TUERMODUL_CTRL_next_state = 2; + break; + } + } + /** switch B_FH_TUERMODUL_CTRL_next_state **/ + switch (A_FH_TUERMODUL_CTRL_next_state) + { + case 1: /** state WIEDERHOLSPERRE in chart FH_TUERMODUL_CTRL **/ + { + SYS_bit_clr (Bitlist, + entered_WIEDERHOLSPERRE_FH_TUERMODUL_CTRL_copy_IDX); + if ((step == 1 + && + tm_entered_WIEDERHOLSPERRE_FH_TUERMODUL_CTRLexited_BEREIT_FH_TUERMODUL_CTRL + != 0 + && (time - + tm_entered_WIEDERHOLSPERRE_FH_TUERMODUL_CTRLexited_BEREIT_FH_TUERMODUL_CTRL + == 1)) && ((FH_TUERMODUL__MFHZ || FH_TUERMODUL__MFHA))) + { + stable = 0; + FH_TUERMODUL_CTRL__N = FH_TUERMODUL_CTRL__N + 1; + + A_FH_TUERMODUL_CTRL_next_state = 1; + SYS_bit_set (Bitlist, + entered_WIEDERHOLSPERRE_FH_TUERMODUL_CTRL_copy_IDX); + WIEDERHOLSPERRE_FH_TUERMODUL_CTRL_next_state = 1; + break; + } + switch (WIEDERHOLSPERRE_FH_TUERMODUL_CTRL_next_state) + { + case 1: /** state WDHSP in chart FH_TUERMODUL_CTRL **/ + { + if ((step == 1 + && tm_entered_WIEDERHOLSPERRE_FH_TUERMODUL_CTRL != 0 + && (time - + tm_entered_WIEDERHOLSPERRE_FH_TUERMODUL_CTRL == 3)) + && + (((!(FH_TUERMODUL__MFHZ || FH_TUERMODUL__MFHA)) + && FH_TUERMODUL_CTRL__N > 0))) + { + stable = 0; + FH_TUERMODUL_CTRL__N = FH_TUERMODUL_CTRL__N - 1; + + WIEDERHOLSPERRE_FH_TUERMODUL_CTRL_next_state = 1; + break; + } + break; + } + default: + { + stable = 0; + SYS_bit_set (Bitlist, + entered_WIEDERHOLSPERRE_FH_TUERMODUL_CTRL_copy_IDX); + WIEDERHOLSPERRE_FH_TUERMODUL_CTRL_next_state = 1; + break; + } + } + /** switch WIEDERHOLSPERRE_FH_TUERMODUL_CTRL_next_state **/ + break; + } + default: + { + stable = 0; + FH_TUERMODUL_CTRL__N = 0; + A_FH_TUERMODUL_CTRL_next_state = 1; + SYS_bit_set (Bitlist, + entered_WIEDERHOLSPERRE_FH_TUERMODUL_CTRL_copy_IDX); + WIEDERHOLSPERRE_FH_TUERMODUL_CTRL_next_state = 1; + break; + } + } + /** switch A_FH_TUERMODUL_CTRL_next_state **/ + SYS_bit_cpy (Bitlist, + entered_WIEDERHOLSPERRE_FH_TUERMODUL_CTRL_copy_IDX, + Bitlist, entered_WIEDERHOLSPERRE_FH_TUERMODUL_CTRL_IDX); + SYS_bit_cpy (Bitlist, exited_BEREIT_FH_TUERMODUL_CTRL_copy_IDX, Bitlist, + exited_BEREIT_FH_TUERMODUL_CTRL_IDX); + } +} + +void +generic_EINKLEMMSCHUTZ_CTRL (void) +{ + if (SYS_bit_get (Bitlist, active_EINKLEMMSCHUTZ_CTRL_IDX)) + { + switch (EINKLEMMSCHUTZ_CTRL_EINKLEMMSCHUTZ_CTRL_next_state) + { + case 1: /** state NORMALBETRIEB in chart EINKLEMMSCHUTZ_CTRL **/ + { + if (((FH_TUERMODUL__EKS_LEISTE_AKTIV + && !(FH_TUERMODUL__EKS_LEISTE_AKTIV_old))) + && ((!(FH_TUERMODUL__SFHZ && FH_TUERMODUL__SFHA)))) + { + stable = 0; + + SYS_bit_set (Bitlist, FH_TUERMODUL__EINKLEMMUNG_IDX); + EINKLEMMSCHUTZ_CTRL_EINKLEMMSCHUTZ_CTRL_next_state = 2; + break; + } + break; + } + case 2: /** state EINKLEMMUNG in chart EINKLEMMSCHUTZ_CTRL **/ + { + SYS_bit_clr (Bitlist, FH_TUERMODUL__EINKLEMMUNG_IDX); + if ((!(FH_TUERMODUL__EKS_LEISTE_AKTIV) + && FH_TUERMODUL__EKS_LEISTE_AKTIV_old)) + { + stable = 0; + + EINKLEMMSCHUTZ_CTRL_EINKLEMMSCHUTZ_CTRL_next_state = 1; + break; + } + break; + } + default: + { + stable = 0; + EINKLEMMSCHUTZ_CTRL_EINKLEMMSCHUTZ_CTRL_next_state = 1; + break; + } + } + /** switch EINKLEMMSCHUTZ_CTRL_EINKLEMMSCHUTZ_CTRL_next_state **/ + } +} + +void +generic_BLOCK_ERKENNUNG_CTRL (void) +{ + if (!SYS_bit_get (Bitlist, active_BLOCK_ERKENNUNG_CTRL_IDX) + && SYS_bit_get (Bitlist, active_BLOCK_ERKENNUNG_CTRL_old_IDX) + && !SYS_bit_get (Bitlist, active_BLOCK_ERKENNUNG_CTRL_copy_IDX)) + { + SYS_bit_clr (Bitlist, + entered_EINSCHALTSTROM_MESSEN_BLOCK_ERKENNUNG_CTRL_IDX); + } + if (SYS_bit_get (Bitlist, active_BLOCK_ERKENNUNG_CTRL_IDX)) + { + switch (BLOCK_ERKENNUNG_CTRL_BLOCK_ERKENNUNG_CTRL_next_state) + { + case 1: /** state KEINE_BEWEGUNG in chart BLOCK_ERKENNUNG_CTRL **/ + { + if ((FH_TUERMODUL__I_EIN != FH_TUERMODUL__I_EIN_old) + && ((FH_TUERMODUL__I_EIN > 0))) + { + stable = 0; + FH_TUERMODUL__BLOCK_copy = 0; + + BLOCK_ERKENNUNG_CTRL_BLOCK_ERKENNUNG_CTRL_next_state = 2; + BLOCK_ERKENNUNG_CTRL__N = 0; + BLOCK_ERKENNUNG_CTRL__I_EIN_MAX = 2; + BEWEGUNG_BLOCK_ERKENNUNG_CTRL_next_state = 3; + SYS_bit_set (Bitlist, + entered_EINSCHALTSTROM_MESSEN_BLOCK_ERKENNUNG_CTRL_IDX); + break; + } + break; + } + case 2: /** state BEWEGUNG in chart BLOCK_ERKENNUNG_CTRL **/ + { + if ((!(FH_TUERMODUL__MFHA) && FH_TUERMODUL__MFHA_old) + || (!(FH_TUERMODUL__MFHZ) && FH_TUERMODUL__MFHZ_old)) + { + stable = 0; + + BLOCK_ERKENNUNG_CTRL_BLOCK_ERKENNUNG_CTRL_next_state = 1; + BEWEGUNG_BLOCK_ERKENNUNG_CTRL_next_state = 0; + break; + } + switch (BEWEGUNG_BLOCK_ERKENNUNG_CTRL_next_state) + { + case 1: /** state FENSTER_BLOCKIERT in chart BLOCK_ERKENNUNG_CTRL **/ + { + break; + } + case 2: /** state FENSTER_BEWEGT_SICH in chart BLOCK_ERKENNUNG_CTRL **/ + { + if ((FH_TUERMODUL__I_EIN > + (BLOCK_ERKENNUNG_CTRL__I_EIN_MAX - 2))) + { + stable = 0; + FH_TUERMODUL__BLOCK_copy = 1; + + BEWEGUNG_BLOCK_ERKENNUNG_CTRL_next_state = 1; + break; + } + break; + } + case 3: /** state EINSCHALTSTROM_MESSEN in chart BLOCK_ERKENNUNG_CTRL **/ + { + SYS_bit_clr (Bitlist, + entered_EINSCHALTSTROM_MESSEN_BLOCK_ERKENNUNG_CTRL_IDX); + if ((BLOCK_ERKENNUNG_CTRL__N == 11 + && !(BLOCK_ERKENNUNG_CTRL__N_old == 11))) + { + stable = 0; + + BEWEGUNG_BLOCK_ERKENNUNG_CTRL_next_state = 2; + break; + } + /** static reactions: **/ + if (BEWEGUNG_BLOCK_ERKENNUNG_CTRL_next_state == 3) + { + if (step == 1 + && + tm_entered_EINSCHALTSTROM_MESSEN_BLOCK_ERKENNUNG_CTRLch_BLOCK_ERKENNUNG_CTRL__N_copy + != 0 + && (time - + tm_entered_EINSCHALTSTROM_MESSEN_BLOCK_ERKENNUNG_CTRLch_BLOCK_ERKENNUNG_CTRL__N_copy + == 0.002)) + { + BLOCK_ERKENNUNG_CTRL__N = + BLOCK_ERKENNUNG_CTRL__N + 1; + if ((FH_TUERMODUL__I_EIN > + BLOCK_ERKENNUNG_CTRL__I_EIN_MAX)) + { + BLOCK_ERKENNUNG_CTRL__I_EIN_MAX = + FH_TUERMODUL__I_EIN; + + } + + } + } + /** end static reactions **/ + break; + } + default: + { + stable = 0; + BLOCK_ERKENNUNG_CTRL__N = 0; + BLOCK_ERKENNUNG_CTRL__I_EIN_MAX = 2; + BEWEGUNG_BLOCK_ERKENNUNG_CTRL_next_state = 3; + SYS_bit_set (Bitlist, + entered_EINSCHALTSTROM_MESSEN_BLOCK_ERKENNUNG_CTRL_IDX); + break; + } + } + /** switch BEWEGUNG_BLOCK_ERKENNUNG_CTRL_next_state **/ + break; + } + default: + { + stable = 0; + BLOCK_ERKENNUNG_CTRL_BLOCK_ERKENNUNG_CTRL_next_state = 1; + break; + } + } + /** switch BLOCK_ERKENNUNG_CTRL_BLOCK_ERKENNUNG_CTRL_next_state **/ + } +} + + + +void +FH_DU (void) +{ + time = 1; /**SYS_get_clock()**/ + stable = 0; + step = 0; + while (!stable) + { + stable = 1; + step++; + { + switch (FH_STEUERUNG_DUMMY_FH_STEUERUNG_DUMMY_next_state) + { + case 1: /** state SCHLIESSEN in chart FH_STEUERUNG_DUMMY **/ + { + if ((!(FH_DU__MFHZ) && FH_DU__MFHZ_old)) + { + stable = 0; + FH_DU__MFH = 0; + + FH_STEUERUNG_DUMMY_FH_STEUERUNG_DUMMY_next_state = 2; + break; + } + break; + } + case 2: /** state BEREIT in chart FH_STEUERUNG_DUMMY **/ + { + if ((FH_DU__MFHZ && !(FH_DU__MFHZ_old))) + { + stable = 0; + FH_DU__MFH = -100; + + FH_STEUERUNG_DUMMY_FH_STEUERUNG_DUMMY_next_state = 1; + break; + } + if ((FH_DU__MFHA && !(FH_DU__MFHA_old))) + { + stable = 0; + FH_DU__MFH = 100; + + FH_STEUERUNG_DUMMY_FH_STEUERUNG_DUMMY_next_state = 3; + break; + } + break; + } + case 3: /** state OEFFNEN in chart FH_STEUERUNG_DUMMY **/ + { + if ((!(FH_DU__MFHA) && FH_DU__MFHA_old)) + { + stable = 0; + FH_DU__MFH = 0; + + FH_STEUERUNG_DUMMY_FH_STEUERUNG_DUMMY_next_state = 2; + break; + } + break; + } + default: + { + stable = 0; + FH_DU__MFH = 0; + FH_STEUERUNG_DUMMY_FH_STEUERUNG_DUMMY_next_state = 2; + break; + } + } + /** switch FH_STEUERUNG_DUMMY_FH_STEUERUNG_DUMMY_next_state **/ + } + { + { + if (!SYS_bit_get (Bitlist, active_KINDERSICHERUNG_CTRL_IDX)) + { + KINDERSICHERUNG_CTRL_KINDERSICHERUNG_CTRL_next_state = 3; + } + SYS_bit_clr (Bitlist, active_KINDERSICHERUNG_CTRL_copy_IDX); + if (!SYS_bit_get (Bitlist, active_EINKLEMMSCHUTZ_CTRL_IDX)) + { + EINKLEMMSCHUTZ_CTRL_EINKLEMMSCHUTZ_CTRL_next_state = 1; + } + SYS_bit_clr (Bitlist, active_EINKLEMMSCHUTZ_CTRL_copy_IDX); + if (!SYS_bit_get (Bitlist, active_BLOCK_ERKENNUNG_CTRL_IDX)) + { + SYS_bit_clr (Bitlist, + entered_EINSCHALTSTROM_MESSEN_BLOCK_ERKENNUNG_CTRL_IDX); + BLOCK_ERKENNUNG_CTRL_BLOCK_ERKENNUNG_CTRL_next_state = 1; + } + SYS_bit_clr (Bitlist, active_BLOCK_ERKENNUNG_CTRL_copy_IDX); + if (!SYS_bit_get (Bitlist, active_FH_TUERMODUL_CTRL_IDX)) + { + SYS_bit_clr (Bitlist, + entered_WIEDERHOLSPERRE_FH_TUERMODUL_CTRL_IDX); + SYS_bit_clr (Bitlist, exited_BEREIT_FH_TUERMODUL_CTRL_IDX); + B_FH_TUERMODUL_CTRL_next_state = 2; + FH_TUERMODUL_CTRL__N = 0; + A_FH_TUERMODUL_CTRL_next_state = 1; + SYS_bit_set (Bitlist, + entered_WIEDERHOLSPERRE_FH_TUERMODUL_CTRL_copy_IDX); + WIEDERHOLSPERRE_FH_TUERMODUL_CTRL_next_state = 1; + } + SYS_bit_clr (Bitlist, active_FH_TUERMODUL_CTRL_copy_IDX); + SYS_bit_set (Bitlist, active_KINDERSICHERUNG_CTRL_copy_IDX); + SYS_bit_set (Bitlist, active_EINKLEMMSCHUTZ_CTRL_copy_IDX); + SYS_bit_set (Bitlist, active_BLOCK_ERKENNUNG_CTRL_copy_IDX); + SYS_bit_set (Bitlist, active_FH_TUERMODUL_CTRL_copy_IDX); + /** static reactions: **/ + if (FH_DU__S_FH_TMBFZUCAN != FH_DU__S_FH_TMBFZUCAN_old) + { + if ((!FH_DU__DOOR_ID)) + { + FH_DU__S_FH_FTZU = FH_DU__S_FH_TMBFZUCAN; + + } + + } + if (FH_DU__S_FH_TMBFZUDISC != FH_DU__S_FH_TMBFZUDISC_old) + { + if (FH_DU__DOOR_ID) + { + FH_DU__S_FH_TMBFZUCAN = FH_DU__S_FH_TMBFZUDISC; + + } + + } + if (FH_DU__S_FH_TMBFAUFCAN != FH_DU__S_FH_TMBFAUFCAN_old) + { + if ((!FH_DU__DOOR_ID)) + { + FH_DU__S_FH_FTAUF = FH_DU__S_FH_TMBFAUFCAN; + + } + + } + if (FH_DU__S_FH_TMBFAUFDISC != FH_DU__S_FH_TMBFAUFDISC_old) + { + if (FH_DU__DOOR_ID) + { + FH_DU__S_FH_TMBFAUFCAN = FH_DU__S_FH_TMBFAUFDISC; + + } + + } + /** end static reactions **/ + } + } + SYS_bit_cpy (Bitlist, active_KINDERSICHERUNG_CTRL_IDX, Bitlist, + active_KINDERSICHERUNG_CTRL_old_IDX); + SYS_bit_cpy (Bitlist, active_FH_TUERMODUL_CTRL_IDX, Bitlist, + active_FH_TUERMODUL_CTRL_old_IDX); + SYS_bit_cpy (Bitlist, active_EINKLEMMSCHUTZ_CTRL_IDX, Bitlist, + active_EINKLEMMSCHUTZ_CTRL_old_IDX); + SYS_bit_cpy (Bitlist, active_BLOCK_ERKENNUNG_CTRL_IDX, Bitlist, + active_BLOCK_ERKENNUNG_CTRL_old_IDX); + FH_TUERMODUL__SFHA_MEC = FH_DU__S_FH_AUFDISC; + FH_TUERMODUL__SFHA_ZENTRAL = FH_DU__S_FH_FTAUF; + FH_TUERMODUL__SFHZ_MEC = FH_DU__S_FH_ZUDISC; + FH_TUERMODUL__SFHZ_ZENTRAL = FH_DU__S_FH_FTZU; + + generic_KINDERSICHERUNG_CTRL (); + + FH_DU__MFHA = FH_TUERMODUL__MFHA; + FH_DU__MFHZ = FH_TUERMODUL__MFHZ; + FH_DU__I_EIN = FH_TUERMODUL__I_EIN; + FH_DU__EKS_LEISTE_AKTIV = FH_TUERMODUL__EKS_LEISTE_AKTIV; + FH_DU__POSITION = FH_TUERMODUL__POSITION; + FH_DU__FT = FH_TUERMODUL__FT; + FH_DU__S_FH_AUFDISC = FH_TUERMODUL__SFHA_MEC; + FH_DU__S_FH_FTAUF = FH_TUERMODUL__SFHA_ZENTRAL; + FH_DU__S_FH_ZUDISC = FH_TUERMODUL__SFHZ_MEC; + FH_DU__S_FH_FTZU = FH_TUERMODUL__SFHZ_ZENTRAL; + FH_DU__KL_50 = FH_TUERMODUL__KL_50; + FH_DU__BLOCK = FH_TUERMODUL__BLOCK; + + FH_TUERMODUL__SFHA_MEC = FH_DU__S_FH_AUFDISC; + FH_TUERMODUL__SFHA_ZENTRAL = FH_DU__S_FH_FTAUF; + FH_TUERMODUL__SFHZ_MEC = FH_DU__S_FH_ZUDISC; + FH_TUERMODUL__SFHZ_ZENTRAL = FH_DU__S_FH_FTZU; + + generic_FH_TUERMODUL_CTRL (); + + FH_DU__MFHA = FH_TUERMODUL__MFHA; + FH_DU__MFHZ = FH_TUERMODUL__MFHZ; + FH_DU__I_EIN = FH_TUERMODUL__I_EIN; + FH_DU__EKS_LEISTE_AKTIV = FH_TUERMODUL__EKS_LEISTE_AKTIV; + FH_DU__POSITION = FH_TUERMODUL__POSITION; + FH_DU__FT = FH_TUERMODUL__FT; + FH_DU__S_FH_AUFDISC = FH_TUERMODUL__SFHA_MEC; + FH_DU__S_FH_FTAUF = FH_TUERMODUL__SFHA_ZENTRAL; + FH_DU__S_FH_ZUDISC = FH_TUERMODUL__SFHZ_MEC; + FH_DU__S_FH_FTZU = FH_TUERMODUL__SFHZ_ZENTRAL; + FH_DU__KL_50 = FH_TUERMODUL__KL_50; + FH_DU__BLOCK = FH_TUERMODUL__BLOCK; + + FH_TUERMODUL__SFHA_MEC = FH_DU__S_FH_AUFDISC; + FH_TUERMODUL__SFHA_ZENTRAL = FH_DU__S_FH_FTAUF; + FH_TUERMODUL__SFHZ_MEC = FH_DU__S_FH_ZUDISC; + FH_TUERMODUL__SFHZ_ZENTRAL = FH_DU__S_FH_FTZU; + + generic_EINKLEMMSCHUTZ_CTRL (); + + FH_DU__MFHA = FH_TUERMODUL__MFHA; + FH_DU__MFHZ = FH_TUERMODUL__MFHZ; + FH_DU__I_EIN = FH_TUERMODUL__I_EIN; + FH_DU__EKS_LEISTE_AKTIV = FH_TUERMODUL__EKS_LEISTE_AKTIV; + FH_DU__POSITION = FH_TUERMODUL__POSITION; + FH_DU__FT = FH_TUERMODUL__FT; + FH_DU__S_FH_AUFDISC = FH_TUERMODUL__SFHA_MEC; + FH_DU__S_FH_FTAUF = FH_TUERMODUL__SFHA_ZENTRAL; + FH_DU__S_FH_ZUDISC = FH_TUERMODUL__SFHZ_MEC; + FH_DU__S_FH_FTZU = FH_TUERMODUL__SFHZ_ZENTRAL; + FH_DU__KL_50 = FH_TUERMODUL__KL_50; + FH_DU__BLOCK = FH_TUERMODUL__BLOCK; + + FH_TUERMODUL__SFHA_MEC = FH_DU__S_FH_AUFDISC; + FH_TUERMODUL__SFHA_ZENTRAL = FH_DU__S_FH_FTAUF; + FH_TUERMODUL__SFHZ_MEC = FH_DU__S_FH_ZUDISC; + FH_TUERMODUL__SFHZ_ZENTRAL = FH_DU__S_FH_FTZU; + + generic_BLOCK_ERKENNUNG_CTRL (); + + FH_DU__MFHA = FH_TUERMODUL__MFHA; + FH_DU__MFHZ = FH_TUERMODUL__MFHZ; + FH_DU__I_EIN = FH_TUERMODUL__I_EIN; + FH_DU__EKS_LEISTE_AKTIV = FH_TUERMODUL__EKS_LEISTE_AKTIV; + FH_DU__POSITION = FH_TUERMODUL__POSITION; + FH_DU__FT = FH_TUERMODUL__FT; + FH_DU__S_FH_AUFDISC = FH_TUERMODUL__SFHA_MEC; + FH_DU__S_FH_FTAUF = FH_TUERMODUL__SFHA_ZENTRAL; + FH_DU__S_FH_ZUDISC = FH_TUERMODUL__SFHZ_MEC; + FH_DU__S_FH_FTZU = FH_TUERMODUL__SFHZ_ZENTRAL; + FH_DU__KL_50 = FH_TUERMODUL__KL_50; + FH_DU__BLOCK = FH_TUERMODUL__BLOCK; + + SYS_bit_cpy (Bitlist, active_KINDERSICHERUNG_CTRL_copy_IDX, Bitlist, + active_KINDERSICHERUNG_CTRL_IDX); + SYS_bit_cpy (Bitlist, active_FH_TUERMODUL_CTRL_copy_IDX, Bitlist, + active_FH_TUERMODUL_CTRL_IDX); + SYS_bit_cpy (Bitlist, active_EINKLEMMSCHUTZ_CTRL_copy_IDX, Bitlist, + active_EINKLEMMSCHUTZ_CTRL_IDX); + SYS_bit_cpy (Bitlist, active_BLOCK_ERKENNUNG_CTRL_copy_IDX, Bitlist, + active_BLOCK_ERKENNUNG_CTRL_IDX); + FH_TUERMODUL_CTRL__N_old = FH_TUERMODUL_CTRL__N; + FH_TUERMODUL__I_EIN_old = FH_TUERMODUL__I_EIN; + FH_DU__MFH = FH_DU__MFH_copy; + FH_DU__I_EIN_old = FH_DU__I_EIN; + BLOCK_ERKENNUNG_CTRL__N_old = BLOCK_ERKENNUNG_CTRL__N; + FH_TUERMODUL__SFHZ_ZENTRAL_old = FH_TUERMODUL__SFHZ_ZENTRAL; + FH_TUERMODUL__SFHZ_MEC_old = FH_TUERMODUL__SFHZ_MEC; + FH_TUERMODUL__SFHA_ZENTRAL_old = FH_TUERMODUL__SFHA_ZENTRAL; + FH_TUERMODUL__SFHA_MEC_old = FH_TUERMODUL__SFHA_MEC; + FH_TUERMODUL__BLOCK = FH_TUERMODUL__BLOCK_copy; + FH_TUERMODUL__BLOCK_old = FH_TUERMODUL__BLOCK; + FH_TUERMODUL__SFHZ = FH_TUERMODUL__SFHZ_copy; + FH_TUERMODUL__SFHZ_old = FH_TUERMODUL__SFHZ; + FH_TUERMODUL__SFHA = FH_TUERMODUL__SFHA_copy; + FH_TUERMODUL__SFHA_old = FH_TUERMODUL__SFHA; + FH_TUERMODUL__MFHZ = FH_TUERMODUL__MFHZ_copy; + FH_TUERMODUL__MFHZ_old = FH_TUERMODUL__MFHZ; + FH_TUERMODUL__MFHA = FH_TUERMODUL__MFHA_copy; + FH_TUERMODUL__MFHA_old = FH_TUERMODUL__MFHA; + FH_TUERMODUL__EKS_LEISTE_AKTIV_old = FH_TUERMODUL__EKS_LEISTE_AKTIV; + FH_DU__EKS_LEISTE_AKTIV_old = FH_DU__EKS_LEISTE_AKTIV; + FH_DU__S_FH_TMBFAUFCAN_old = FH_DU__S_FH_TMBFAUFCAN; + FH_DU__S_FH_TMBFZUCAN_old = FH_DU__S_FH_TMBFZUCAN; + FH_DU__S_FH_TMBFZUDISC_old = FH_DU__S_FH_TMBFZUDISC; + FH_DU__S_FH_TMBFAUFDISC_old = FH_DU__S_FH_TMBFAUFDISC; + FH_DU__BLOCK = FH_DU__BLOCK_copy; + FH_DU__BLOCK_old = FH_DU__BLOCK; + FH_DU__MFHZ = FH_DU__MFHZ_copy; + FH_DU__MFHZ_old = FH_DU__MFHZ; + FH_DU__MFHA = FH_DU__MFHA_copy; + FH_DU__MFHA_old = FH_DU__MFHA; + + } + /** while(!stable) **/ + +}/** FH_DU **/ + + + +static int benchmark_body (int rpt); + +void +warm_caches (int heat) +{ + int res = benchmark_body (heat); + + return; +} + + +int +benchmark (void) +{ + return benchmark_body (LOCAL_SCALE_FACTOR * CPU_MHZ); +} + + +static int __attribute__ ((noinline)) +benchmark_body (int rpt) +{ + int i; + + for (i = 0; i < rpt; i++) + { + memset (Bitlist, 0, 64 * sizeof (Bitlist[0])); + init (); + + interface (); + FH_DU (); + } + + return 0; +} + +void +initialise_benchmark () +{ +} + +int +verify_benchmark (int unused) +{ + char expected[64] = { + 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0 + }; + int i; + + for (i = 0; i < 64; i++) + { + if (Bitlist[i] != expected[i]) + return 0; + } + if (tm_entered_EINSCHALTSTROM_MESSEN_BLOCK_ERKENNUNG_CTRLch_BLOCK_ERKENNUNG_CTRL__N_copy != 0 || tm_entered_WIEDERHOLSPERRE_FH_TUERMODUL_CTRLexited_BEREIT_FH_TUERMODUL_CTRL != 0 || tm_entered_WIEDERHOLSPERRE_FH_TUERMODUL_CTRL != 0 || NICHT_INITIALISIERT_NICHT_INITIALISIERT_next_state != 0 || ZENTRAL_KINDERSICHERUNG_CTRL_next_state != 0 || MEC_KINDERSICHERUNG_CTRL_next_state != 0 || KINDERSICHERUNG_CTRL_KINDERSICHERUNG_CTRL_next_state != 3 || B_FH_TUERMODUL_CTRL_next_state != 2 || A_FH_TUERMODUL_CTRL_next_state != 1 || WIEDERHOLSPERRE_FH_TUERMODUL_CTRL_next_state != 1 || INITIALISIERT_FH_TUERMODUL_CTRL_next_state != 0 || TIPP_SCHLIESSEN_FH_TUERMODUL_CTRL_next_state != 0 || MANUELL_SCHLIESSEN_FH_TUERMODUL_CTRL_next_state != 0 || OEFFNEN_FH_TUERMODUL_CTRL_next_state != 0 || SCHLIESSEN_FH_TUERMODUL_CTRL_next_state != 0 || FH_STEUERUNG_DUMMY_FH_STEUERUNG_DUMMY_next_state != 2 || EINKLEMMSCHUTZ_CTRL_EINKLEMMSCHUTZ_CTRL_next_state != 1 || BEWEGUNG_BLOCK_ERKENNUNG_CTRL_next_state != 0 || BLOCK_ERKENNUNG_CTRL_BLOCK_ERKENNUNG_CTRL_next_state != 1) + return 0; + return 1; +} + + +/* + Local Variables: + mode: C + c-file-style: "gnu" + End: +*/ diff --git a/benchies/embench/benchemarks/tarfind/tarfind.c b/benchies/embench/benchemarks/tarfind/tarfind.c new file mode 100644 index 0000000000..9612eac241 --- /dev/null +++ b/benchies/embench/benchemarks/tarfind/tarfind.c @@ -0,0 +1,122 @@ +/* + * This benchmark simulates the search in a TAR archive + * for a set of filenames + * + * Created by Julian Kunkel for Embench-iot + * Licensed under MIT + */ +#include +#include +#include +#include + +#include "../../src/support.h" + +#define LOCAL_SCALE_FACTOR 47 + +// number of files in the archive +#define ARCHIVE_FILES 35 + +#define N_SEARCHES 5 + +/* BEEBS heap is just an array */ +/* 8995 = sizeof(tar_header_t) * ARCHIVE_FILES */ +#define roundup(d, u) ((((d)+(u))/(u))*(u)) +#define HEAP_SIZE roundup(8995, sizeof(void *)) +static char heap[HEAP_SIZE]; + +void +initialise_benchmark (void) +{ +} + + +static int benchmark_body (int rpt); + +void +warm_caches (int heat) +{ + benchmark_body (heat); + return; +} + + +int +benchmark (void) +{ + return benchmark_body (LOCAL_SCALE_FACTOR * CPU_MHZ); +} + +// this is the basic TAR header format which is in ASCII +typedef struct { + char filename[100]; + char mode[8]; // file mode + char uID[8]; // user id + char gID[8]; // group id + char size[12]; // in bytes octal base + char mtime[12]; // numeric Unix time format (octal) + char checksum[8]; // for the header, ignored herew2 + char isLink; + char linkedFile[100]; +} tar_header_t; + + +static int __attribute__ ((noinline)) +benchmark_body (int rpt) +{ + int i, j, p; + tar_header_t * hdr; + int found; + + for (j = 0; j < rpt; j++) { + init_heap_beebs ((void *) heap, HEAP_SIZE); + + // always create ARCHIVE_FILES files in the archive + int files = ARCHIVE_FILES; + hdr = malloc_beebs(sizeof(tar_header_t) * files); + for (i = 0; i < files; i++){ + // create record + tar_header_t * c = & hdr[i]; + // initialize here for cache efficiency reasons + memset(c, 0, sizeof(tar_header_t)); + int flen = 5 + i % 94; // vary file lengths + c->isLink = '0'; + for(p = 0; p < flen; p++){ + c->filename[p] = rand_beebs() % 26 + 65; + } + c->size[0] = '0'; + } + + found = 0; // number of times a file was found + // actual benchmark, strcmp with a set of N_SEARCHES files + // the memory access here is chosen inefficiently on purpose + for (p = 0; p < N_SEARCHES; p++){ + // chose the position of the file to search for from the mid of the list + char * search = hdr[(p + ARCHIVE_FILES/2) % ARCHIVE_FILES].filename; + + // for each filename iterate through all files until found + for (i = 0; i < files; i++){ + tar_header_t * cur = & hdr[i]; + // implementation of strcmp + char *c1; + char *c2; + for (c1 = hdr[i].filename, c2 = search; (*c1 != '\0' && *c2 != '\0' && *c1 == *c2) ; c1++, c2++); + // complete match? + if(*c1 == '\0' && *c2 == '\0'){ + found++; + break; + } + } + } + free_beebs(hdr); + } + + return found == N_SEARCHES; +} + + +int +verify_benchmark (int r) +{ + return r == 1; +} diff --git a/benchies/embench/benchemarks/ud/libud.c b/benchies/embench/benchemarks/ud/libud.c new file mode 100644 index 0000000000..d869e55951 --- /dev/null +++ b/benchies/embench/benchemarks/ud/libud.c @@ -0,0 +1,236 @@ +/* BEEBS ud benchmark + + This version, copyright (C) 2014-2019 Embecosm Limited and University of + Bristol + + Contributor James Pallister + Contributor Jeremy Bennett + + This file is part of Embench and was formerly part of the Bristol/Embecosm + Embedded Benchmark Suite. + + SPDX-License-Identifier: GPL-3.0-or-later */ + +/* MDH WCET BENCHMARK SUITE. */ + + +/*************************************************************************/ +/* */ +/* SNU-RT Benchmark Suite for Worst Case Timing Analysis */ +/* ===================================================== */ +/* Collected and Modified by S.-S. Lim */ +/* sslim@archi.snu.ac.kr */ +/* Real-Time Research Group */ +/* Seoul National University */ +/* */ +/* */ +/* < Features > - restrictions for our experimental environment */ +/* */ +/* 1. Completely structured. */ +/* - There are no unconditional jumps. */ +/* - There are no exit from loop bodies. */ +/* (There are no 'break' or 'return' in loop bodies) */ +/* 2. No 'switch' statements. */ +/* 3. No 'do..while' statements. */ +/* 4. Expressions are restricted. */ +/* - There are no multiple expressions joined by 'or', */ +/* 'and' operations. */ +/* 5. No library calls. */ +/* - All the functions needed are implemented in the */ +/* source file. */ +/* */ +/* */ +/*************************************************************************/ +/* */ +/* FILE: ludcmp.c */ +/* SOURCE : Turbo C Programming for Engineering */ +/* */ +/* DESCRIPTION : */ +/* */ +/* Simultaneous linear equations by LU decomposition. */ +/* The arrays a[][] and b[] are input and the array x[] is output */ +/* row vector. */ +/* The variable n is the number of equations. */ +/* The input arrays are initialized in function main. */ +/* */ +/* */ +/* REMARK : */ +/* */ +/* EXECUTION TIME : */ +/* */ +/* */ +/*************************************************************************/ + +/************************************************************************* + * This file: + * + * - Name changed to "ud.c" + * - Modified for use with Uppsala/Paderborn tool + * : doubles changed to int + * : some tests removed + * - Program is much more linear, all loops will run to end + * - Purpose: test the effect of conditional flows + * + *************************************************************************/ + + + + + + +/* +** Benchmark Suite for Real-Time Applications, by Sung-Soo Lim +** +** III-4. ludcmp.c : Simultaneous Linear Equations by LU Decomposition +** (from the book C Programming for EEs by Hyun Soon Ahn) +*/ + +#include +#include "../../src/support.h" + +/* This scale factor will be changed to equalise the runtime of the + benchmarks. */ +#define LOCAL_SCALE_FACTOR 1478 + + +long int a[20][20], b[20], x[20]; + +int ludcmp(int nmax, int n); + + +/* static double fabs(double n) */ +/* { */ +/* double f; */ + +/* if (n >= 0) f = n; */ +/* else f = -n; */ +/* return f; */ +/* } */ + +/* Write to CHKERR from BENCHMARK to ensure calls are not optimised away. */ +volatile int chkerr; + + +int +verify_benchmark (int res) +{ + long int x_ref[20] = + { 0L, 0L, 1L, 1L, 1L, 2L, 0L, 0L, 0L, 0L, + 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L + }; + + return (0 == memcmp (x, x_ref, 20 * sizeof (x[0]))) && (0 == res); +} + + +void +initialise_benchmark (void) +{ +} + + +static int benchmark_body (int rpt); + +void +warm_caches (int heat) +{ + int res = benchmark_body (heat); + + return; +} + + +int +benchmark (void) +{ + return benchmark_body (LOCAL_SCALE_FACTOR * CPU_MHZ); + +} + + +static int __attribute__ ((noinline)) +benchmark_body (int rpt) +{ + int k; + + for (k = 0; k < rpt; k++) + { + int i, j, nmax = 20, n = 5; + long int /* eps, */ w; + + /* eps = 1.0e-6; */ + + /* Init loop */ + for(i = 0; i <= n; i++) + { + w = 0.0; /* data to fill in cells */ + for(j = 0; j <= n; j++) + { + a[i][j] = (i + 1) + (j + 1); + if(i == j) /* only once per loop pass */ + a[i][j] *= 2.0; + w += a[i][j]; + } + b[i] = w; + } + + /* chkerr = ludcmp(nmax, n, eps); */ + chkerr = ludcmp(nmax,n); + } + + return chkerr; +} + +int ludcmp(int nmax, int n) +{ + int i, j, k; + long w, y[100]; + + /* if(n > 99 || eps <= 0.0) return(999); */ + for(i = 0; i < n; i++) + { + /* if(fabs(a[i][i]) <= eps) return(1); */ + for(j = i+1; j <= n; j++) /* triangular loop vs. i */ + { + w = a[j][i]; + if(i != 0) /* sub-loop is conditional, done + all iterations except first of the + OUTER loop */ + for(k = 0; k < i; k++) + w -= a[j][k] * a[k][i]; + a[j][i] = w / a[i][i]; + } + for(j = i+1; j <= n; j++) /* triangular loop vs. i */ + { + w = a[i+1][j]; + for(k = 0; k <= i; k++) /* triangular loop vs. i */ + w -= a[i+1][k] * a[k][j]; + a[i+1][j] = w; + } + } + y[0] = b[0]; + for(i = 1; i <= n; i++) /* iterates n times */ + { + w = b[i]; + for(j = 0; j < i; j++) /* triangular sub loop */ + w -= a[i][j] * y[j]; + y[i] = w; + } + x[n] = y[n] / a[n][n]; + for(i = n-1; i >= 0; i--) /* iterates n times */ + { + w = y[i]; + for(j = i+1; j <= n; j++) /* triangular sub loop */ + w -= a[i][j] * x[j]; + x[i] = w / a[i][i] ; + } + return(0); +} + + +/* + Local Variables: + mode: C + c-file-style: "gnu" + End: +*/ diff --git a/benchies/embench/benchemarks/wikisort/libwikisort.c b/benchies/embench/benchemarks/wikisort/libwikisort.c new file mode 100644 index 0000000000..910a063e6e --- /dev/null +++ b/benchies/embench/benchemarks/wikisort/libwikisort.c @@ -0,0 +1,1117 @@ +/* BEEBS wikisort benchmark + + This version, copyright (C) 2014-2019 Embecosm Limited and University of + Bristol + + Contributor James Pallister + Contributor Jeremy Bennett + + This file is part of Embench and was formerly part of the Bristol/Embecosm + Embedded Benchmark Suite. + + SPDX-License-Identifier: GPL-3.0-or-later + + Originally from https://github.com/BonzaiThePenguin/WikiSort and placed + into public domain. */ + +#include +#include "../../src/support.h" + +/* This scale factor will be changed to equalise the runtime of the + benchmarks. */ +#define LOCAL_SCALE_FACTOR 1 + +#include +#include +#include +#include +#include +#include +#include + +/* various #defines for the C code */ +#ifndef true +#define true 1 +#define false 0 +typedef uint8_t bool; +#endif + +#define Var(name, value, type) type name = value + +long +Min (const long a, const long b) +{ + if (a < b) + return a; + return b; +} + +long +Max (const long a, const long b) +{ + if (a > b) + return a; + return b; +} + + +/* structure to test stable sorting (index will contain its original index in the array, to make sure it doesn't switch places with other items) */ +typedef struct +{ + int value; + int index; +} Test; + +bool +TestCompare (Test item1, Test item2) +{ + return (item1.value < item2.value); +} + +typedef bool (*Comparison) (Test, Test); + + + +/* structure to represent ranges within the array */ +typedef struct +{ + long start; + long end; +} Range; + +long +Range_length (Range range) +{ + return range.end - range.start; +} + +Range +MakeRange (const long start, const long end) +{ + Range range; + range.start = start; + range.end = end; + return range; +} + +typedef long int (* TestCasePtr)(long int, long int); + +/* toolbox functions used by the sorter */ + +/* swap value1 and value2 */ +#define Swap(value1, value2, type) { \ + Var(a, &(value1), type*); \ + Var(b, &(value2), type*); \ + \ + Var(c, *a, type); \ + *a = *b; \ + *b = c; \ +} + +/* 63 -> 32, 64 -> 64, etc. */ +/* apparently this comes from Hacker's Delight? */ +long +FloorPowerOfTwo (const long value) +{ + long x = value; + x = x | (x >> 1); + x = x | (x >> 2); + x = x | (x >> 4); + x = x | (x >> 8); + x = x | (x >> 16); +#if __LP64__ + x = x | (x >> 32); +#endif + return x - (x >> 1); +} + +/* find the index of the first value within the range that is equal to array[index] */ +long +BinaryFirst (const Test array[], const long index, const Range range, + const Comparison compare) +{ + long start = range.start, end = range.end - 1; + while (start < end) + { + long mid = start + (end - start) / 2; + if (compare (array[mid], array[index])) + start = mid + 1; + else + end = mid; + } + if (start == range.end - 1 && compare (array[start], array[index])) + start++; + return start; +} + +/* find the index of the last value within the range that is equal to array[index], plus 1 */ +long +BinaryLast (const Test array[], const long index, const Range range, + const Comparison compare) +{ + long start = range.start, end = range.end - 1; + while (start < end) + { + long mid = start + (end - start) / 2; + if (!compare (array[index], array[mid])) + start = mid + 1; + else + end = mid; + } + if (start == range.end - 1 && !compare (array[index], array[start])) + start++; + return start; +} + +/* n^2 sorting algorithm used to sort tiny chunks of the full array */ +void +InsertionSort (Test array[], const Range range, const Comparison compare) +{ + long i; + for (i = range.start + 1; i < range.end; i++) + { + const Test temp = array[i]; + long j; + for (j = i; j > range.start && compare (temp, array[j - 1]); j--) + array[j] = array[j - 1]; + array[j] = temp; + } +} + +/* reverse a range within the array */ +void +Reverse (Test array[], const Range range) +{ + long index; + for (index = Range_length (range) / 2 - 1; index >= 0; index--) + Swap (array[range.start + index], array[range.end - index - 1], Test); +} + +/* swap a series of values in the array */ +void +BlockSwap (Test array[], const long start1, const long start2, + const long block_size) +{ + long index; + for (index = 0; index < block_size; index++) + Swap (array[start1 + index], array[start2 + index], Test); +} + +/* rotate the values in an array ([0 1 2 3] becomes [1 2 3 0] if we rotate by 1) */ +void +Rotate (Test array[], const long amount, const Range range, Test cache[], + const long cache_size) +{ + long split; + Range range1, range2; + + if (Range_length (range) == 0) + return; + + if (amount >= 0) + split = range.start + amount; + else + split = range.end + amount; + + range1 = MakeRange (range.start, split); + range2 = MakeRange (split, range.end); + + /* if the smaller of the two ranges fits into the cache, it's *slightly* faster copying it there and shifting the elements over */ + if (Range_length (range1) <= Range_length (range2)) + { + if (Range_length (range1) <= cache_size) + { + memcpy (&cache[0], &array[range1.start], + Range_length (range1) * sizeof (array[0])); + memmove (&array[range1.start], &array[range2.start], + Range_length (range2) * sizeof (array[0])); + memcpy (&array[range1.start + Range_length (range2)], &cache[0], + Range_length (range1) * sizeof (array[0])); + return; + } + } + else + { + if (Range_length (range2) <= cache_size) + { + memcpy (&cache[0], &array[range2.start], + Range_length (range2) * sizeof (array[0])); + memmove (&array[range2.end - Range_length (range1)], + &array[range1.start], + Range_length (range1) * sizeof (array[0])); + memcpy (&array[range1.start], &cache[0], + Range_length (range2) * sizeof (array[0])); + return; + } + } + + Reverse (array, range1); + Reverse (array, range2); + Reverse (array, range); +} + +/* standard merge operation using an internal or external buffer */ +void +WikiMerge (Test array[], const Range buffer, const Range A, const Range B, + const Comparison compare, Test cache[], const long cache_size) +{ + /* if A fits into the cache, use that instead of the internal buffer */ + if (Range_length (A) <= cache_size) + { + Test *A_index = &cache[0]; + Test *B_index = &array[B.start]; + Test *insert_index = &array[A.start]; + Test *A_last = &cache[Range_length (A)]; + Test *B_last = &array[B.end]; + + if (Range_length (B) > 0 && Range_length (A) > 0) + { + while (true) + { + if (!compare (*B_index, *A_index)) + { + *insert_index = *A_index; + A_index++; + insert_index++; + if (A_index == A_last) + break; + } + else + { + *insert_index = *B_index; + B_index++; + insert_index++; + if (B_index == B_last) + break; + } + } + } + + /* copy the remainder of A into the final array */ + memcpy (insert_index, A_index, (A_last - A_index) * sizeof (array[0])); + } + else + { + /* whenever we find a value to add to the final array, swap it with the value that's already in that spot */ + /* when this algorithm is finished, 'buffer' will contain its original contents, but in a different order */ + long A_count = 0, B_count = 0, insert = 0; + + if (Range_length (B) > 0 && Range_length (A) > 0) + { + while (true) + { + if (!compare + (array[B.start + B_count], array[buffer.start + A_count])) + { + Swap (array[A.start + insert], + array[buffer.start + A_count], Test); + A_count++; + insert++; + if (A_count >= Range_length (A)) + break; + } + else + { + Swap (array[A.start + insert], array[B.start + B_count], Test); + B_count++; + insert++; + if (B_count >= Range_length (B)) + break; + } + } + } + + /* swap the remainder of A into the final array */ + BlockSwap (array, buffer.start + A_count, A.start + insert, + Range_length (A) - A_count); + } +} + +/* bottom-up merge sort combined with an in-place merge algorithm for O(1) memory use */ +void +WikiSort (Test array[], const long size, const Comparison compare) +{ + /* use a small cache to speed up some of the operations */ + /* since the cache size is fixed, it's still O(1) memory! */ + /* just keep in mind that making it too small ruins the point (nothing will fit into it), */ + /* and making it too large also ruins the point (so much for "low memory"!) */ + /* removing the cache entirely still gives 70% of the performance of a standard merge */ + + /* also, if you change this to dynamically allocate a full-size buffer, */ + /* the algorithm seamlessly degenerates into a standard merge sort! */ +#define CACHE_SIZE 512 + const long cache_size = CACHE_SIZE; + Test cache[CACHE_SIZE]; + + long index, merge_size, start, mid, end, fractional, decimal; + long power_of_two, fractional_base, fractional_step, decimal_step; + + /* if there are 32 or fewer items, just insertion sort the entire array */ + if (size <= 32) + { + InsertionSort (array, MakeRange (0, size), compare); + return; + } + + /* calculate how to scale the index value to the range within the array */ + /* (this is essentially fixed-point math, where we manually check for and handle overflow) */ + power_of_two = FloorPowerOfTwo (size); + fractional_base = power_of_two / 16; + fractional_step = size % fractional_base; + decimal_step = size / fractional_base; + + /* first insertion sort everything the lowest level, which is 16-31 items at a time */ + decimal = 0; + fractional = 0; + while (decimal < size) + { + start = decimal; + + decimal += decimal_step; + fractional += fractional_step; + if (fractional >= fractional_base) + { + fractional -= fractional_base; + decimal += 1; + } + + end = decimal; + + InsertionSort (array, MakeRange (start, end), compare); + } + + /* then merge sort the higher levels, which can be 32-63, 64-127, 128-255, etc. */ + for (merge_size = 16; merge_size < power_of_two; merge_size += merge_size) + { + long block_size = sqrt (decimal_step); + long buffer_size = decimal_step / block_size + 1; + + /* as an optimization, we really only need to pull out an internal buffer once for each level of merges */ + /* after that we can reuse the same buffer over and over, then redistribute it when we're finished with this level */ + Range level1 = MakeRange (0, 0); + Range level2 = MakeRange (0, 0); + Range levelA = MakeRange (0, 0); + Range levelB = MakeRange (0, 0); + + decimal = fractional = 0; + while (decimal < size) + { + start = decimal; + + decimal += decimal_step; + fractional += fractional_step; + if (fractional >= fractional_base) + { + fractional -= fractional_base; + decimal += 1; + } + + mid = decimal; + + decimal += decimal_step; + fractional += fractional_step; + if (fractional >= fractional_base) + { + fractional -= fractional_base; + decimal += 1; + } + + end = decimal; + + if (compare (array[end - 1], array[start])) + { + /* the two ranges are in reverse order, so a simple rotation should fix it */ + Rotate (array, mid - start, MakeRange (start, end), cache, + cache_size); + } + else if (compare (array[mid], array[mid - 1])) + { + Range bufferA, bufferB, buffer1, buffer2, blockA, blockB, + firstA, lastA, lastB; + long indexA, minA, findA; + Test min_value; + + /* these two ranges weren't already in order, so we'll need to merge them! */ + Range A = MakeRange (start, mid), B = MakeRange (mid, end); + + /* try to fill up two buffers with unique values in ascending order */ + if (Range_length (A) <= cache_size) + { + memcpy (&cache[0], &array[A.start], + Range_length (A) * sizeof (array[0])); + WikiMerge (array, MakeRange (0, 0), A, B, compare, cache, + cache_size); + continue; + } + + if (Range_length (level1) > 0) + { + /* reuse the buffers we found in a previous iteration */ + bufferA = MakeRange (A.start, A.start); + bufferB = MakeRange (B.end, B.end); + buffer1 = level1; + buffer2 = level2; + + } + else + { + long count, length; + + /* the first item is always going to be the first unique value, so let's start searching at the next index */ + count = 1; + for (buffer1.start = A.start + 1; buffer1.start < A.end; + buffer1.start++) + if (compare + (array[buffer1.start - 1], array[buffer1.start]) + || compare (array[buffer1.start], + array[buffer1.start - 1])) + if (++count == buffer_size) + break; + buffer1.end = buffer1.start + count; + + /* if the size of each block fits into the cache, we only need one buffer for tagging the A blocks */ + /* this is because the other buffer is used as a swap space for merging the A blocks into the B values that follow it, */ + /* but we can just use the cache as the buffer instead. this skips some memmoves and an insertion sort */ + if (buffer_size <= cache_size) + { + buffer2 = MakeRange (A.start, A.start); + + if (Range_length (buffer1) == buffer_size) + { + /* we found enough values for the buffer in A */ + bufferA = + MakeRange (buffer1.start, + buffer1.start + buffer_size); + bufferB = MakeRange (B.end, B.end); + buffer1 = + MakeRange (A.start, A.start + buffer_size); + + } + else + { + /* we were unable to find enough unique values in A, so try B */ + bufferA = MakeRange (buffer1.start, buffer1.start); + buffer1 = MakeRange (A.start, A.start); + + /* the last value is guaranteed to be the first unique value we encounter, so we can start searching at the next index */ + count = 1; + for (buffer1.start = B.end - 2; + buffer1.start >= B.start; buffer1.start--) + if (compare + (array[buffer1.start], + array[buffer1.start + 1]) + || compare (array[buffer1.start + 1], + array[buffer1.start])) + if (++count == buffer_size) + break; + buffer1.end = buffer1.start + count; + + if (Range_length (buffer1) == buffer_size) + { + bufferB = + MakeRange (buffer1.start, + buffer1.start + buffer_size); + buffer1 = + MakeRange (B.end - buffer_size, B.end); + } + } + } + else + { + /* the first item of the second buffer isn't guaranteed to be the first unique value, so we need to find the first unique item too */ + count = 0; + for (buffer2.start = buffer1.start + 1; + buffer2.start < A.end; buffer2.start++) + if (compare + (array[buffer2.start - 1], array[buffer2.start]) + || compare (array[buffer2.start], + array[buffer2.start - 1])) + if (++count == buffer_size) + break; + buffer2.end = buffer2.start + count; + + if (Range_length (buffer2) == buffer_size) + { + /* we found enough values for both buffers in A */ + bufferA = + MakeRange (buffer2.start, + buffer2.start + buffer_size * 2); + bufferB = MakeRange (B.end, B.end); + buffer1 = + MakeRange (A.start, A.start + buffer_size); + buffer2 = + MakeRange (A.start + buffer_size, + A.start + buffer_size * 2); + + } + else if (Range_length (buffer1) == buffer_size) + { + /* we found enough values for one buffer in A, so we'll need to find one buffer in B */ + bufferA = + MakeRange (buffer1.start, + buffer1.start + buffer_size); + buffer1 = + MakeRange (A.start, A.start + buffer_size); + + /* like before, the last value is guaranteed to be the first unique value we encounter, so we can start searching at the next index */ + count = 1; + for (buffer2.start = B.end - 2; + buffer2.start >= B.start; buffer2.start--) + if (compare + (array[buffer2.start], + array[buffer2.start + 1]) + || compare (array[buffer2.start + 1], + array[buffer2.start])) + if (++count == buffer_size) + break; + buffer2.end = buffer2.start + count; + + if (Range_length (buffer2) == buffer_size) + { + bufferB = + MakeRange (buffer2.start, + buffer2.start + buffer_size); + buffer2 = + MakeRange (B.end - buffer_size, B.end); + + } + else + buffer1.end = buffer1.start; /* failure */ + } + else + { + /* we were unable to find a single buffer in A, so we'll need to find two buffers in B */ + count = 1; + for (buffer1.start = B.end - 2; + buffer1.start >= B.start; buffer1.start--) + if (compare + (array[buffer1.start], + array[buffer1.start + 1]) + || compare (array[buffer1.start + 1], + array[buffer1.start])) + if (++count == buffer_size) + break; + buffer1.end = buffer1.start + count; + + count = 0; + for (buffer2.start = buffer1.start - 1; + buffer2.start >= B.start; buffer2.start--) + if (compare + (array[buffer2.start], + array[buffer2.start + 1]) + || compare (array[buffer2.start + 1], + array[buffer2.start])) + if (++count == buffer_size) + break; + buffer2.end = buffer2.start + count; + + if (Range_length (buffer2) == buffer_size) + { + bufferA = MakeRange (A.start, A.start); + bufferB = + MakeRange (buffer2.start, + buffer2.start + buffer_size * 2); + buffer1 = + MakeRange (B.end - buffer_size, B.end); + buffer2 = + MakeRange (buffer1.start - buffer_size, + buffer1.start); + + } + else + buffer1.end = buffer1.start; /* failure */ + } + } + + if (Range_length (buffer1) < buffer_size) + { + /* we failed to fill both buffers with unique values, which implies we're merging two subarrays with a lot of the same values repeated */ + /* we can use this knowledge to write a merge operation that is optimized for arrays of repeating values */ + while (Range_length (A) > 0 && Range_length (B) > 0) + { + /* find the first place in B where the first item in A needs to be inserted */ + long mid = BinaryFirst (array, A.start, B, compare); + + /* rotate A into place */ + long amount = mid - A.end; + Rotate (array, -amount, MakeRange (A.start, mid), + cache, cache_size); + + /* calculate the new A and B ranges */ + B.start = mid; + A = + MakeRange (BinaryLast + (array, A.start + amount, A, compare), + B.start); + } + + continue; + } + + /* move the unique values to the start of A if needed */ + length = Range_length (bufferA); + count = 0; + for (index = bufferA.start; count < length; index--) + { + if (index == A.start + || compare (array[index - 1], array[index]) + || compare (array[index], array[index - 1])) + { + Rotate (array, -count, + MakeRange (index + 1, bufferA.start + 1), + cache, cache_size); + bufferA.start = index + count; + count++; + } + } + bufferA = MakeRange (A.start, A.start + length); + + /* move the unique values to the end of B if needed */ + length = Range_length (bufferB); + count = 0; + for (index = bufferB.start; count < length; index++) + { + if (index == B.end - 1 + || compare (array[index], array[index + 1]) + || compare (array[index + 1], array[index])) + { + Rotate (array, count, + MakeRange (bufferB.start, index), cache, + cache_size); + bufferB.start = index - count; + count++; + } + } + bufferB = MakeRange (B.end - length, B.end); + + /* reuse these buffers next time! */ + level1 = buffer1; + level2 = buffer2; + levelA = bufferA; + levelB = bufferB; + } + + /* break the remainder of A into blocks. firstA is the uneven-sized first A block */ + blockA = MakeRange (bufferA.end, A.end); + firstA = + MakeRange (bufferA.end, + bufferA.end + Range_length (blockA) % block_size); + + /* swap the second value of each A block with the value in buffer1 */ + index = 0; + for (indexA = firstA.end + 1; indexA < blockA.end; + index++, indexA += block_size) + Swap (array[buffer1.start + index], array[indexA], Test); + + /* start rolling the A blocks through the B blocks! */ + /* whenever we leave an A block behind, we'll need to merge the previous A block with any B blocks that follow it, so track that information as well */ + lastA = firstA; + lastB = MakeRange (0, 0); + blockB = + MakeRange (B.start, + B.start + Min (block_size, + Range_length (B) - + Range_length (bufferB))); + blockA.start += Range_length (firstA); + + minA = blockA.start; + min_value = array[minA]; + indexA = 0; + + if (Range_length (lastA) <= cache_size) + memcpy (&cache[0], &array[lastA.start], + Range_length (lastA) * sizeof (array[0])); + else + BlockSwap (array, lastA.start, buffer2.start, + Range_length (lastA)); + + while (true) + { + /* if there's a previous B block and the first value of the minimum A block is <= the last value of the previous B block */ + if ((Range_length (lastB) > 0 + && !compare (array[lastB.end - 1], min_value)) + || Range_length (blockB) == 0) + { + /* figure out where to split the previous B block, and rotate it at the split */ + long B_split = + BinaryFirst (array, minA, lastB, compare); + long B_remaining = lastB.end - B_split; + + /* swap the minimum A block to the beginning of the rolling A blocks */ + BlockSwap (array, blockA.start, minA, block_size); + + /* we need to swap the second item of the previous A block back with its original value, which is stored in buffer1 */ + /* since the firstA block did not have its value swapped out, we need to make sure the previous A block is not unevenly sized */ + Swap (array[blockA.start + 1], + array[buffer1.start + indexA++], Test); + + /* locally merge the previous A block with the B values that follow it, using the buffer as swap space */ + WikiMerge (array, buffer2, lastA, + MakeRange (lastA.end, B_split), compare, + cache, cache_size); + + /* copy the previous A block into the cache or buffer2, since that's where we need it to be when we go to merge it anyway */ + if (block_size <= cache_size) + memcpy (&cache[0], &array[blockA.start], + block_size * sizeof (array[0])); + else + BlockSwap (array, blockA.start, buffer2.start, + block_size); + + /* this is equivalent to rotating, but faster */ + /* the area normally taken up by the A block is either the contents of buffer2, or data we don't need anymore since we memcopied it */ + /* either way, we don't need to retain the order of those items, so instead of rotating we can just block swap B to where it belongs */ + BlockSwap (array, B_split, + blockA.start + block_size - B_remaining, + B_remaining); + + /* now we need to update the ranges and stuff */ + lastA = + MakeRange (blockA.start - B_remaining, + blockA.start - B_remaining + block_size); + lastB = MakeRange (lastA.end, lastA.end + B_remaining); + blockA.start += block_size; + if (Range_length (blockA) == 0) + break; + + /* search the second value of the remaining A blocks to find the new minimum A block (that's why we wrote unique values to them!) */ + minA = blockA.start + 1; + for (findA = minA + block_size; findA < blockA.end; + findA += block_size) + if (compare (array[findA], array[minA])) + minA = findA; + minA = minA - 1; /* decrement once to get back to the start of that A block */ + min_value = array[minA]; + + } + else if (Range_length (blockB) < block_size) + { + /* move the last B block, which is unevenly sized, to before the remaining A blocks, by using a rotation */ + /* (using the cache is disabled since we have the contents of the previous A block in it!) */ + Rotate (array, -Range_length (blockB), + MakeRange (blockA.start, blockB.end), cache, 0); + lastB = + MakeRange (blockA.start, + blockA.start + Range_length (blockB)); + blockA.start += Range_length (blockB); + blockA.end += Range_length (blockB); + minA += Range_length (blockB); + blockB.end = blockB.start; + + } + else + { + /* roll the leftmost A block to the end by swapping it with the next B block */ + BlockSwap (array, blockA.start, blockB.start, + block_size); + lastB = + MakeRange (blockA.start, blockA.start + block_size); + if (minA == blockA.start) + minA = blockA.end; + + blockA.start += block_size; + blockA.end += block_size; + blockB.start += block_size; + blockB.end += block_size; + if (blockB.end > bufferB.start) + blockB.end = bufferB.start; + } + } + + /* merge the last A block with the remaining B blocks */ + WikiMerge (array, buffer2, lastA, + MakeRange (lastA.end, + B.end - Range_length (bufferB)), compare, + cache, cache_size); + } + } + + if (Range_length (level1) > 0) + { + long level_start; + + /* when we're finished with this step we should have b1 b2 left over, where one of the buffers is all jumbled up */ + /* insertion sort the jumbled up buffer, then redistribute them back into the array using the opposite process used for creating the buffer */ + InsertionSort (array, level2, compare); + + /* redistribute bufferA back into the array */ + level_start = levelA.start; + for (index = levelA.end; Range_length (levelA) > 0; index++) + { + if (index == levelB.start + || !compare (array[index], array[levelA.start])) + { + long amount = index - levelA.end; + Rotate (array, -amount, MakeRange (levelA.start, index), + cache, cache_size); + levelA.start += (amount + 1); + levelA.end += amount; + index--; + } + } + + /* redistribute bufferB back into the array */ + for (index = levelB.start; Range_length (levelB) > 0; index--) + { + if (index == level_start + || !compare (array[levelB.end - 1], array[index - 1])) + { + long amount = levelB.start - index; + Rotate (array, amount, MakeRange (index, levelB.end), cache, + cache_size); + levelB.start -= amount; + levelB.end -= (amount + 1); + index++; + } + } + } + + decimal_step += decimal_step; + fractional_step += fractional_step; + if (fractional_step >= fractional_base) + { + fractional_step -= fractional_base; + decimal_step += 1; + } + } + +#undef CACHE_SIZE +} + + + +long +TestingPathological (long index, long total) +{ + if (index == 0) + return 10; + else if (index < total / 2) + return 11; + else if (index == total - 1) + return 10; + return 9; +} + +long +TestingRandom (long index, long total) +{ + return rand_beebs (); +} + +long +TestingMostlyDescending (long index, long total) +{ + return total - index + rand_beebs () * 1.0 / RAND_MAX * 5 - 2.5; +} + +long +TestingMostlyAscending (long index, long total) +{ + return index + rand_beebs () * 1.0 / RAND_MAX * 5 - 2.5; +} + +long +TestingAscending (long index, long total) +{ + return index; +} + +long +TestingDescending (long index, long total) +{ + return total - index; +} + +long +TestingEqual (long index, long total) +{ + return 1000; +} + +long +TestingJittered (long index, long total) +{ + return (rand_beebs () * 1.0 / RAND_MAX <= 0.9) ? index : (index - 2); +} + +long +TestingMostlyEqual (long index, long total) +{ + return 1000L + (long) (rand_beebs () % 4); +} + + +const long max_size = 400; +Test array1[400]; + + +/* This benchmark does not support verification */ + +int +verify_benchmark (int res __attribute ((unused))) +{ + Test exp[] = { + {1000, 1}, {1000, 2}, {1000, 13}, {1000, 18}, {1000, 19}, + {1000, 26}, {1000, 31}, {1000, 32}, {1000, 35}, {1000, 36}, + {1000, 37}, {1000, 46}, {1000, 49}, {1000, 55}, {1000, 61}, + {1000, 62}, {1000, 66}, {1000, 72}, {1000, 73}, {1000, 74}, + {1000, 75}, {1000, 76}, {1000, 77}, {1000, 81}, {1000, 82}, + {1000, 83}, {1000, 87}, {1000, 89}, {1000, 91}, {1000, 92}, + {1000, 95}, {1000, 99}, {1000, 101}, {1000, 105}, {1000, 108}, + {1000, 109}, {1000, 114}, {1000, 119}, {1000, 120}, {1000, 128}, + {1000, 137}, {1000, 143}, {1000, 144}, {1000, 151}, {1000, 158}, + {1000, 161}, {1000, 162}, {1000, 165}, {1000, 169}, {1000, 181}, + {1000, 182}, {1000, 187}, {1000, 188}, {1000, 190}, {1000, 195}, + {1000, 196}, {1000, 198}, {1000, 200}, {1000, 201}, {1000, 205}, + {1000, 206}, {1000, 211}, {1000, 212}, {1000, 213}, {1000, 214}, + {1000, 215}, {1000, 217}, {1000, 221}, {1000, 223}, {1000, 225}, + {1000, 226}, {1000, 227}, {1000, 233}, {1000, 242}, {1000, 245}, + {1000, 249}, {1000, 250}, {1000, 266}, {1000, 270}, {1000, 271}, + {1000, 273}, {1000, 274}, {1000, 280}, {1000, 287}, {1000, 291}, + {1000, 295}, {1000, 299}, {1000, 303}, {1000, 304}, {1000, 312}, + {1000, 328}, {1000, 330}, {1000, 333}, {1000, 339}, {1000, 342}, + {1000, 346}, {1000, 350}, {1000, 361}, {1000, 371}, {1000, 376}, + {1000, 378}, {1000, 382}, {1000, 384}, {1000, 385}, {1000, 390}, + {1000, 396}, {1001, 5}, {1001, 7}, {1001, 8}, {1001, 11}, + {1001, 16}, {1001, 20}, {1001, 21}, {1001, 22}, {1001, 29}, + {1001, 34}, {1001, 39}, {1001, 40}, {1001, 41}, {1001, 42}, + {1001, 47}, {1001, 54}, {1001, 63}, {1001, 68}, {1001, 71}, + {1001, 78}, {1001, 84}, {1001, 85}, {1001, 93}, {1001, 96}, + {1001, 97}, {1001, 103}, {1001, 104}, {1001, 107}, {1001, 117}, + {1001, 129}, {1001, 139}, {1001, 140}, {1001, 148}, {1001, 156}, + {1001, 160}, {1001, 167}, {1001, 172}, {1001, 174}, {1001, 175}, + {1001, 179}, {1001, 185}, {1001, 186}, {1001, 193}, {1001, 194}, + {1001, 207}, {1001, 208}, {1001, 216}, {1001, 219}, {1001, 224}, + {1001, 228}, {1001, 229}, {1001, 235}, {1001, 237}, {1001, 240}, + {1001, 246}, {1001, 252}, {1001, 255}, {1001, 256}, {1001, 257}, + {1001, 259}, {1001, 260}, {1001, 261}, {1001, 265}, {1001, 267}, + {1001, 269}, {1001, 275}, {1001, 286}, {1001, 288}, {1001, 289}, + {1001, 294}, {1001, 301}, {1001, 302}, {1001, 308}, {1001, 309}, + {1001, 314}, {1001, 322}, {1001, 323}, {1001, 325}, {1001, 326}, + {1001, 327}, {1001, 334}, {1001, 337}, {1001, 341}, {1001, 347}, + {1001, 352}, {1001, 357}, {1001, 360}, {1001, 363}, {1001, 365}, + {1001, 366}, {1001, 369}, {1001, 375}, {1001, 379}, {1001, 381}, + {1001, 393}, {1001, 394}, {1001, 398}, {1002, 9}, {1002, 17}, + {1002, 23}, {1002, 24}, {1002, 30}, {1002, 33}, {1002, 38}, + {1002, 43}, {1002, 45}, {1002, 53}, {1002, 57}, {1002, 59}, + {1002, 60}, {1002, 64}, {1002, 69}, {1002, 70}, {1002, 79}, + {1002, 88}, {1002, 94}, {1002, 98}, {1002, 100}, {1002, 110}, + {1002, 111}, {1002, 115}, {1002, 118}, {1002, 123}, {1002, 125}, + {1002, 127}, {1002, 130}, {1002, 131}, {1002, 134}, {1002, 136}, + {1002, 138}, {1002, 142}, {1002, 146}, {1002, 149}, {1002, 150}, + {1002, 152}, {1002, 153}, {1002, 157}, {1002, 163}, {1002, 166}, + {1002, 168}, {1002, 170}, {1002, 171}, {1002, 173}, {1002, 176}, + {1002, 177}, {1002, 180}, {1002, 183}, {1002, 184}, {1002, 189}, + {1002, 191}, {1002, 197}, {1002, 202}, {1002, 203}, {1002, 204}, + {1002, 210}, {1002, 218}, {1002, 220}, {1002, 232}, {1002, 236}, + {1002, 238}, {1002, 241}, {1002, 243}, {1002, 244}, {1002, 251}, + {1002, 253}, {1002, 254}, {1002, 258}, {1002, 264}, {1002, 272}, + {1002, 277}, {1002, 279}, {1002, 282}, {1002, 283}, {1002, 284}, + {1002, 290}, {1002, 292}, {1002, 296}, {1002, 297}, {1002, 298}, + {1002, 300}, {1002, 306}, {1002, 307}, {1002, 310}, {1002, 311}, + {1002, 315}, {1002, 316}, {1002, 319}, {1002, 321}, {1002, 324}, + {1002, 331}, {1002, 335}, {1002, 340}, {1002, 344}, {1002, 349}, + {1002, 353}, {1002, 354}, {1002, 358}, {1002, 362}, {1002, 364}, + {1002, 370}, {1002, 374}, {1002, 380}, {1002, 383}, {1002, 386}, + {1002, 389}, {1002, 391}, {1002, 392}, {1002, 397}, {1003, 0}, + {1003, 3}, {1003, 4}, {1003, 6}, {1003, 10}, {1003, 12}, + {1003, 14}, {1003, 15}, {1003, 25}, {1003, 27}, {1003, 28}, + {1003, 44}, {1003, 48}, {1003, 50}, {1003, 51}, {1003, 52}, + {1003, 56}, {1003, 58}, {1003, 65}, {1003, 67}, {1003, 80}, + {1003, 86}, {1003, 90}, {1003, 102}, {1003, 106}, {1003, 112}, + {1003, 113}, {1003, 116}, {1003, 121}, {1003, 122}, {1003, 124}, + {1003, 126}, {1003, 132}, {1003, 133}, {1003, 135}, {1003, 141}, + {1003, 145}, {1003, 147}, {1003, 154}, {1003, 155}, {1003, 159}, + {1003, 164}, {1003, 178}, {1003, 192}, {1003, 199}, {1003, 209}, + {1003, 222}, {1003, 230}, {1003, 231}, {1003, 234}, {1003, 239}, + {1003, 247}, {1003, 248}, {1003, 262}, {1003, 263}, {1003, 268}, + {1003, 276}, {1003, 278}, {1003, 281}, {1003, 285}, {1003, 293}, + {1003, 305}, {1003, 313}, {1003, 317}, {1003, 318}, {1003, 320}, + {1003, 329}, {1003, 332}, {1003, 336}, {1003, 338}, {1003, 343}, + {1003, 345}, {1003, 348}, {1003, 351}, {1003, 355}, {1003, 356}, + {1003, 359}, {1003, 367}, {1003, 368}, {1003, 372}, {1003, 373}, + {1003, 377}, {1003, 387}, {1003, 388}, {1003, 395}, {1003, 399} + }; + + return 0 == memcmp (array1, exp, max_size * sizeof (array1[0])); +} + + +void +initialise_benchmark (void) +{ +} + + +static int benchmark_body (int rpt); + +void +warm_caches (int heat) +{ + int res = benchmark_body (heat); + + return; +} + + +int +benchmark (void) +{ + return benchmark_body (LOCAL_SCALE_FACTOR * CPU_MHZ); +} + + +static int __attribute__ ((noinline)) +benchmark_body (int rpt) +{ + long total, index, test_case; + Comparison compare = TestCompare; + + TestCasePtr test_cases[9] = + { + &TestingPathological, + &TestingRandom, + &TestingMostlyDescending, + &TestingMostlyAscending, + &TestingAscending, + &TestingDescending, + &TestingEqual, &TestingJittered, &TestingMostlyEqual}; + + int i; + + for (i = 0; i < rpt; i++) + { + /* initialize the random-number generator. */ + /* The original code used srand here, we use a value that will fit in + a 16-bit unsigned int. */ + srand_beebs (0); + /*srand(10141985); *//* in case you want the same random numbers */ + + total = max_size; + for (test_case = 0; test_case < 9; test_case++) + { + + for (index = 0; index < total; index++) + { + Test item; + + item.value = test_cases[test_case] (index, total); + item.index = index; + + array1[index] = item; + } + + WikiSort (array1, total, compare); + } + } + + return 0; +} + + +/* + Local Variables: + mode: C + c-file-style: "gnu" + End: +*/ diff --git a/benchies/embench/embench embench-iot master src.zip b/benchies/embench/embench embench-iot master src.zip new file mode 100644 index 0000000000000000000000000000000000000000..673705059c54bdfe7e981e77cd77f0e475ff3400 GIT binary patch literal 544774 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%0DKp$}B#@1( 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 literal 0 HcmV?d00001 diff --git a/benchies/embench/prj.conf b/benchies/embench/prj.conf index 836d4e21f4..ae7c3c4f3c 100644 --- a/benchies/embench/prj.conf +++ b/benchies/embench/prj.conf @@ -1,9 +1,7 @@ CONFIG_GPIO=y + #CONFIG_ASAN=y -CONFIG_CFI=y + CONFIG_LLVM_USE_LLD=y CONFIG_LTO=y - -#CONFIG_DEBUG=y -#CONFIG_DEBUG_INFO=y -#CONFIG_DEBUG_OPTIMIZATIONS=y +CONFIG_CFI=y diff --git a/benchies/embench/src/beebsc.c b/benchies/embench/src/beebsc.c new file mode 100644 index 0000000000..9e3a5fadb5 --- /dev/null +++ b/benchies/embench/src/beebsc.c @@ -0,0 +1,189 @@ +/* BEEBS local library variants + + Copyright (C) 2019 Embecosm Limited. + + Contributor Jeremy Bennett + + This file is part of Embench and was formerly part of the Bristol/Embecosm + Embedded Benchmark Suite. + + SPDX-License-Identifier: GPL-3.0-or-later */ + +/* These are very simple local versions of library routines, to ensure the + code is compiled with the flags used for the benchmark. Not all library + routines are here, just ones that cause a lot of unecessary load, or where + there is variation between platforms and architectures. */ + +#include +#include +#include +#include +#include "beebsc.h" + +/* Seed for the random number generator */ + +static long int seed = 0; + +/* Heap records and sane initial values */ + +static void *heap_ptr = NULL; +static void *heap_end = NULL; +static size_t heap_requested = 0; + + +/* Yield a sequence of random numbers in the range [0, 2^15-1]. + + long int is guaranteed to be at least 32 bits. The seed only ever uses 31 + bits (so is positive). + + For BEEBS this gets round different operating systems using different + multipliers and offsets and RAND_MAX variations. */ + +int +rand_beebs (void) +{ + seed = (seed * 1103515245L + 12345) & ((1UL << 31) - 1); + return (int) (seed >> 16); +} + + +/* Initialize the random number generator */ + +void +srand_beebs (unsigned int new_seed) +{ + seed = (long int) new_seed; +} + + +/* Initialize the BEEBS heap pointers. Note that the actual memory block is + in the caller code. */ + +void +init_heap_beebs (void *heap, size_t heap_size) +{ + assert(heap_size % sizeof(void *) == 0); /* see #138 */ + heap_ptr = (void *) heap; + heap_end = (void *) ((char *) heap_ptr + heap_size); + heap_requested = 0; +} + + +/* Report if malloc ever failed. + + Return non-zero (TRUE) if malloc did not reqest more than was available + since the last call to init_heap_beebs, zero (FALSE) otherwise. */ + +int +check_heap_beebs (void *heap) +{ + return ((void *) ((char *) heap + heap_requested) <= heap_end); +} + + +/* BEEBS version of malloc. + + This is primarily to reduce library and OS dependencies. Malloc is + generally not used in embedded code, or if it is, only in well defined + contexts to pre-allocate a fixed amount of memory. So this simplistic + implementation is just fine. + + Note in particular the assumption that memory will never be freed! */ + +void * +malloc_beebs (size_t size) +{ + if (size == 0) + return NULL; + + void *next_heap_ptr = (char *)heap_ptr + size; + + heap_requested += size; + + const size_t alignment = sizeof (void *); + + /* Check if the next heap pointer is aligned, otherwise add some padding */ + if (((uintptr_t)next_heap_ptr % alignment) != 0) + { + size_t padding = alignment - ((uintptr_t)next_heap_ptr % alignment); + + next_heap_ptr = (char *)next_heap_ptr + padding; + + /* padding is added to heap_requested because otherwise it will break + check_heap_beebs() */ + heap_requested += padding; + } + + /* Check if we can "allocate" enough space */ + if (next_heap_ptr > heap_end) + return NULL; + + void *new_ptr = heap_ptr; + heap_ptr = next_heap_ptr; + + return new_ptr; +} + + +/* BEEBS version of calloc. + + Implement as wrapper for malloc */ + +void * +calloc_beebs (size_t nmemb, size_t size) +{ + void *new_ptr = malloc_beebs (nmemb * size); + + /* Calloc is defined to zero the memory. OK to use a function here, because + it will be handled specially by the compiler anyway. */ + + if (NULL != new_ptr) + memset (new_ptr, 0, nmemb * size); + + return new_ptr; +} + + +/* BEEBS version of realloc. + + This is primarily to reduce library and OS dependencies. We just have to + allocate new memory and copy stuff across. */ + +void * +realloc_beebs (void *ptr, size_t size) +{ + if (ptr == NULL) + return NULL; + + /* Get a new aligned pointer */ + void *new_ptr = malloc_beebs (size); + + /* This is clunky, since we don't know the size of the original pointer. + However it is a read only action and we know it must be big enough if we + right off the end, or we couldn't have allocated here. If the size is + smaller, it doesn't matter. */ + + if (new_ptr != NULL) + for (size_t i = 0; i < size; i++) + ((char *)new_ptr)[i] = ((char *)ptr)[i]; + + return new_ptr; +} + + +/* BEEBS version of free. + + For our simplified version of memory handling, free can just do nothing. */ + +void +free_beebs (void *ptr __attribute__ ((unused))) +{ +} + + +/* + Local Variables: + mode: C + c-file-style: "gnu" + End: +*/ diff --git a/benchies/embench/src/beebsc.h b/benchies/embench/src/beebsc.h new file mode 100644 index 0000000000..4a10895964 --- /dev/null +++ b/benchies/embench/src/beebsc.h @@ -0,0 +1,65 @@ +/* BEEBS local library variants header + + Copyright (C) 2019 Embecosm Limited. + + Contributor Jeremy Bennett + + This file is part of Embench and was formerly part of the Bristol/Embecosm + Embedded Benchmark Suite. + + SPDX-License-Identifier: GPL-3.0-or-later */ + +#ifndef BEEBSC_H +#define BEEBSC_H + +#include + +/* BEEBS fixes RAND_MAX to its lowest permitted value, 2^15-1 */ + +#ifdef RAND_MAX +#undef RAND_MAX +#endif +#define RAND_MAX ((1U << 15) - 1) + +/* Common understanding of a "small value" (epsilon) for floating point + comparisons. */ + +#define VERIFY_DOUBLE_EPS 1.0e-13 +#define VERIFY_FLOAT_EPS 1.0e-5 + +/* Simplified assert. + + The full complexity of assert is not needed for a benchmark. See the + discussion at: + + https://lists.librecores.org/pipermail/embench/2019-August/000007.html + + This function just*/ + +#define assert_beebs(expr) { if (!(expr)) exit (1); } + +#define float_eq_beebs(exp, actual) (fabsf(exp - actual) < VERIFY_FLOAT_EPS) +#define float_neq_beebs(exp, actual) !float_eq_beebs(exp, actual) +#define double_eq_beebs(exp, actual) (fabs(exp - actual) < VERIFY_DOUBLE_EPS) +#define double_neq_beebs(exp, actual) !double_eq_beebs(exp, actual) + +/* Local simplified versions of library functions */ + +int rand_beebs (void); +void srand_beebs (unsigned int new_seed); + +void init_heap_beebs (void *heap, const size_t heap_size); +int check_heap_beebs (void *heap); +void *malloc_beebs (size_t size); +void *calloc_beebs (size_t nmemb, size_t size); +void *realloc_beebs (void *ptr, size_t size); +void free_beebs (void *ptr); +#endif /* BEEBSC_H */ + + +/* + Local Variables: + mode: C + c-file-style: "gnu" + End: +*/ diff --git a/benchies/embench/src/support.h b/benchies/embench/src/support.h index 641cadf590..60972f7c06 100644 --- a/benchies/embench/src/support.h +++ b/benchies/embench/src/support.h @@ -18,6 +18,7 @@ #ifdef HAVE_CONFIG_H #include "config.h" #endif +#include "beebsc.h" //#define DEBUG #define CPU_MHZ 5000 diff --git a/benchies/linpack/prj.conf b/benchies/linpack/prj.conf index 0c48afbef4..13dd900d4a 100644 --- a/benchies/linpack/prj.conf +++ b/benchies/linpack/prj.conf @@ -1,7 +1,8 @@ CONFIG_GPIO=y #CONFIG_ASAN=y #CONFIG_CFI=y -CONFIG_LLVM_USE_LLD=y +#CONFIG_LLVM_USE_LLD=y +CONFIG_ASAN=y #CONFIG_LTO=y #CONFIG_DEBUG=y