问题背景
在FPGA设计中有没有在为顶层合成而烦恼,明明是很简单的事情,但是还是每次将代码拷贝过去,删除端口类型 加括号 等等很无脑的操作,因此基于无脑操作的顶层合成来了。
功能实现
- 自动识别文件夹里的.v文件
- 提取模块里的关键信息(端口名,模块名)
- 将各个模块标准例化
实现原理
功能实现基于C语言,采用文件读写进行操作。
我们知道在Verilog 语言中,其基本的组成 如图1 所示,其关键信息就隐藏在module 与endmodule 之间。
module 后面跟文件名,输入输出端口在()之间,因此可将内容读取到字符缓冲区中。根据module 和 );定位到关键信息点。
代码实现
代码有点长,但是关键的地方我都做了注释了。
懒得看 点击我直接看结果
#include "string.h"
#include "stdlib.h"
#include "stdio.h"
#include "dirent.h"
#include "time.h"
#define MODULE_NAME_SIZE 20
#define MAX_BUFF_SIZE 1024 * 5
#define PORT_NUMBER_SIZE 20
#define PORT_NAME_SIZE 20
#define FIlE_MAME "Top.v"
enum _IO_Type
{
_IN_PUT,
_OUT_PUT,
_IN_OUT
};
typedef struct Link
{
char _IO_Type;
char _IO_Name[20];
char _IO_Module[20];
char _IO_Width;
struct Link *next;
} link;
char input[PORT_NUMBER_SIZE][PORT_NAME_SIZE] = {0};
char output[PORT_NUMBER_SIZE][PORT_NAME_SIZE] = {0};
char module_name[MODULE_NAME_SIZE] = {0};
char module_nuber;
FILE *file;
link *head, *node, *head_buff;
char judgeFileName(char *fileName);
char readMessage(char *fileName);
char *getKeyMessage(char *char_buff, int len);
char getKeyMessageIo(char *char_buff);
void valReset();
void printfSelf();
void printfHead();
void proMessage();
void DeletwoList(link *L);
int main()
{
int i = 0;
int filesize = 0;
DIR *dir = NULL;
struct dirent *entry;
head = (link *)malloc(sizeof(link));
memset(head->_IO_Name, 0, sizeof(head->_IO_Name));
head_buff = head;
char name_buff[260];
if ((dir = opendir(getcwd(NULL, 0))) == NULL)
{
printf("opendir failed!");
return -1;
}
else
{
//做一次 读端口操作
while (entry = readdir(dir))
{
i++;
strcpy(name_buff, entry->d_name); //输出文件或者目录的名称
if (judgeFileName(name_buff)) //找到.v文件
{
if (strcmp(name_buff, FIlE_MAME) == 0)
continue; //排除自己
readMessage(name_buff); //将信息全部写入全局变量中
proMessage(); //将端口 加载到 链表中
valReset();
}
}
closedir(dir);
head->next = NULL;
}
//做一次 打印操作
if ((dir = opendir(getcwd(NULL, 0))) == NULL)
{
printf("opendir failed!");
return -1;
}
else
{
file = fopen(FIlE_MAME, "w+");
printfHead();
while (entry = readdir(dir))
{
i++;
strcpy(name_buff, entry->d_name); //输出文件或者目录的名称
if (judgeFileName(name_buff)) //找到.v文件
{
if (strcmp(name_buff, FIlE_MAME) == 0)
continue; //排除自己
readMessage(name_buff); //将信息全部写入全局变量中
puts(name_buff);
printfSelf();
fprintf(file, " \n");
valReset();
}
}
fprintf(file, "endmodule \n");
closedir(dir);
fclose(file);
free(head);
}
printf("%s\n\n", "Done");
}
//判断是不是.v文件
char judgeFileName(char *fileName)
{
int len = strlen(fileName);
if (len > 2)
{
char a = fileName[len - 1];
char b = fileName[len - 2];
if (a == 'v' && b == '.')
return 1;
}
return 0;
}
//读取文件关键信息
char readMessage(char *fileName)
{
char char_buff[MAX_BUFF_SIZE];
FILE *fp;
fp = fopen(fileName, "r");
if (fp == NULL)
{
printf("File error\n");
return 0;
}
char ch;
int i = 0;
while ((ch = fgetc(fp)) != EOF) //按字符读文件
{
char_buff[i++] = ch;
}
char_buff[i - 1] = '\0';
getKeyMessage(char_buff, i);
fclose(fp);
return 1;
}
//抽取关键信息-模块名
char *getKeyMessage(char *char_buff, int len)
{
char *p;
//先找module name
p = strstr(char_buff, "module ");
p = strstr(p, " ");
p++;
int index = 0;
while (*p != '(')
{
module_name[index++] = *p;
p++;
}
module_name[index] = '\0'; //模块名找到了
//找IO端口
getKeyMessageIo(p);
free(p);
}
char getKeyMessageIo(char *char_buff)
{
char *p;
char *pp;
char *p_copy;
int index2 = 0;
int index1 = 0;
p_copy = char_buff;
p = char_buff;
while (EOF)
{
p = strstr(p, "input"); //输入定位
if (p == NULL)
break;
p = strstr(p, " ");
while (*p == ' ') //清空空格
{
p++;
}
if (*p == '[') //清空位宽
{
p++;
while (*p != ']')
{
p++;
}
p++;
}
while (*p != ',' && *(p + 1) != '\n' && *(p + 1) != ' ') //获得输入变量名
{
input[index1][index2++] = *p;
p++;
}
if (*(p - 1) != '\n')
input[index1][index2++] = *(p);
input[index1++][index2] = '\0';
index2 = 0;
}
for (int i = 0; i < index1; i++)
{
int sizelen = strlen(input[i]);
if (input[i][sizelen - 1] == ','||input[i][sizelen - 1] == ';')
input[i][sizelen - 1] = '\0';
}
input[PORT_NUMBER_SIZE - 1][0] = index1;
//输出定位
index2 = 0;
index1 = 0;
while (EOF)
{
p_copy = strstr(p_copy, "output"); //输出定位
if (p_copy == NULL)
break;
p_copy = strstr(p_copy, " ");
while (*p_copy == ' ') //清空空格
{
p_copy++;
}
//输出是寄存器变量
if (*(p_copy) == 'r' && *(p_copy + 1) == 'e' && *(p_copy + 2) == 'g')
{
p_copy++;
p_copy++;
p_copy++;
while (*p_copy == ' ') //清空空格
{
p_copy++;
}
}
if (*p_copy == '[') //清空位宽
{
p_copy++;
while (*p_copy != ']')
{
p_copy++;
}
p_copy++;
}
while (*p_copy != ',' && *(p_copy + 1) != '\n' && *(p_copy + 1) != ' ') //获得输入变量名
{
output[index1][index2++] = *p_copy;
p_copy++;
}
if (*(p_copy - 1) != '\n')
output[index1][index2++] = *(p_copy);
output[index1++][index2] = '\0';
index2 = 0;
}
for (int i = 0; i < index1; i++)
{
int sizelen = strlen(output[i]);
if (output[i][sizelen - 1] == ','||output[i][sizelen - 1] == ';')
output[i][sizelen - 1] = '\0';
}
output[PORT_NUMBER_SIZE - 1][0] = index1;
free(p);
free(pp);
free(p_copy);
}
void valReset()
{
memset(input, 0, sizeof(input));
memset(output, 0, sizeof(output));
memset(module_name, 0, sizeof(module_name));
}
void printfSelf()
{
module_nuber++;
fprintf(file, "%s u%d(\n", module_name, module_nuber);
for (int i = 0; i < input[PORT_NUMBER_SIZE - 1][0]; i++)
{
fprintf(file, " .%s(%s),\t\n", input[i], input[i]);
}
if (output[PORT_NUMBER_SIZE - 1][0] > 1)
{
for (int i = 0; i < output[PORT_NUMBER_SIZE - 1][0] - 1; i++)
{
fprintf(file, " .%s(%s),\t\n", output[i], output[i]);
}
}
fprintf(file, " .%s(%s)\t\n);\n", output[output[PORT_NUMBER_SIZE - 1][0] - 1], output[output[PORT_NUMBER_SIZE - 1][0] - 1]);
}
void printfHead()
{
time_t timep;
struct tm *p;
time(&timep);
p = gmtime(&timep);
fprintf(file, "`timescale 1ns / 1ps\n");
fprintf(file, "/\n");
fprintf(file, "// Company:\n");
fprintf(file, "// Engineer: \n");
fprintf(file, "// \n");
fprintf(file, "// Create Date: %d/%d/", p->tm_year + 1900, p->tm_mon + 1);
fprintf(file, "%d %d:%d:%d\n", p->tm_mday, 8 + p->tm_hour, p->tm_min, p->tm_sec);
fprintf(file, "// Design Name: Deam\n");
fprintf(file, "// Module Name: Top\n");
fprintf(file, "// Project Name:\n");
fprintf(file, "// Target Devices:\n");
fprintf(file, "// Tool Versions:\n");
fprintf(file, "// Description:\n");
fprintf(file, "//\n");
fprintf(file, "// Dependencies:\n");
fprintf(file, "//\n");
fprintf(file, "// Revision:\n");
fprintf(file, "// Revision 0.01 - File Created\n");
fprintf(file, "// Additional Comments:\n");
fprintf(file, "//\n");
fprintf(file, "/\n");
char buffch[PORT_NUMBER_SIZE] = {0};
strncpy(buffch, FIlE_MAME, strlen(FIlE_MAME) - 2);
fprintf(file, "module %s(\n", buffch);
DeletwoList(head_buff);
link *pp;
pp = head_buff;
while (pp->next != NULL)
{
if (pp->_IO_Type == _IN_PUT)
fprintf(file, "input %s,\n", pp->_IO_Name);
pp = pp->next;
}
pp = head_buff;
while (pp->next->next != NULL)
{
if (pp->_IO_Type == _OUT_PUT)
fprintf(file, "output %s,\n", pp->_IO_Name);
pp = pp->next;
}
fprintf(file, "output %s\n", pp->_IO_Name);
free(pp);
fprintf(file, ");\n\n\n");
}
void proMessage()
{
for (int i = 0; i < input[PORT_NUMBER_SIZE - 1][0]; i++)
{
strcpy(head->_IO_Module, module_name);
strcpy(head->_IO_Name, input[i]);
head->_IO_Type = _IN_PUT;
node = (link *)malloc(sizeof(link));
memset(node->_IO_Name, 0, sizeof(node->_IO_Name));
head->next = node;
head = head->next;
}
for (int i = 0; i < output[PORT_NUMBER_SIZE - 1][0]; i++)
{
strcpy(head->_IO_Module, module_name);
strcpy(head->_IO_Name, output[i]);
head->_IO_Type = _OUT_PUT;
node = (link *)malloc(sizeof(link));
memset(node->_IO_Name, 0, sizeof(node->_IO_Name));
head->next = node;
head = head->next;
}
}
void DeletwoList(link *L)
{
link *p, *q;
p = L->next;
while (p != NULL)
{
q = p;
while (q->next != NULL)
{
if (strcmp(p->_IO_Name, q->next->_IO_Name) == 0) //删除这和节点
{
q->next = q->next->next; //删除p->next这个节点
}
else
{
q = q->next;
}
}
p = p->next;
}
}
运行结果
在这里插入图片描述
ps使用小技巧
将编译后的.exe文件直接放到 FPGA工程源码工程下 像这样
然后双击就会有小惊喜产生了