LegUp使用及源码分析

本文主要记录由加拿大多伦多大学开发的开源高层次综合工具LegUp HLS的编译、使用方法及源码分析。

安装及使用

需要先导入clang-3.5的位置

echo "alias clang-3.5='~/clang+llvm-3.5.0-x86_64-linux-gnu/bin/clang-3.5'" >> ~/.bash_aliases && source ~/.bash_aliases
echo "alias clang-3.5++='~/clang+llvm-3.5.0-x86_64-linux-gnu/bin/clang-3.5++'" >> ~/.bash_aliases && source ~/.bash_aliases
export PATH=~/clang+llvm-3.5.0-x86_64-linux-gnu/bin:$PATH

以及Quartus vsim的位置

export QUARTUS_ROOTDIR=~/altera/15.0/quartus/
export PATH=~/altera/15.0/quartus/sopc_builder/bin/:$PATH
export PATH=~/altera/15.0/modelsim_ase/bin/:$PATH
export PATH=~/altera/15.0/quartus/bin/:$PATH

编译方法

  • 硬件流生成Verilog:make
  • ModelSim仿真:make v
  • Quartus创建项目:make p
  • Quartus后端综合:make f

程序结构

没有主函数!没有主函数!没有主函数!因为是直接生成动态库文件.so,所以实际上编译是用llvm/clang进行编译,然后链接所需的库文件而已。

对于llvm来说,新增一个库,即写一个pass,所以Legup的核心即为LegupPass.cpp

该文件第210行的runOnModule可以看作是它的主函数。

bool LegupPass::runOnModule(Module &M){ // schedule each function
    ...
    // Schedule the operations in each function
    for (Allocation::hw_iterator i = allocation->hw_begin(), ie =
            allocation->hw_end(); i != ie; ++i) {
        GenerateRTL *HW = *i;
        HW->scheduleOperations();
    }
    ...
}

接着对应的是GenerateRTL.cpp中第6780行的scheduleOperations

void GenerateRTL::scheduleOperations(){
    dag = new SchedulerDAG;
    dag->runOnFunction(*Fp, alloc); // build DAG!

    if (!LEGUP_CONFIG->getParameterInt("NO_DFG_DOT_FILES")) {
        printSchedulingDFGDot(*dag);
    }

    sched = new SDCScheduler(alloc);

    sched->schedule(Fp, dag); // schedule!
    fsm = sched->getFSM(Fp);
}

建图的过程可见SchedulerDAG.cpp第291行的runOnFunction

bool SchedulerDAG::runOnFunction(Function &F, Allocation *_alloc) {
    // read in function and iterate all its instructions
    ...
    for (Function::iterator b = F.begin(), be = F.end(); b != be; b++) {
        for (BasicBlock::iterator instr = b->begin(), ie = b->end();
             instr != ie; ++instr) {
            updateDAGwithInst(instr); // add nodes
        }
    }
    for (Function::iterator b = F.begin(), be = F.end(); b != be; b++) {
        for (BasicBlock::iterator instr = b->begin(), ie = b->end();
             instr != ie; ++instr) {
            generateDependencies(instr); // add edges
        }
    }
    ...
}

都是以指令为单位进行处理,一条指令(instruction)就是一个操作(operation)。 updateDAGwithInst用来添加每条指令的时延(delay),generateDependencies则用来添加数据依赖(别名分析等)。

Legup存在的问题

  • SDC的调度没有办法跨基本块,进而导致不同基本块之间的指令无法处于同个状态