devdc
devdc

Reputation: 161

Vitis HLS 2022.2 ERROR: [HLS 200-1715] Encountered problem during source synthesis

I'm a Vitis HLS beginner and trying to practice by building a bruteforcer on an idea of providing MD5 hash string, charset and max length and ideally run it on a PYNQ-Z2.

I've managed to come up with this code up until now and get the above error when synthisizing on Vitis HLS.

#include <iostream>
#include <vector>
 
char* pad_data(const char *data, size_t len, size_t& padded_size);
void md5(const unsigned int *in, unsigned int *out, const size_t size);
void generateCombinations(char* charset, int charset_size);
//void print_md5(unsigned char* md5);
 
 
void generateCombinations(char* charset, int charset_size)
{
#pragma HLS INTERFACE m_axi port=charset
#pragma HLS INTERFACE m_axi port=charset_size
    int length =  3;
    char current[length+1];
    for (size_t i = 0; i < length; i++)
    {
        current[i] = charset[0];
    }
 
 
    while (true)
    {
        //std::cout<<current<<std::endl;
        char c[length+1];
 
        for (size_t i = 0; i < length; i++)
        {
            c[i] = current[i];
        }
        unsigned char out[16];
        size_t data_size;
        char *pdata = pad_data(c, length, data_size);
        md5((unsigned int*)pdata, (unsigned int*)out, data_size);
        //print_md5(out);
        // check if out is equal to requested MD5 hash
        // if yes break and return to AXI port
 
        // Generate next combination
        bool carry = true;
        for (int i = length - 1; i >= 0; --i) {
            if (carry) {
                char* ptr;
                for (int j = 0; j < charset_size; j++) {
                    if (charset[j] == current[i]) {
                        ptr = charset + j;
                        break;
                    }
                }
                int idx = (ptr-charset)+1;
                if (idx >= charset_size) {
                    idx = 0;
                    carry = true;
                }
                else {
                    carry = false;
                }
                current[i] = charset[idx];
            }
        }
 
        if (carry) {
            break;
        }
    }
 
}
 
 
char* pad_data(const char *data, size_t len, size_t& padded_size)
{
    // Do padding in software for simplicity
    size_t mod = (len+1)%64;
    size_t pad_size = (64+56-mod)%64;
    padded_size = len+1+pad_size+8;
    char padded[padded_size];
 
 
    for (size_t i = 0; i < len; i++)
    {
        padded[i] = data[i];
    }
 
    padded[len] = (char)0x80;
 
    for (size_t i = len+1; i < len+1+pad_size; i++)
    {
        padded[i] = 0x0;
    }
 
    // Convert bytes to bits and append length
    len <<= 3;
    for(char* p = padded+(padded_size-8); p < padded+padded_size; ++p){
        *p = len & 0xff;
        len >>= 8;
    }
 
    return padded;
}
 
const unsigned int 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
};
 
const unsigned char S[][16] = {
    {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}
};
 
void md5_round1(const unsigned int *M, const unsigned int *in, unsigned int *out)
{
    unsigned int A = in[0];
    unsigned int B = in[1];
    unsigned int C = in[2];
    unsigned int D = in[3];
 
 
    for(int i=0; i<16; ++i){
        unsigned int tmp0 = (B&C)|(~B&D);
        unsigned int tmp1 = A + tmp0;
        unsigned int tmp2 = M[i] + K[i] + tmp1;
        unsigned int tmp3 = (tmp2 << S[0][i]) | (tmp2 >> (32-S[0][i]));
        A = D;
        D = C;
        C = B;
        B = tmp3 + B;
 
    }
    out[0] = A;
    out[1] = B;
    out[2] = C;
    out[3] = D;
}
 
void md5_round2(const unsigned int *M, const unsigned int *in, unsigned int *out)
{
    unsigned int A = in[0];
    unsigned int B = in[1];
    unsigned int C = in[2];
    unsigned int D = in[3];
    for(int i=0; i<16; ++i){
        unsigned int tmp0 = (B&D)|(C&~D);
        unsigned int tmp1 = A + tmp0;
        // unsigned int tmp2 = M[16+i] + K[16+i] + tmp1;
        unsigned int tmp2 = M[(((i+16) * 5) + 1) % 16] + K[16+i] + A + tmp0;
        unsigned int tmp3 = (tmp2 << S[1][i]) | (tmp2 >> (32-S[1][i]));
        A = D;
        D = C;
        C = B;
        B = tmp3 + B;
 
    }
    out[0] = A;
    out[1] = B;
    out[2] = C;
    out[3] = D;
}
 
void md5_round3(const unsigned int *M, const unsigned int *in, unsigned int *out)
{
    unsigned int A = in[0];
    unsigned int B = in[1];
    unsigned int C = in[2];
    unsigned int D = in[3];
    for(int i=0; i<16; ++i){
        unsigned int tmp0 = B^C^D;
        unsigned int tmp1 = A + tmp0;
        unsigned int tmp2 = M[(((i+32) * 3) + 5) % 16] + K[32+i] + tmp1;
        unsigned int tmp3 = (tmp2 << S[2][i]) | (tmp2 >> (32-S[2][i]));
        A = D;
        D = C;
        C = B;
        B = tmp3 + B;
 
    }
    out[0] = A;
    out[1] = B;
    out[2] = C;
    out[3] = D;
}
 
void md5_round4(const unsigned int *M, const unsigned int *in, unsigned int *out)
{
    unsigned int A = in[0];
    unsigned int B = in[1];
    unsigned int C = in[2];
    unsigned int D = in[3];
    for(int i=0; i<16; ++i){
        unsigned int tmp0 = C^(B|~D);
        unsigned int tmp1 = A + tmp0;
        unsigned int tmp2 = M[((i+48) * 7) % 16] + K[48+i] + tmp1;
        unsigned int tmp3 = (tmp2 << S[3][i]) | (tmp2 >> (32-S[3][i]));
        A = D;
        D = C;
        C = B;
        B = tmp3 + B;
 
    }
    out[0] = A;
    out[1] = B;
    out[2] = C;
    out[3] = D;
}
 
void md5(const unsigned int *in, unsigned int *out, const size_t size)
{
 
    const unsigned int *M = in;
    unsigned int v0[] = {0x67452301,0xEFCDAB89,0x98BADCFE,0x10325476};
    unsigned int v1[4];
    unsigned int v2[4];
    unsigned int v3[4];
    unsigned int v4[4];
 
    for(size_t i=0; i<size; i+=64)
    {
        md5_round1(M, v0, v1);
        md5_round2(M, v1, v2);
        md5_round3(M, v2, v3);
        md5_round4(M, v3, v4);
 
        M += 16;
        v0[0] += v4[0];
        v0[1] += v4[1];
        v0[2] += v4[2];
        v0[3] += v4[3];
    }
    out[0] = v0[0];
    out[1] = v0[1];
    out[2] = v0[2];
    out[3] = v0[3];
}

The C++ code works and I was able to compile and run it on x86 machine.

Was also able to solve non-synthisizable issues along the way.

I would highly appreciate any help and guidance that would help me understand what I'm missing or doing wrong.

Thanks so much!

Upvotes: 0

Views: 831

Answers (1)

lematthias
lematthias

Reputation: 291

While I can't pinpoint the issue directly I can give some general advice for HLS that may help:

  • You include <vector> but don't actually use it. Especially for HLS it is best to strictly follow the iwyu idiom. Not every part of the C++ standard is synthesizeable and including additional code may cause issues.
  • Use the C-Simulation integrated into Vivado HLS (or you use your own compiler) and enable additional warnings and check them thoroughly. pad_data() returns a reference to a local variable!
  • Local variables must have a fixed size. You declare c-arrays which might have unknown size at compile time. HLS translates this to hardware and additional ressources cannot be allocated on the FPGA during runtime. Depending on the size and your directives these arrays may be implemented with LUTs or BRAMs or FFs. If you need to store data locally then use an upper limit to declare your array and keep track of the size manually.
  • Include log files. You may also find helpful information in the Xilinx Forums

Upvotes: 1

Related Questions