本章介绍如何添加自定义的组件。(前面发布了两个第7章节,内容是不同的)
一、错误纠正
在 使用LiteX快速创建FPGA SoC工程(7) 的 2.2 章节中,实际上如果不是需要专门定制 image 的话,在litex-board
的target
目录中执行以下命令即可,注意,--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文件中使用,注意连接clk
和rst
:
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逻辑。后续会进行更复杂的添加研究。
没有回复内容