本章介绍 BaseSoC 的继承关系的细节。
一、BaseSoC
以下是上一章节所使用的 Target 文件中的 BaseSoC 的代码:
# BaseSoC ------------------------------------------------------------------------------------------
class BaseSoC(SoCCore):
#kwargs指代了继承自SoCCore类的__init__方法的除了sys_clk_freq 和 with_led_chaser之外的所有所有参数,是一个字典
def __init__(self, sys_clk_freq=int(100e6),
with_ethernet = False,
eth_phy = "rgmii",
with_led_chaser = True, **kwargs):
platform = alinx_ax7z100.Platform()
# CRG --------------------------------------------------------------------------------------
# 创建一个子模块,即PLL
self.submodules.crg = _CRG(platform, sys_clk_freq)#platform的clk200会连接到pll,pll会生成sys_clk_freq的输出时钟
# SoCCore ----------------------------------------------------------------------------------
#if kwargs["uart_name"] == "serial": kwargs["uart_name"] = "usb_uart" # Use USB-UART Pmod on JB.
kwargs["uart_name"] = "serial"#强制把SoCCore的uar_name成员变量设置为serial,以和7100的platform文件中的定义对应
SoCCore.__init__(self, platform, sys_clk_freq, ident="LiteX SoC on Alinx AX7Z100", **kwargs)
# DDR3 SDRAM -------------------------------------------------------------------------------
if not self.integrated_main_ram_size:#该选项默认是None
self.ddrphy = s7ddrphy.K7DDRPHY(platform.request("ddram"),
memtype = "DDR3",
nphases = 4,
sys_clk_freq = sys_clk_freq)
self.add_sdram("sdram",
phy = self.ddrphy,
module = MT41J256M16(sys_clk_freq, "1:4"),
# module = MT41J256M16(sys_clk_freq, "1:4","800"),
l2_cache_size = kwargs.get("l2_size", 8192)
)
# Ethernet ---------------------------------------------------------------------------------
if with_ethernet:
# RGMII Ethernet PHY -------------------------------------------------------------------
if eth_phy == "rgmii":
# phy
self.ethphy = LiteEthPHYRGMII(
clock_pads = self.platform.request("eth_clocks"),
pads = self.platform.request("eth"))
self.add_ethernet(phy=self.ethphy)
# Leds -------------------------------------------------------------------------------------
if with_led_chaser:
self.submodules.leds = LedChaser(
pads = platform.request_all("user_led"),
sys_clk_freq = sys_clk_freq)
# 使用示例
soc = BaseSoC(#生成一个soc对象
sys_clk_freq = int(float(args.sys_clk_freq)),
#这里的args.sys_clk_freq实际上就是上面的--sys-clk-freq指定的值,最终决定了pll的输出频率
with_ethernet = args.with_ethernet,
eth_phy = args.eth_phy,
**soc_core_argdict(args)#传递SOC相关参数的字典给BaseSoc
)
可以看到,BaseSoC 继承自SoCCore 类,SoCCore 类是 LiteX 所提供的类。整体的继承关系如下图:
PS:图中最下面的类应该是自定义的BaseSoC
图 1 BaseSoC 的继承关系
各层级的父类的主要作用如下:
-
一级:
-
Migen Module:除了常规的功能,提供了 finalize 和 do_finalize 方法,其中 finalize 调用了 do_finalize,而 do_finalize 未定义具体的操作。
-
AutoCSR:是一种 MixIn,用于提供独立于总线的、对 CSR 寄存器的访问途径;一个 Module 可以通过继承该类,来继承 get_scrs、get_memories、get_constants 三个方法,这三个方法用于扫描 CSR 和 memory 的属性,并返回相关的列表;
-
AutoDoc:自动生成 SoC 相关信息的文档的功能,例如各个外设的地址空间,此处不进行介绍;
-
-
二级:
-
LiteXModule:是 Migen Module 的强化版本,提供了一些处理子模块、specials 和时钟域的方便的方法;一般无需改动;
-
SoCCoreCompat:为了实现某些兼容性,定义了一些方法,目前已经在其他类中有替代性的方法,最好不要使用;包括:添加中断、添加 wb_master、添加 wb_slave、添加寄存器 memory、添加寄存器 rom 等;
-
-
三级:
-
SoC:该类大量实现了 SoC 的相关细节,包括总线定义、csr 定义、中断定义等,将重点介绍该类;
-
-
四级:
-
LiteXSoC:相对于 SoC 类新增了大量的方法,包括添加 UART、UARTbone、jtagbone、sdram、ethernet、etherbone、spi_flash、spi_sdcard、sdcard、sata、pcie、video_colorbars、video_terminal、video_framebuffer;
-
-
五级:
-
SoCCore:进一步细化的 SoC 的细节,包括总线、CPU、ROM、SRAM、MainRAM、CSR、中断、UART、timer、JTAG 等;将详细介绍;
-
从 BaseSoC 的构造器函数init代码和使用示例可以看出,如果该 SoC 需要某种功能的开关,则需要在构造器函数的参数中进行添加,并通过命令行参数进行传递。
注意这一行代码:SoCCore.__init__(self, platform, sys_clk_freq, ident="LiteX SoC on Alinx AX7Z100", **kwargs)
,BaseSoC 调用了其父类的构造器函数,传递了 platform、默认时钟域的时钟频率、以及打印信息。
下面将逐步查看继承关系中的类的定义。
二、LiteXModule
该类定义了两个经常使用的方法add_module
和get_module
,用于添加或获取子模块。
LiteXModule 有三个子类:
-
SoCBusHandler
-
SoCLocHandler
-
SoCController
-
SoC
2.1 SoCBusHandler
该类定义了所支持的总线及其可能的参数,支持三种总线 wishbone、axi-lite 和 axi;具体如下:
# 三个类变量
supported_standard = ["wishbone", "axi-lite", "axi"]
supported_data_width = [32, 64, 128, 256, 512]
supported_address_width = [32, 64]
其中,wishbone 只能按字的大小寻址,其他的可以按字节寻址,还定义了 masters、slaves、regions、io_regeions 等成员变量,如下:
# Create Bus;以下都是成员变量
self.standard = standard
self.data_width = data_width
self.address_width = address_width
self.addressing = {
"wishbone" : "word", # FIXME: Allow selection for Wishbone.
"axi-lite" : "byte",
"axi" : "byte",
}[standard]
self.bursting = bursting
self.interconnect = interconnect
self.interconnect_register = interconnect_register
self.masters = {}
self.slaves = {}
self.regions = {}
self.io_regions = {}
self.io_regions_check = True
self.timeout = timeout
self.logger.info("{}-bit {} Bus, {}GiB Address Space.".format(
colorer(data_width), colorer(standard), colorer(2**address_width/2**30)))
支持添加保留字段:
# Add reserved regions.
self.logger.info("Adding {} Bus Regions...".format(colorer("reserved", color="cyan")))
for name, region in reserved_regions.items():
if isinstance(region, int):
# SoCRegion的构造器函数为:__init__(self, origin=None, size=None, mode="rw", cached=True, linker=False, decode=True):
region = SoCRegion(origin=region, size=0x1000000)
self.add_region(name, region)
self.logger.info("Bus Handler {}.".format(colorer("created", color="green")))
2.1.1 类方法
-
add_regin(name, region)
该方法用于添加、分配或检查 region。如果一个 region 是 IO region,那么该 region 只能是不可缓存的,否则只能是可缓存的。
-
alloc_region(name, size, cached=True)
该方法用于为那些没有指定边界的 regin 进行分配。分配的region具有2的幂次方对齐的起始地址,并且确保不会和其他已有的region重叠。
-
check_region_is_in(region, container)
检查region的下边界是否小于container的下边界,或者region的上边界是否大于等于container的上边界,满足其一则返回false。
-
check_region_is_io(region)
检查传入的region与所有的io_region是否存在in关系,即循环调用check_region_is_in
进行检查。
-
add_adapter(name, interface, direction="m2s")
其中又定义了:bus_data_width_convert
、bus_addressing_convert
、bus_standard_convert
、通过使用add_adapter
,将对外提供与系统总线不同的总结接口。参数interface是所需要的总线类型。
-
add_master(name=None, master=None)
在总线上添加master。
-
add_controller(name=None, controller=None)
实际上就是调用了add_master
,将其master参数设置为controller。应该没有什么区别。
-
add_slave(name=None, slave=None, region=None)
添加slave,会进行是否重名、是否重复添加的检查。
-
add_peripheral(name=None, peripheral=None, region=None)
实际上就是调研了add_slave
,将peripheral和region传递给它。
-
get_address_width(standard)
该方法返回系统总线(即standard参数所代表的总线)的地址为宽,如果standard所代表的总线类型与实际的系统总线不一致,还会进行地址位宽的变换。
此外,SoCBusHandler子类会根据masters和slaves的数量来决定使用p2p还是crossbar/sharedbus。
2.2 SoCLocHandler
2.2.1 构造器函数__init__
def __init__(self, name, n_locs):
self.name = name
self.locs = {}
self.n_locs = n_locs
2.2.2 类方法
-
alloc(name)
-
add(name, n=None, use_loc_if_exists=False)
SoCLocHandler类又有以下子类:
-
SoCCSRHandler
-
SoCIRQHandler
2.2.3 子类SoCCSRHandler
2.2.3.1 类成员
SoCCSRHandler有几个类成员,如下所示,定义了所支持的寄存器的数据位宽、地址位宽、对齐位宽、分页大小、大小端等:
supported_data_width = [8, 32]
supported_address_width = [14+i for i in range(4)]
supported_alignment = [32]
supported_paging = [0x800*2**i for i in range(4)] # 0x800 =>1000_0000_0000, 左移0~3bit
supported_ordering = ["big", "little"]
2.2.3.2 构造器函数__init__
def __init__(self, data_width=32, address_width=14, alignment=32, paging=0x800, ordering="big", reserved_csrs={}):
SoCLocHandler.__init__(self, "CSR", n_locs=alignment//8*(2**address_width)//paging) # name = "CSR", n_locs计算的是,在指定地址位宽后,有多少个分页
...
self.data_width = data_width
self.address_width = address_width
self.alignment = alignment
self.paging = paging
self.ordering = ordering
self.masters = {}
self.regions = {}
...
# Add reserved CSRs.
self.logger.info("Adding {} CSRs...".format(colorer("reserved", color="cyan")))
for name, n in reserved_csrs.items():
self.add(name, n)
...
注意到masters和regions是空的。
2.2.3.3 类方法
-
add_master(name=None, master=None)
用于添加master,会进行是否重复添加的检查和数据位宽是否匹配的检查。
-
add_region(name, region)
添加region
-
address_map(name, memory)
如果name未被添加,则会自动添加;如果已存在,则直接返回该name所对应的序号。
2.2.4 子类SoCIRQHandler
2.2.4.1 构造器函数__init__
def __init__(self, n_irqs=32, reserved_irqs={}):
SoCLocHandler.__init__(self, "IRQ", n_locs=n_irqs)
self.logger = logging.getLogger("SoCIRQHandler")
self.logger.info("Creating IRQ Handler...")
self.enabled = False
...
for name, n in reserved_irqs.items():
self.add(name, n)
...
构造器函数默认没有启用irq。
2.2.4.2 类方法
-
enable()
将enabled
设置为True
。
-
add(name, *args, **kwargs)
检查是否启用了irq,然后才调用父类SoCLocHandler
的add
方法。未启用就调用,会报错。
2.3 SoCController
该类仅有一个构造器函数:
def __init__(self, with_reset=True, with_scratch=True, with_errors=True):
if with_reset:
self._reset = CSRStorage(fields=[
CSRField("soc_rst", size=1, offset=0, pulse=True, description="""Write `1` to this register to reset the full SoC (Pulse Reset)"""),
CSRField("cpu_rst", size=1, offset=1, description="""Write `1` to this register to reset the CPU(s) of the SoC (Hold Reset)"""),
])
if with_scratch:
self._scratch = CSRStorage(32, reset=0x12345678, description="""
Use this register as a scratch space to verify that software read/write accesses
to the Wishbone/CSR bus are working correctly. The initial reset value of 0x1234578
can be used to verify endianness.""")
if with_errors:
self._bus_errors = CSRStatus(32, description="Total number of Wishbone bus errors (timeouts) since start.")
# # #
# Reset
if with_reset:
self.soc_rst = self._reset.fields.soc_rst
self.cpu_rst = self._reset.fields.cpu_rst
# Errors
if with_errors:
self.bus_error = Signal()
bus_errors = Signal(32)
self.sync += [
If(bus_errors != (2**len(bus_errors)-1),
If(self.bus_error, bus_errors.eq(bus_errors + 1))
)
]
self.comb += self._bus_errors.status.eq(bus_errors)
该类总的来说就是设置了一些寄存器,用于CPU复位、SOC复位和总线读写操作测试。
下面将单独介绍LiteXModule的SoC子类。
三、SoC
3.1 类成员
mem_map = {}
可以看到初始的mem_map
为空。
3.2 构造器函数__init__
def __init__(self, platform, sys_clk_freq,
bus_standard = "wishbone",
bus_data_width = 32,
bus_address_width = 32,
bus_timeout = 1e6,
bus_bursting = False,
bus_interconnect = "shared",
bus_reserved_regions = {},
csr_data_width = 32,
csr_address_width = 14,
csr_paging = 0x800,
csr_ordering = "big",
csr_reserved_csrs = {},
irq_n_irqs = 32,
irq_reserved_irqs = {},
):
...
self.platform = platform # 设置板卡
self.sys_clk_freq = int(sys_clk_freq) # Do conversion to int here to allow passing float to SoC.
self.constants = {} #在add_constant中使用
self.csr_regions = {}
...
# 调用三个子类处理相关事务
# SoC Bus Handler --------------------------------------------------------------------------
self.bus = SoCBusHandler(
standard = bus_standard,
data_width = bus_data_width,
address_width = bus_address_width,
timeout = bus_timeout,
bursting = bus_bursting,
interconnect = bus_interconnect,
reserved_regions = bus_reserved_regions,
)
# SoC Bus Handler --------------------------------------------------------------------------
self.csr = SoCCSRHandler(
data_width = csr_data_width,
address_width = csr_address_width,
alignment = 32,
paging = csr_paging,
ordering = csr_ordering,
reserved_csrs = csr_reserved_csrs,
)
# SoC IRQ Handler --------------------------------------------------------------------------
self.irq = SoCIRQHandler(
n_irqs = irq_n_irqs,
reserved_irqs = irq_reserved_irqs
)
...
self.add_config("CLOCK_FREQUENCY", int(sys_clk_freq))
3.3 类方法
以下是SoC的一些辅助方法:
-
check_if_exists(name)
检查name
所代表的子模块是否存在。
-
add_constant(name, value=None, check_duplicate=True)
将name
全都大写,并保存value
至self.constants
中。
-
add_config(name, value=None, check_duplicate=True)
将"CONFIG_" + name
保存到self.constants
中。
-
check_bios_requirements()
检查是否有timer0
、rom
、sram
等外设。
以下是SoC的主要组件:
-
add_controller(name="ctrl", **kwargs)
调用父类LiteXModule的add_module方法,添加CPU控制器SoCController
-
add_ram(name, origin, size, contents=[], mode="rwx")
添加SRAM,SRAM的接口实际上只支持wishbone
或者AXILite
。
-
add_rom(name, origin, size, contents=[], mode="rx")
实际上就是调用了add_ram
-
init_rom(name, contents=[], auto_size=True)
初始化rom,如果auto_size
为True,并且name
所对应的存储的读写模式设置为只读,则还会设置该存储的depth
属性为contents
的长度。
-
add_csr_bridge(name="csr", origin=None, register=False)
添加一个子模块,将所选定的系统总线转换为访问CSR的总线。
-
add_cpu(name="vexriscv", variant="standard", reset_address=None, cfu=None)
用于添加哪种CPU。name
为CPU的名称,variant
为CPU的变种,如果要运行linux系统,可能需要指定variant
为特定的值。
要查找所支持CPU的name
和variant
,在litex仓库的根目录下执行以下命令:
(base) ➜ litex git:(master) ✗ find . -name "core.py"
./litex/gen/sim/core.py
./litex/soc/cores/cpu/rocket/core.py
./litex/soc/cores/cpu/mor1kx/core.py
./litex/soc/cores/cpu/cortex_m3/core.py
./litex/soc/cores/cpu/blackparrot/core.py
./litex/soc/cores/cpu/marocchino/core.py
./litex/soc/cores/cpu/cv32e41p/core.py
./litex/soc/cores/cpu/lm32/core.py
./litex/soc/cores/cpu/femtorv/core.py
./litex/soc/cores/cpu/cortex_m1/core.py
./litex/soc/cores/cpu/vexriscv_smp/core.py
./litex/soc/cores/cpu/firev/core.py
./litex/soc/cores/cpu/picorv32/core.py
./litex/soc/cores/cpu/ibex/core.py
./litex/soc/cores/cpu/cv32e40p/core.py
./litex/soc/cores/cpu/eos_s3/core.py
./litex/soc/cores/cpu/serv/core.py
./litex/soc/cores/cpu/zynqmp/core.py
./litex/soc/cores/cpu/cva6/core.py
./litex/soc/cores/cpu/kianv/core.py
./litex/soc/cores/cpu/zynq7000/core.py
./litex/soc/cores/cpu/microwatt/core.py
./litex/soc/cores/cpu/openc906/core.py
./litex/soc/cores/cpu/gowin_emcu/core.py
./litex/soc/cores/cpu/naxriscv/core.py
./litex/soc/cores/cpu/cva5/core.py
./litex/soc/cores/cpu/vexriscv/core.py
./litex/soc/cores/cpu/neorv32/core.py
./litex/soc/cores/cpu/minerva/core.py
打开其中一个文件,以vexriscv为例,其中的部分内容如下:
class VexRiscv(CPU, AutoCSR):
category = "softcore"
family = "riscv"
name = "vexriscv"
human_name = "VexRiscv"
variants = CPU_VARIANTS
data_width = 32
endianness = "little"
gcc_triple = CPU_GCC_TRIPLE_RISCV32
linker_output_format = "elf32-littleriscv"
nop = "nop"
io_regions = {0x8000_0000: 0x8000_0000} # Origin, Length
# Memory Mapping.
@property
def mem_map(self):
return {
"rom": 0x0000_0000,
"sram": 0x1000_0000,
"main_ram": 0x4000_0000,
"csr": 0xf000_0000,
"vexriscv_debug": 0xf00f_0000,
}
....
# Variants -----------------------------------------------------------------------------------------
CPU_VARIANTS = {
"minimal": "VexRiscv_Min",
"minimal+debug": "VexRiscv_MinDebug",
"minimal+debug+hwbp": "VexRiscv_MinDebugHwBP",
"lite": "VexRiscv_Lite",
"lite+debug": "VexRiscv_LiteDebug",
"lite+debug+hwbp": "VexRiscv_LiteDebugHwBP",
"standard": "VexRiscv",
"standard+debug": "VexRiscv_Debug",
"imac": "VexRiscv_IMAC",
"imac+debug": "VexRiscv_IMACDebug",
"full": "VexRiscv_Full",
"full+cfu": "VexRiscv_FullCfu",
"full+debug": "VexRiscv_FullDebug",
"full+cfu+debug": "VexRiscv_FullCfuDebug",
"linux": "VexRiscv_Linux",
"linux+debug": "VexRiscv_LinuxDebug",
"linux+no-dsp": "VexRiscv_LinuxNoDspFmax",
"secure": "VexRiscv_Secure",
"secure+debug": "VexRiscv_SecureDebug",
}
可以发现其变种非常多,如果要支持Linux系统,需要进行指定。
说明一下cfu
,即Custom Function Unit,自定义的加速单元,如果要添加加速单元,需要选择特殊的、带”cfu”的CPU变种,例如"full+cfu"
。
回归到add_cpu
函数中,该函数还有一个reset_address=None
的参数,该参数如果为None,则复位地地址会被设置为类成员mem_map
中rom
的地址:
if reset_address is None:
reset_address = self.mem_map["rom"]
add_timer(name=”timer0″)
添加计时器,并且添加该计时器产生的终端
-
finalize(self)
进行收尾工作,比较复杂。
四、LiteXSoC
该类主要是添加了一系列方法,以添加LiteX提供的标准外设。
-
add_identifier(name="identifier", identifier="LiteX SoC", with_build_time=True)
该方法主要是添加一个LiteX提供的模块Identifier
,用于打印文字信息,参数name为模块名,identifier
为所需要打印的信息,with_build_time
表示是否需要在identifier后面加上时间辍信息。
-
def add_uart(name="uart", uart_name="serial", baudrate=115200, fifo_depth=16):
顾名思义,该方法用于添加UART,name
为模块名称,uart_name
则是指定了UART的类型,并且会根据该类型获取platform中的引脚,支持以下类型的uart:
supported_uarts = [
"crossover",
"crossover+uartbone",
"jtag_uart",
"sim",
"stub",
"stream",
"uartbone",
"usb_acm",
"serial(x)",
]
add_uartbone(name=”uartbone”, uart_name=”serial”, clk_freq=None, baudrate=115200, cd=”sys”)
不太清除其功能,应该是UART到Wishbone的转化器,可以通过串口来访问Wishbone总线;
-
add_jtagbone(name="jtagbone", chain=1)
不太清楚其功能,应该是UART到Wishbone的转换器,可以通过JTAG来访问Wishbone总线
add_sdram(self, name="sdram", phy=None, module=None, origin=None, size=None,
with_bist = False,
with_soc_interconnect = True,
l2_cache_size = 8192,
l2_cache_min_data_width = 128,
l2_cache_reverse = False,
l2_cache_full_memory_we = True,
**kwargs)
name
:模块名称;
-
phy
:SDRAM的物理接口,例如s7ddrphy.K7DDRPHY
; -
module
:具体的DRAM芯片型号所对应的模块,例如MT41J256M16
; -
origin
:主内存的起始地址,首先会使用类成员mem_map
中main_ram
键所对应的值,如果没有就使用该值; -
size
:SDRAM的大小,计算如代码所示:# Compute/Check SDRAM size. module就是参数module sdram_size = 2**(module.geom_settings.bankbits + module.geom_settings.rowbits + module.geom_settings.colbits)*phy.settings.nranks*phy.settings.databits//8 if size is not None: sdram_size = min(sdram_size, size) #从参数size和计算获得的sdram_size中选择较小值
-
with_bist
:bist即为Built-inSelfTest,在片内在加一些逻辑,使得片外DDR SDRAM能脱离ATE机台测试,并且有输出响应来判断其测试结果; -
with_soc_interconnect
:如果为False,则DDR不会连接到SoC; -
其余参数用于控制在系统总线和DRAM之间创建缓存;
-
add_ethernet(self, name="ethmac", phy=None, phy_cd="eth", dynamic_ip=False, software_debug=False, data_width = 8, nrxslots = 2, rxslots_read_only = True, ntxslots = 2, txslots_write_only = False, with_timestamp = False, with_timing_constraints = True):
name
:模块名 -
phy
:一般只需要指定该参数,其类型可能为LiteEthPHYRGMII
等; -
phy_cd:是一个字符串,网卡的时钟域,默认为”eth”;该参数的作用是,当参数
data_width
不等于32时,会将MAC的时钟域——eth_tx/eth_rx,修改为phy_cd + _tx“
和phy_cd + "_rx"
;一般不会设置data_width
参数,所以一般会执行该修改操作; -
dynamic_ip
:顾名思义,使用动态IP; -
software_debug
:不清楚作用,可能是启用UDP进行DEBUG的功能;
注意,从顶层应用来看,目前官方仅支持添加
RGMII
接口的以太网,不支持SGMII
接口(VC707就是该接口);理论上可以自己定义一个SGMII
的模块,从add_ethernet
的方法可以看出,该模块必须为LiteEthPHYModel
的子类,有需要的可以自己研究。
-
add_etherbone(self, name="etherbone", phy=None, phy_cd="eth", data_width=8, mac_address = 0x10e2d5000000, ip_address = "192.168.1.50", arp_entries = 1, udp_port = 1234, buffer_depth = 16, with_ip_broadcast = True, with_timing_constraints = True, with_ethmac = False):
创建一个UDP以太网IP核,使得可以通过以太网来访问Wishbone总线。
-
add_spi_flash(name="spiflash", mode="4x", clk_freq=None, module=None, phy=None, rate="1:1", software_debug=False, **kwargs)
添加一个SPI接口的FLASH:
-
name
:模块名; -
mode
:只能是["1x", "4x"]
; -
clk_freq
:如果为None,则会自动使用sys_clk_freq
的值; -
module
:芯片型号名称; -
phy
:SPI的物理接口,如果为None,则会自动创建; -
rate
:速度,支持1:1和1:2;assert rate in ["1:1", "1:2"]
;
-
add_spi_sdcard(name="spisdcard", spi_clk_freq=400e3, with_tristate=False, software_debug=False)
添加一个SPI接口的SDCard:
-
name
:该名称将用于从platfrom中请求相关引脚,即该字段需要和Platform中的定义相对应; -
spi_clk_freq
:SPImaster的工作时钟; -
with_tristate
:可选,是否使用三态门;
-
add_sdcard(name="sdcard", sdcard_name="sdcard", mode="read+write", use_emulator=False, software_debug=False)
添加一个SDCard:
-
name
:模块名称,可随意; -
sdcard_name
:用于从platform中请求相关的引脚,即该字段需要和Platform中的定义相对应; -
mode
:支持["read", "write", "read+write"]
; -
use_emulator
:如果是仿真的话,就不需要根据sdcard_name
请求引脚了,会自动创建一个SD卡的仿真模块;
-
add_sata(name="sata", phy=None, mode="read+write", with_identify=True)
添加SATA设备:
-
name
:模块名,可随意 -
phy
:物理接口模块; -
mode
:支持["read", "write", "read+write"]
; -
with_identify
:添加标识模块; - 12.
add_pcie(name="pcie", phy=None, ndmas=0, max_pending_requests=8, address_width=32, data_width=None,
with_dma_buffering = True, dma_buffering_depth=1024,
with_dma_loopback = True,
with_dma_synchronizer = False,
with_dma_monitor = False,
with_dma_status = False,
with_msi = True, msi_type="msi", msi_width=32,
with_ptm = False,
):
name
:模块名,可随意;
-
phy
:例如S7PCIEPHY
类,由LiteX提供; -
ndmas
:DMA的通道数量; -
with_msi
:消息中断机制;如果ndmas
不为0,则该选项必须设置为True;
-
add_video_colorbars(self, name="video_colorbars", phy=None, timings="800x600@60Hz", clock_domain="sys") add_video_terminal(self, name="video_terminal", phy=None, timings="800x600@60Hz", clock_domain="sys") add_video_framebuffer(self, name="video_framebuffer", phy=None, timings="800x600@60Hz", clock_domain="sys", format="rgb888"
视频相关的功能,不太明白。
五、SoCCore
5.1 类成员
# Default register/interrupt/memory mappings (can be redefined by user)
csr_map = {}
interrupt_map = {}
mem_map = {
"rom": 0x00000000,
"sram": 0x01000000,
"main_ram": 0x40000000,
}
其中mem_map
在其父类SoC
中就存在,只是为空。
5.2 构造器函数
def __init__(self, platform, clk_freq,
# Bus parameters
bus_standard = "wishbone",
bus_data_width = 32,
bus_address_width = 32,
bus_timeout = 1e6,
bus_bursting = False,
bus_interconnect = "shared",
# CPU parameters
cpu_type = "vexriscv",
cpu_reset_address = None,
cpu_variant = None,
cpu_cfu = None,
# CFU parameters
cfu_filename = None,
# ROM parameters
integrated_rom_size = 0,
integrated_rom_mode = "rx",
integrated_rom_init = [],
# SRAM parameters
integrated_sram_size = 0x2000,
integrated_sram_init = [],
# MAIN_RAM parameters
integrated_main_ram_size = 0,
integrated_main_ram_init = [],
# CSR parameters
csr_data_width = 32,
csr_address_width = 14,
csr_paging = 0x800,
csr_ordering = "big",
# Interrupt parameters
irq_n_irqs = 32,
# Identifier parameters
ident = "",
ident_version = False,
# UART parameters
with_uart = True,
uart_name = "serial",
uart_baudrate = 115200,
uart_fifo_depth = 16,
# Timer parameters
with_timer = True,
timer_uptime = False,
# Controller parameters
with_ctrl = True,
# JTAGBone
with_jtagbone = False,
jtagbone_chain = 1,
# UARTBone
with_uartbone = False,
# Others
**kwargs):
参数的具体含义看上面的代码就基本上能清楚,在该构造器函数中,调用了其父类LiteXSoC
的构造器函数。
5.3 类方法
-
add_csr(csr_name, csr_id=None, use_loc_if_exists=False)
实际上是调用了SoCCSRHandler
类的add
方法;添加CSR寄存器:
-
csr_name
:字符串; -
csr_id
:Int数字了;
-
initialize_rom(data)
实际上是调用了父类SoC
的init_rom
方法:init_rom(name="rom", contents=data)
。
-
def add_memory_region(self, name, origin, length, type="cached"): self.bus.add_region(name, SoCRegion(origin=origin, size=length, cached="cached" in type, linker="linker" in type) )
可以看出,实际上是调用了
SoCBusHandler
类的add_region
方法。 -
def add_csr_region(self, name, origin, busword, obj): self.csr_regions[name] = SoCCSRRegion(origin, busword, obj)
实际上是将父类
SoC
的参数csr_regions
添加了一个元素;
没有回复内容