SpinalHDL(三) 一行代码生成Soc系统

SpinalHDL(三) 一行代码生成Soc系统

如何生成一个Soc系统

(注:Soc系统本身是一个比较笼统的概念,有各种各样不同复杂程度的SOC系统,我们这里指的Soc是一个最小系统,带处理器,片上Mem,一些基本外设以及总线拓扑的基础框架)

在Spinal生成一个最小Soc系统只需要一行代码

1
2
import spinal.lib.soc.pinsec._
SpinalVerilog(new Pinsec(500 MHz))

即可生成一个完整的SOC系统,其中一个RISCV的处理器VexRiscv, 和AXI总线路由
以及APB桥。
pinsec-soc

没了,就这么屌

trump-no-more

如果需要定制,那么继续往下

如何定制Soc系统

定制CPU

1
2
3
4
5
6
7
8
9
10
11
12
13
14
val myCpuConfig = RiscvCoreConfig(
pcWidth = 32,
addrWidth = 32,
startAddress = 0x00000000,
regFileReadyKind = sync,
branchPrediction = dynamic,
bypassExecute0 = true,
bypassExecute1 = true,
bypassWriteBack = true,
bypassWriteBackBuffer = true,
collapseBubble = false,
fastFetchCmdPcCalculation = true,
dynamicBranchPredictorCacheSizeLog2 = 7
)

插件式扩展CPU, 除了已有的扩展,你可以添加自己的扩展, 比如浮点,矢量处理

1
2
3
4
5
myCpuConfig.add(new MulExtension)
myCpuConfig.add(new DivExtension)
myCpuConfig.add(new BarrelShifterFullExtension)
myCpuConfig.add(new MyFloatExtension)
myCpuConfig.add(new MyVectorExtension)

iCache 配置

1
2
3
4
5
6
7
8
9
val myiCacheConfig = InstructionCacheConfig(
cacheSize = 4096,
bytePerLine = 32,
wayCount = 1,
wrappedMemAccess = true,
addressWidth = 32,
cpuDataWidth = 32,
memDataWidth = 32
)

更新PinsecSOC配置

1
2
3
4
5
6
7
8
9
10
11
12
val mySocConfig = PinsecConfig(
axiFrequency = 100 MHz,
onChipRamSize = 4 KiB,
sdramLayout = IS42x320D.layout,
sdramTimings = IS42x320D.timingGrade7,
cpu = myCpuConfig,
iCache = myiCacheConfig)
wrappedMemAccess = true,
addressWidth = 32,
cpuDataWidth = 32,
memDataWidth = 32
)

resoc
重新生成, 得到全新定制的SOC系统

1
SpinalVerilog(new Pinsec(mySocConfig))

这个一个完整的例子,可以看得出SpinalHDL的参数设计非常合理,层层设计,每一个功能模块有自己的参数伴侣,
所有的配置,模块的扩展,全部放在参数里。

RocketChip隐式参数p恐怕要把你绕晕,这也是Chisel常备被吐槽的问题之一。
Spinal完全不存在这样的问题,即便是你第一次接触,也基本上不存在什么阅读障碍,
完整的Pinsec源码只有300行,能够完整的描述Soc顶层的互联信息,表达能力实属强大,源码参见Pinsec.scala

当然实际工程上的Soc系统不会这么简单,但是这个框架也不失一般性,即便是一个复杂的Soc系统完全可以以这种方式去管理。往往一个公司会有多个系列的芯片,一个系列的基本架构是有延续性,一个系列可以维护一个Soc-Top,利用参数化来管理。不同系列之间也有共性,比如像总线路由这种基础框架SpinalHDL都有现漂亮的实现。相比原来的Verilog代码,集成工作量几乎忽略不计,而且可以设置各种检查规则,更不容易犯错。

评论