Replaced sha1 implementation

This commit is contained in:
Clifford Wolf 2014-08-01 19:01:10 +02:00
parent 1e224506be
commit bd74ed7da4
8 changed files with 334 additions and 283 deletions

View File

@ -979,10 +979,6 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, std::map<RTLIL::IdStrin
use_internal_line_num(); use_internal_line_num();
std::string para_info; std::string para_info;
std::vector<unsigned char> hash_data;
hash_data.insert(hash_data.end(), stripped_name.begin(), stripped_name.end());
hash_data.push_back(0);
AstNode *new_ast = ast->clone(); AstNode *new_ast = ast->clone();
int para_counter = 0; int para_counter = 0;
@ -999,10 +995,6 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, std::map<RTLIL::IdStrin
para_info += stringf("%s=%s", child->str.c_str(), log_signal(RTLIL::SigSpec(parameters[para_id]))); para_info += stringf("%s=%s", child->str.c_str(), log_signal(RTLIL::SigSpec(parameters[para_id])));
delete child->children.at(0); delete child->children.at(0);
child->children[0] = AstNode::mkconst_bits(parameters[para_id].bits, (parameters[para_id].flags & RTLIL::CONST_FLAG_SIGNED) != 0); child->children[0] = AstNode::mkconst_bits(parameters[para_id].bits, (parameters[para_id].flags & RTLIL::CONST_FLAG_SIGNED) != 0);
hash_data.insert(hash_data.end(), child->str.begin(), child->str.end());
hash_data.push_back(0);
hash_data.insert(hash_data.end(), parameters[para_id].bits.begin(), parameters[para_id].bits.end());
hash_data.push_back(0xff);
parameters.erase(para_id); parameters.erase(para_id);
continue; continue;
} }
@ -1018,28 +1010,11 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, std::map<RTLIL::IdStrin
std::string modname; std::string modname;
if (orig_parameters_n == 0) if (orig_parameters_n == 0)
{
modname = stripped_name; modname = stripped_name;
} else if (para_info.size() > 60)
modname = "$paramod$" + sha1(para_info) + stripped_name;
else else
if (para_info.size() > 60)
{
unsigned char hash[20];
unsigned char *hash_data2 = new unsigned char[hash_data.size()];
for (size_t i = 0; i < hash_data.size(); i++)
hash_data2[i] = hash_data[i];
sha1::calc(hash_data2, hash_data.size(), hash);
delete[] hash_data2;
char hexstring[41];
sha1::toHexString(hash, hexstring);
modname = "$paramod$" + std::string(hexstring) + stripped_name;
}
else
{
modname = "$paramod" + stripped_name + para_info; modname = "$paramod" + stripped_name + para_info;
}
if (!design->has(modname)) { if (!design->has(modname)) {
new_ast->str = modname; new_ast->str = modname;

View File

@ -1,185 +1,270 @@
/* /*
Copyright (c) 2011, Micael Hildenborg sha1.cpp - source code of
All rights reserved.
Redistribution and use in source and binary forms, with or without ============
modification, are permitted provided that the following conditions are met: SHA-1 in C++
* 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 Micael Hildenborg 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 Micael Hildenborg ''AS IS'' AND ANY 100% Public Domain.
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 Micael Hildenborg 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.
*/
/* Original C Code
Contributors: -- Steve Reid <steve@edmweb.com>
Gustav Small changes to fit into bglibs
Several members in the gamedev.se forum. -- Bruce Guenter <bruce@untroubled.org>
Gregory Petrosyan Translation to simpler C++ Code
-- Volker Grabsch <vog@notjusthosting.com>
*/ */
#include "sha1.h" #include "sha1.h"
#include <sstream>
#include <iomanip>
#include <fstream>
namespace sha1 /* Help macros */
#define SHA1_ROL(value, bits) (((value) << (bits)) | (((value) & 0xffffffff) >> (32 - (bits))))
#define SHA1_BLK(i) (block[i&15] = SHA1_ROL(block[(i+13)&15] ^ block[(i+8)&15] ^ block[(i+2)&15] ^ block[i&15],1))
/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
#define SHA1_R0(v,w,x,y,z,i) z += ((w&(x^y))^y) + block[i] + 0x5a827999 + SHA1_ROL(v,5); w=SHA1_ROL(w,30);
#define SHA1_R1(v,w,x,y,z,i) z += ((w&(x^y))^y) + SHA1_BLK(i) + 0x5a827999 + SHA1_ROL(v,5); w=SHA1_ROL(w,30);
#define SHA1_R2(v,w,x,y,z,i) z += (w^x^y) + SHA1_BLK(i) + 0x6ed9eba1 + SHA1_ROL(v,5); w=SHA1_ROL(w,30);
#define SHA1_R3(v,w,x,y,z,i) z += (((w|x)&y)|(w&x)) + SHA1_BLK(i) + 0x8f1bbcdc + SHA1_ROL(v,5); w=SHA1_ROL(w,30);
#define SHA1_R4(v,w,x,y,z,i) z += (w^x^y) + SHA1_BLK(i) + 0xca62c1d6 + SHA1_ROL(v,5); w=SHA1_ROL(w,30);
SHA1::SHA1()
{ {
namespace // local reset();
{
// Rotate an integer value to left.
inline unsigned int rol(const unsigned int value,
const unsigned int steps)
{
return ((value << steps) | (value >> (32 - steps)));
} }
// Sets the first 16 integers in the buffert to zero.
// Used for clearing the W buffert. void SHA1::update(const std::string &s)
inline void clearWBuffert(unsigned int* buffert)
{ {
for (int pos = 16; --pos >= 0;) std::istringstream is(s);
update(is);
}
void SHA1::update(std::istream &is)
{ {
buffert[pos] = 0; std::string rest_of_buffer;
read(is, rest_of_buffer, BLOCK_BYTES - buffer.size());
buffer += rest_of_buffer;
while (is)
{
uint32 block[BLOCK_INTS];
buffer_to_block(buffer, block);
transform(block);
read(is, buffer, BLOCK_BYTES);
} }
} }
void innerHash(unsigned int* result, unsigned int* w)
/*
* Add padding and return the message digest.
*/
std::string SHA1::final()
{ {
unsigned int a = result[0]; /* Total number of hashed bits */
unsigned int b = result[1]; uint64 total_bits = (transforms*BLOCK_BYTES + buffer.size()) * 8;
unsigned int c = result[2];
unsigned int d = result[3];
unsigned int e = result[4];
int round = 0; /* Padding */
buffer += 0x80;
#define sha1macro(func,val) \ unsigned int orig_size = buffer.size();
{ \ while (buffer.size() < BLOCK_BYTES)
const unsigned int t = rol(a, 5) + (func) + e + val + w[round]; \
e = d; \
d = c; \
c = rol(b, 30); \
b = a; \
a = t; \
}
while (round < 16)
{ {
sha1macro((b & c) | (~b & d), 0x5a827999) buffer += (char)0x00;
++round;
}
while (round < 20)
{
w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
sha1macro((b & c) | (~b & d), 0x5a827999)
++round;
}
while (round < 40)
{
w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
sha1macro(b ^ c ^ d, 0x6ed9eba1)
++round;
}
while (round < 60)
{
w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
sha1macro((b & c) | (b & d) | (c & d), 0x8f1bbcdc)
++round;
}
while (round < 80)
{
w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
sha1macro(b ^ c ^ d, 0xca62c1d6)
++round;
} }
#undef sha1macro uint32 block[BLOCK_INTS];
buffer_to_block(buffer, block);
result[0] += a; if (orig_size > BLOCK_BYTES - 8)
result[1] += b;
result[2] += c;
result[3] += d;
result[4] += e;
}
} // namespace
void calc(const void* src, const int bytelength, unsigned char* hash)
{ {
// Init the result array. transform(block);
unsigned int result[5] = { 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0 }; for (unsigned int i = 0; i < BLOCK_INTS - 2; i++)
// Cast the void src pointer to be the byte array we can work with.
const unsigned char* sarray = (const unsigned char*) src;
// The reusable round buffer
unsigned int w[80];
// Loop through all complete 64byte blocks.
const int endOfFullBlocks = bytelength - 64;
int endCurrentBlock;
int currentBlock = 0;
while (currentBlock <= endOfFullBlocks)
{ {
endCurrentBlock = currentBlock + 64; block[i] = 0;
// Init the round buffer with the 64 byte block data.
for (int roundPos = 0; currentBlock < endCurrentBlock; currentBlock += 4)
{
// This line will swap endian on big endian and keep endian on little endian.
w[roundPos++] = (unsigned int) sarray[currentBlock + 3]
| (((unsigned int) sarray[currentBlock + 2]) << 8)
| (((unsigned int) sarray[currentBlock + 1]) << 16)
| (((unsigned int) sarray[currentBlock]) << 24);
}
innerHash(result, w);
}
// Handle the last and not full 64 byte block if existing.
endCurrentBlock = bytelength - currentBlock;
clearWBuffert(w);
int lastBlockBytes = 0;
for (;lastBlockBytes < endCurrentBlock; ++lastBlockBytes)
{
w[lastBlockBytes >> 2] |= (unsigned int) sarray[lastBlockBytes + currentBlock] << ((3 - (lastBlockBytes & 3)) << 3);
}
w[lastBlockBytes >> 2] |= 0x80 << ((3 - (lastBlockBytes & 3)) << 3);
if (endCurrentBlock >= 56)
{
innerHash(result, w);
clearWBuffert(w);
}
w[15] = bytelength << 3;
innerHash(result, w);
// Store hash in result pointer, and make sure we get in in the correct order on both endian models.
for (int hashByte = 20; --hashByte >= 0;)
{
hash[hashByte] = (result[hashByte >> 2] >> (((3 - hashByte) & 0x3) << 3)) & 0xff;
} }
} }
void toHexString(const unsigned char* hash, char* hexstring) /* Append total_bits, split this uint64 into two uint32 */
{ block[BLOCK_INTS - 1] = total_bits;
const char hexDigits[] = { "0123456789abcdef" }; block[BLOCK_INTS - 2] = (total_bits >> 32);
transform(block);
for (int hashByte = 20; --hashByte >= 0;) /* Hex std::string */
std::ostringstream result;
for (unsigned int i = 0; i < DIGEST_INTS; i++)
{ {
hexstring[hashByte << 1] = hexDigits[(hash[hashByte] >> 4) & 0xf]; result << std::hex << std::setfill('0') << std::setw(8);
hexstring[(hashByte << 1) + 1] = hexDigits[hash[hashByte] & 0xf]; result << (digest[i] & 0xffffffff);
} }
hexstring[40] = 0;
/* Reset for next run */
reset();
return result.str();
}
std::string SHA1::from_file(const std::string &filename)
{
std::ifstream stream(filename.c_str(), std::ios::binary);
SHA1 checksum;
checksum.update(stream);
return checksum.final();
}
void SHA1::reset()
{
/* SHA1 initialization constants */
digest[0] = 0x67452301;
digest[1] = 0xefcdab89;
digest[2] = 0x98badcfe;
digest[3] = 0x10325476;
digest[4] = 0xc3d2e1f0;
/* Reset counters */
transforms = 0;
buffer = "";
}
/*
* Hash a single 512-bit block. This is the core of the algorithm.
*/
void SHA1::transform(uint32 block[BLOCK_BYTES])
{
/* Copy digest[] to working vars */
uint32 a = digest[0];
uint32 b = digest[1];
uint32 c = digest[2];
uint32 d = digest[3];
uint32 e = digest[4];
/* 4 rounds of 20 operations each. Loop unrolled. */
SHA1_R0(a,b,c,d,e, 0);
SHA1_R0(e,a,b,c,d, 1);
SHA1_R0(d,e,a,b,c, 2);
SHA1_R0(c,d,e,a,b, 3);
SHA1_R0(b,c,d,e,a, 4);
SHA1_R0(a,b,c,d,e, 5);
SHA1_R0(e,a,b,c,d, 6);
SHA1_R0(d,e,a,b,c, 7);
SHA1_R0(c,d,e,a,b, 8);
SHA1_R0(b,c,d,e,a, 9);
SHA1_R0(a,b,c,d,e,10);
SHA1_R0(e,a,b,c,d,11);
SHA1_R0(d,e,a,b,c,12);
SHA1_R0(c,d,e,a,b,13);
SHA1_R0(b,c,d,e,a,14);
SHA1_R0(a,b,c,d,e,15);
SHA1_R1(e,a,b,c,d,16);
SHA1_R1(d,e,a,b,c,17);
SHA1_R1(c,d,e,a,b,18);
SHA1_R1(b,c,d,e,a,19);
SHA1_R2(a,b,c,d,e,20);
SHA1_R2(e,a,b,c,d,21);
SHA1_R2(d,e,a,b,c,22);
SHA1_R2(c,d,e,a,b,23);
SHA1_R2(b,c,d,e,a,24);
SHA1_R2(a,b,c,d,e,25);
SHA1_R2(e,a,b,c,d,26);
SHA1_R2(d,e,a,b,c,27);
SHA1_R2(c,d,e,a,b,28);
SHA1_R2(b,c,d,e,a,29);
SHA1_R2(a,b,c,d,e,30);
SHA1_R2(e,a,b,c,d,31);
SHA1_R2(d,e,a,b,c,32);
SHA1_R2(c,d,e,a,b,33);
SHA1_R2(b,c,d,e,a,34);
SHA1_R2(a,b,c,d,e,35);
SHA1_R2(e,a,b,c,d,36);
SHA1_R2(d,e,a,b,c,37);
SHA1_R2(c,d,e,a,b,38);
SHA1_R2(b,c,d,e,a,39);
SHA1_R3(a,b,c,d,e,40);
SHA1_R3(e,a,b,c,d,41);
SHA1_R3(d,e,a,b,c,42);
SHA1_R3(c,d,e,a,b,43);
SHA1_R3(b,c,d,e,a,44);
SHA1_R3(a,b,c,d,e,45);
SHA1_R3(e,a,b,c,d,46);
SHA1_R3(d,e,a,b,c,47);
SHA1_R3(c,d,e,a,b,48);
SHA1_R3(b,c,d,e,a,49);
SHA1_R3(a,b,c,d,e,50);
SHA1_R3(e,a,b,c,d,51);
SHA1_R3(d,e,a,b,c,52);
SHA1_R3(c,d,e,a,b,53);
SHA1_R3(b,c,d,e,a,54);
SHA1_R3(a,b,c,d,e,55);
SHA1_R3(e,a,b,c,d,56);
SHA1_R3(d,e,a,b,c,57);
SHA1_R3(c,d,e,a,b,58);
SHA1_R3(b,c,d,e,a,59);
SHA1_R4(a,b,c,d,e,60);
SHA1_R4(e,a,b,c,d,61);
SHA1_R4(d,e,a,b,c,62);
SHA1_R4(c,d,e,a,b,63);
SHA1_R4(b,c,d,e,a,64);
SHA1_R4(a,b,c,d,e,65);
SHA1_R4(e,a,b,c,d,66);
SHA1_R4(d,e,a,b,c,67);
SHA1_R4(c,d,e,a,b,68);
SHA1_R4(b,c,d,e,a,69);
SHA1_R4(a,b,c,d,e,70);
SHA1_R4(e,a,b,c,d,71);
SHA1_R4(d,e,a,b,c,72);
SHA1_R4(c,d,e,a,b,73);
SHA1_R4(b,c,d,e,a,74);
SHA1_R4(a,b,c,d,e,75);
SHA1_R4(e,a,b,c,d,76);
SHA1_R4(d,e,a,b,c,77);
SHA1_R4(c,d,e,a,b,78);
SHA1_R4(b,c,d,e,a,79);
/* Add the working vars back into digest[] */
digest[0] += a;
digest[1] += b;
digest[2] += c;
digest[3] += d;
digest[4] += e;
/* Count the number of transformations */
transforms++;
}
void SHA1::buffer_to_block(const std::string &buffer, uint32 block[BLOCK_BYTES])
{
/* Convert the std::string (byte buffer) to a uint32 array (MSB) */
for (unsigned int i = 0; i < BLOCK_INTS; i++)
{
block[i] = (buffer[4*i+3] & 0xff)
| (buffer[4*i+2] & 0xff)<<8
| (buffer[4*i+1] & 0xff)<<16
| (buffer[4*i+0] & 0xff)<<24;
}
}
void SHA1::read(std::istream &is, std::string &s, int max)
{
char sbuf[max];
is.read(sbuf, max);
s.assign(sbuf, is.gcount());
}
std::string sha1(const std::string &string)
{
SHA1 checksum;
checksum.update(string);
return checksum.final();
} }
} // namespace sha1

View File

@ -1,49 +1,57 @@
/* /*
Copyright (c) 2011, Micael Hildenborg sha1.h - header of
All rights reserved.
Redistribution and use in source and binary forms, with or without ============
modification, are permitted provided that the following conditions are met: SHA-1 in C++
* 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 Micael Hildenborg 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 Micael Hildenborg ''AS IS'' AND ANY 100% Public Domain.
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE Original C Code
DISCLAIMED. IN NO EVENT SHALL Micael Hildenborg BE LIABLE FOR ANY -- Steve Reid <steve@edmweb.com>
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES Small changes to fit into bglibs
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -- Bruce Guenter <bruce@untroubled.org>
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND Translation to simpler C++ Code
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -- Volker Grabsch <vog@notjusthosting.com>
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#ifndef SHA1_DEFINED #ifndef SHA1_HPP
#define SHA1_DEFINED #define SHA1_HPP
namespace sha1
#include <iostream>
#include <string>
class SHA1
{ {
public:
SHA1();
void update(const std::string &s);
void update(std::istream &is);
std::string final();
static std::string from_file(const std::string &filename);
/** private:
@param src points to any kind of data to be hashed. typedef unsigned long int uint32; /* just needs to be at least 32bit */
@param bytelength the number of bytes to hash from the src pointer. typedef unsigned long long uint64; /* just needs to be at least 64bit */
@param hash should point to a buffer of at least 20 bytes of size for storing the sha1 result in.
*/
void calc(const void* src, const int bytelength, unsigned char* hash);
/** static const unsigned int DIGEST_INTS = 5; /* number of 32bit integers per SHA1 digest */
@param hash is 20 bytes of sha1 hash. This is the same data that is the result from the calc function. static const unsigned int BLOCK_INTS = 16; /* number of 32bit integers per SHA1 block */
@param hexstring should point to a buffer of at least 41 bytes of size for storing the hexadecimal representation of the hash. A zero will be written at position 40, so the buffer will be a valid zero ended string. static const unsigned int BLOCK_BYTES = BLOCK_INTS * 4;
*/
void toHexString(const unsigned char* hash, char* hexstring);
} // namespace sha1 uint32 digest[DIGEST_INTS];
std::string buffer;
uint64 transforms;
#endif // SHA1_DEFINED void reset();
void transform(uint32 block[BLOCK_BYTES]);
static void buffer_to_block(const std::string &buffer, uint32 block[BLOCK_BYTES]);
static void read(std::istream &is, std::string &s, int max);
};
std::string sha1(const std::string &string);
#endif /* SHA1_HPP */

View File

@ -6,9 +6,9 @@ with Yosys.
\section{SHA1} \section{SHA1}
The files in {\tt libs/sha1/} provide a SHA1 implementation written by Micael The files in {\tt libs/sha1/} provide a public domain SHA1 implementation written
Hildenborg \citeweblink{smallsha1}. It is used for generating unique names when by Steve Reid, Bruce Guenter, and Volker Grabsch. It is used for generating
specializing parameterized modules. unique names when specializing parameterized modules.
\section{BigInt} \section{BigInt}

View File

@ -132,9 +132,3 @@
note = {\url{http://mattmccutchen.net/bigint/}} note = {\url{http://mattmccutchen.net/bigint/}}
} }
@misc{smallsha1,
author = {Micael Hildenborg},
title = {{smallsha1}},
note = {\url{https://code.google.com/p/smallsha1/}}
}

View File

@ -22,7 +22,6 @@
#include "kernel/sigtools.h" #include "kernel/sigtools.h"
#include "kernel/log.h" #include "kernel/log.h"
#include "kernel/celltypes.h" #include "kernel/celltypes.h"
#include "libs/sha1/sha1.h"
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <set> #include <set>

View File

@ -107,12 +107,7 @@ struct OptShareWorker
hash_string += "\n"; hash_string += "\n";
} }
unsigned char hash[20]; cell_hash_cache[cell] = sha1(hash_string);
char hash_hex_string[41];
sha1::calc(hash_string.c_str(), hash_string.size(), hash);
sha1::toHexString(hash, hash_hex_string);
cell_hash_cache[cell] = hash_hex_string;
return cell_hash_cache[cell]; return cell_hash_cache[cell];
} }
#endif #endif

View File

@ -99,12 +99,7 @@ struct TechmapWorker
connbits_map[bit] = std::pair<std::string, int>(conn.first, i);stringf("%s %d", log_id(conn.first), i, bit.data); connbits_map[bit] = std::pair<std::string, int>(conn.first, i);stringf("%s %d", log_id(conn.first), i, bit.data);
} }
unsigned char hash[20]; return stringf("$paramod$constmap:%s%s", sha1(constmap_info).c_str(), tpl->name.c_str());
char hash_hex_string[41];
sha1::calc(constmap_info.c_str(), constmap_info.size(), hash);
sha1::toHexString(hash, hash_hex_string);
return stringf("$paramod$constmap$%s%s", hash_hex_string, tpl->name.c_str());
} }
TechmapWires techmap_find_special_wires(RTLIL::Module *module) TechmapWires techmap_find_special_wires(RTLIL::Module *module)