c语言算法

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
#include<stdio.h>
#include<string>
#include<ctype.h>

void encrypt(char *plaintext, int shift)
{
int length = strlen(plaintext);
for(int i = 0; i < length; i++)
{
char current = plaintext[i];
if(isalpha(current))
{
char base = islower(current) ? 'a' : 'A';
plaintext[i] = (current - base + shift) % 26 + base;
}
else
exit(-1);
}
}

int main()
{
char plaintext[100];
for(i = 0; i < 100; i++)
{
plaintext[i] = 'a';
}
int shift = 5;
//fgets(plaintext, sizeof(plaintext), stdin);//c语言中的安全输入函数。提前预留空间
encrypt(plaintext, shift);
return 0;
}

上述是c语言代码,但是,在HLS中,只支持最基本的c语言函数,所以像字符串的很多函数比如strlen(), islower()都不支持。我们需要自己编写。

HLS中算法修改

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
#include<stdio.h>
#include<string.h>
#include<ctype.h>

int calculate_length(char *string)
{
int len = 0;
while (string[len] != '\0') {
len++;
}
return len;
}

void encrypt(char *plaintext, int shift)//注意如果用int表示位移会导致占用位数太大,而位移最多26位
{
int length = calculate_length(plaintext);//不支持常规长度函数,所以把长度函数写在头文件中
for(int i = 0; i < length; i++)
{
char current = plaintext[i];
if((current >='a' && current <= 'z') || (current >= 'A' && current <= 'Z'))
{
char base = (current >='a' && current <= 'z') ? 'a' : 'A';
plaintext[i] = (current - base + shift) % 26 + base;
}
//else
//exit(-1);
}
}

我们进行仿真,上述代码已经修改正确。(并非最终代码)

image-20231029182315274

我们观察仿真出来的verilog代码,看到shift位宽32位如图所示:

image-20231029182553308

然而位移最多26位,所以将宽度限制为5位即可。

所以定义一个头文件,在其中定义一些数据类型。

1
2
3
4
5
6
7
8
9
10
#ifndef _SHIFT_ENCRYPT_H
#define _SHIFT_ENCRYPT_H

#include "ap_int.h"


typedef ap_fixed<5, 5> shift_t;

void encrypt(char *plaintext, int shift);
#endif

之后我们要修改我们的源文件shift_encrypt.cpp如下:(并非最终代码)

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
#include<stdio.h>
#include<string.h>
#include<ctype.h>
#include "D:\Vitis_HLS\shift_encrypt\src\shift_encrypt.h"
int calculate_length(char *string)
{
int len = 0;
while (string[len] != '\0') {
len++;
}
return len;
}

void encrypt(char *plaintext, shift_t shift)//注意如果用int表示位移会导致占用位数太大,而位移最多26位
{
int length = calculate_length(plaintext);//不支持常规长度函数,所以把长度函数写在头文件中
for(int i = 0; i < length; i++)
{
char current = plaintext[i];
if((current >='a' && current <= 'z') || (current >= 'A' && current <= 'Z'))
{
char base = (current >='a' && current <= 'z') ? 'a' : 'A';
plaintext[i] = (current - base + (int)shift) % 26 + base;
}
//else
//exit(-1);
}
}

重新运行仿真,即可看到shift占位5bits.

注意,此时还有问题,因为我们的输入和输出都是同一个地址处的变量plaintext,不利于区分输入和输出端口,所以我们应该定义输入和输出,分开赋值,便于接口分配。

最终代码

所以修改之后的shift_encrypt文件如下:

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
#include<stdio.h>
#include<string.h>
#include<ctype.h>
#include "D:\Vitis_HLS\shift_encrypt\src\shift_encrypt.h"
//int calculate_length(char *string)
//{
// int len = 0;
// while (string[len] != '\0') {
// len++;
// }
// return len;
//}

void encrypt(char *input, shift_t shift, char *output)//注意如果用int表示位移会导致占用位数太大,而位移最多26位
{
//int length = calculate_length(input);//不支持常规长度函数,所以把长度函数写在头文件中
encrypt_label0:for(shift_t i = 0; i < 3; i++)
{
char current = input[i];
if((current >='a' && current <= 'z') || (current >= 'A' && current <= 'Z'))
{
char base = (current >='a' && current <= 'z') ? 'a' : 'A';
output[i] = (current - base + (int)shift) % 26 + base;
}
//else
//exit(-1);
}
}

修改的testbench.cpp文件如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include<stdio.h>
#include<string>
#include<ctype.h>
#include "D:\Vitis_HLS\shift_encrypt\src\shift_encrypt.h"
int main()
{
char input[4] = "aaa";
char output[4];
shift_t shift = 5;
//fgets(plaintext, sizeof(plaintext), stdin);//c语言中的安全输入函数。提前预留空间
encrypt(input, shift, output);
fprintf(stdout, "output result = %s\n", output);
return 0;
}

现在查看仿真报告可以看到端口输入输出端口明确。联合仿真之后可以查看波形,确定我们的testbench很好的适应源文件。

image-20231030111757834

我们尝试新建了一个solution,并且保留之前solution的directives文件,

image-20231030111935854

然后我们在这个solution中添加pipeline优化看能不能优化latency。

image-20231030112037102

然后对solution2进行综合,并且对比其与solution1综合的报告,对比latency。