Spinal 时钟域

时钟域的例化和管理通常发生在top level,时钟信号和复位信号的互联在顶层或者次顶层。

Spinal中提供了ClockDomain类来建模和管理不同的时钟域。

一个系统如下:

https://wswslzp.github.io/2022/03/04/spinal/clockdomain/clockdomain.png

系统内部包含一个外部时钟和三个内部时钟域。外部时钟域,即时钟源在片外,比如片外晶振,其产生的时钟信号通过IO pad连入chip,作为片内PLL的时钟输入,或者直接用。内部时钟域则是时钟源在片内产生的,比如PLL产生的时钟信号。

时钟域的例化

外部时钟域

1
2
// 例化一个前缀为“ref”的外部时钟域
val ref_clk_dom1 = ClockDomain.external(name = "ref")

如上,例化了一个外部时钟域。它会在模块的顶层产生对应的前缀的时钟信号和复位信号,作为chip的输入端口。我们可以直接使用ClockingArea来给我们的设计定义为这一时钟域,也可以使用 mapClockDomain(<ext_clk_dom>, clock=<driven_clk>, reset = <driven_reset>) 来让外部时钟域定义的时钟信号和复位信号,驱动IP定义的时钟信号和复位信号。

1
2
3
4
5
6
7
8
9
10
11
val iopll = IOPLL()
val por = POR()

// 不能直接调用外部时钟域的clock、reset去驱动内部的时钟,只能通过mapClockDomain的方法
iopll.mapClockDomain(ref_clk_dom1, clock = iopll.refclk) // OK
iopll.refclk := ref_clk_dom1.clock // ERROR!

// 或者使用 ClockingArea 包住用户的逻辑
val ref_clk_area = new ClockingArea(ref_clk_dom1){
...
}

内部时钟域

1
2
3
4
5
6
// 例化一个前缀为“sys”的内部时钟域
val sys_clk_dom1 = ClockDomain.internal(name = "sys")

// 将内部时钟源和内部时钟域绑定起来
sys_clk_dom1.clock := iopll.outclk0
sys_clk_dom1.reset := por.ninit_done

与外部时钟域不同,内部时钟域的时钟信号和复位信号都由chip内部产生,需要用户自己定义内部时钟源和内部时钟域的连接关系。

它的使用也和外部时钟域类似,主要也是两种:

  • 使用 mapClockDomain 函数,将时钟域和IP的时钟域绑定
  • 使用 ClockingArea,将时钟域和用户逻辑绑定

时钟域的绑定

Component的类内自带一个默认的 clockDomain ,其自动绑定到下面的时序单元。

通过上述的方法例化的时钟域,类似于入栈,压在默认时钟域上方,这些时钟域对应的 ClockingArea 中的用户逻辑,包括 ComponentBlackBox 都会使用相应的栈顶的时钟域而不是栈底的时钟域。

用户逻辑的绑定

两种方式,一种直接将逻辑放在对应的时钟域内:

1
2
3
4
val aclk = ClockDomain.external("a")
aclk {
// some logic here
}

缺点在于,内部逻辑是匿名的,无法被外部访问。声明只能都放在外面。适用于toplevel的连接。优点是简洁,不易产生cdc问题。

另外一种,声明一个 ClockingArea ,包住一个时钟域。随后逻辑放在Area内部。外面的逻辑可以直接访问内部逻辑。缺点是可能有cdc问题(人为失误)。另外Spinal提供预设的三种Clocking Area:

  • SlowArea 分频时钟域,该Area下的时钟域是当前时钟域的一个整数分频
  • ResetArea 复位域,该Area下的时钟域与当前时钟域共享一个时钟,但是引入新的复位信号。原复位信号是否起作用,可以选择, cumulative 为true则起作用
  • ClockEnableArea 门控时钟域,该Area下的时钟共享当前时钟域的时钟,并引入一个新的信号作为门控信号。

IP的绑定

通过 BlackBox 的方法: mapClockDomainmapCurrentClockDomain 。传参有:

  • clockDomain: 用作驱动的时钟域(mapCurrentClockDomain 没有这一参数,它使用的就是当前时钟域,即IP被例化的位置所拥有的时钟域)
  • clock: 被驱动的时钟信号
  • reset:被驱动的复位信号
  • enable:被驱动的时钟门控信号