FPGA 顶层自动合成

问题背景

在FPGA设计中有没有在为顶层合成而烦恼,明明是很简单的事情,但是还是每次将代码拷贝过去,删除端口类型 加括号 等等很无脑的操作,因此基于无脑操作的顶层合成来了。

功能实现

  1. 自动识别文件夹里的.v文件在这里插入图片描述
  2. 提取模块里的关键信息(端口名,模块名)在这里插入图片描述
  3. 将各个模块标准例化在这里插入图片描述

实现原理

功能实现基于C语言,采用文件读写进行操作。
我们知道在Verilog 语言中,其基本的组成 如图1 所示,其关键信息就隐藏在module 与endmodule 之间。
module 后面跟文件名,输入输出端口在()之间,因此可将内容读取到字符缓冲区中。根据module 和 );定位到关键信息点。
图1

代码实现

代码有点长,但是关键的地方我都做了注释了。
懒得看 点击我直接看结果


#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工程源码工程下 像这样
在这里插入图片描述
然后双击就会有小惊喜产生了
在这里插入图片描述

  • 4
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值