使用LiteX快速创建FPGA SoC工程(8)-LiteX社区-FPGA CPLD-ChipDebug

使用LiteX快速创建FPGA SoC工程(8)

本章介绍如何添加自定义的组件。(前面发布了两个第7章节,内容是不同的)

一、错误纠正

在 使用LiteX快速创建FPGA SoC工程(7) 的 2.2 章节中,实际上如果不是需要专门定制 image 的话,在litex-boardtarget目录中执行以下命令即可,注意,--cpu-variant的值设置为linux即可,不需要在 linux-on-litex-vecriscv 仓库的根目录中的 make.py 文件中添加自己的板卡支持类(当然这么做也是可以的):

./alinx_ax7z100_target_linux.py  --cpu-type vexriscv_smp --cpu-variant linux --bus-standard axi

二、通过Verilog添加自己的组件

通常,我们使用改SoC只是为了快速生成SoC,然后添加一些加速IP,下面将举例说明如何添加;假设我们有一个Verilog代码,也是一个流水灯的功能,Verilog代码如下:

module my_leds(
    input clock,
    input reset,
    output reg [3:0] leds//there is 4 leds on my boards
);

localparam COUNT=100_000_000;//the freq of clock is 100MHz

reg [31:0] cnt;
always @(posedge clock)begin
    if(reset)
        leds <= 4'b1111;
    else if(cnt==COUNT)begin
        leds <= ~leds;
    end
end

always @(posedge clock)begin
    if(reset)
        cnt <= 4'b1111;
    else if(cnt==COUNT)begin
        cnt <= 0;
    end
    else begin
        cnt <= cnt + 1;
    end
end

endmodule

根据使用《LiteX快速创建FPGA SoC工程(2)》所述,添加Verilog代码需要使用Instance类,该类的源代码定义如下:

class Instance(Special):
        ...
        for k, v in sorted(kwargs.items(), key=itemgetter(0)): #kwargs代表了传递进来的Verilog信号与Migen信号的连接关系;itemgetter返回的是一个可调用对象,给key传入一个对象,返回该对象的第0个值
            # kwargs是一个字典,以该字典中每一项的第0个元素为依据进行排序(即以key进行排序)
            try:
                item_type, item_name = k.split("_", maxsplit=1) #k是一个字符串,以"_"为分隔符,最多分隔一次
            except ValueError:
                raise TypeError("Wrong format for value '" + str(k) +
                                "', format should be 'type_name'")

            item_class = {
                "i": Instance.Input,
                "o": Instance.Output,
                "io": Instance.InOut,
                "p": Instance.Parameter
            }[item_type] #也就是说,假设Veilog代码中有个输入端口名为"clk",则在Migen中的应表示为"i_clk",这里的item_type就是"i",item_name就是"clk"
            self.items.append(item_class(item_name, v)) #item_name是该信号在Verilog中的名称,v是该信号在Migen中的Signal对象
            ...

假设上述Verilog代码保存在my_leds.v文件中,该放在target文件夹下,如下所示:

(base) xlg@xlg16p:~/wrk/litex-boards/litex_boards/targets$ ls | grep leds
my_leds.py
my_leds.v

第一步,在platfrom文件,即alinx_ax7z100.py文件的构造器函数中,添加如下代码,其中add_source是继承自GenericPlatfrom类的方法(见使用LiteX快速创建FPGA SoC工程(5)):

def __init__(self):
        XilinxPlatform.__init__(self, "xc7z100ffg900-2", _io, _connectors, toolchain="vivado")
        self.add_extension(_ps7_io)
        self.add_extension(_usb_uart_pmod_io)
        self.add_source("./my_leds.v") # 新增的代码,注意此处的路径指的是相对于target文件执行的路径,而不是相对platfrom文件的路径

第二步,编写封装类——my_leds.py是封装Verilog代码创建的类,内容如下:

import os
from migen import *
from migen.fhdl import verilog
from random import randrange

from litex.gen import *
from litex.gen.genlib.misc import WaitTimer

from litex.soc.interconnect.csr import *

class my_leds(LiteXModule):
    def __init__(self, pads, clk=None, rst=None):
        self.pads = pads
        self.leds = Signal(len(pads))
        self.specials += [
            Instance("my_leds",
                        i_clock = clk,
                        i_reset = rst,
                        o_leds = self.leds,
                    )
        ] #Instance.of = "myleds",;
        
        self.comb += pads.eq(self.leds)

重要的几点如下:

  • i_clock:时钟输入,对Verilog模块来说,时钟信号为clock,那么此处前面就要加上前缀i_
  • i_reset:复位输入,原理同上;
  • o_leds:Verilog模块的输出,前面需要加上前缀o_
  • clk:是外部传入的时钟信号,稍后介绍;
  • rst:是外部传入的复位信号,稍后介绍;

第三步,在target文件中使用,注意连接clkrst

from my_leds import my_leds

...

if with_led_chaser:
            # self.submodules.leds = LedChaser(
            #     pads         = platform.request_all("user_led"),
            #     sys_clk_freq = sys_clk_freq)
            self.submodules.leds = my_leds(pads=platform.request_all("user_led"), clk=self.crg.cd_sys.clk, rst=self.crg.cd_sys.rst)

第四步,编译下载bit文件即可,可以看到led闪烁。

需要注意的是,通过上述方法,CPU并不能访问该led组件,只是初步的添加了一个FPGA逻辑。后续会进行更复杂的添加研究。

 

请登录后发表评论

    没有回复内容