## 总线(bus)
### 一、AHB-Lite3
1. 配置与实例化(Configuration and instanciation)
首先, 每次创建AHB-Lite3总线时, 都需要一个配置对象。这个配置对象是一个`AhbLite3Config`, 有以下参数:
| 参数名 | 类型 | 默认值 | 描述 |
| :----------: | :---: | :----: | :-------------------: |
| addressWidth | Int | | HADDR的位宽(字节粒度) |
| dataWidth | Int | | HWDATA和HRDATA的位宽 |
简而言之, 在SpinalHDL库中AHB-Lite3总线是如下定义的:
```Scala
case class AhbLite3(config: AhbLite3Config) extends Bundle with IMasterSlave{
// 地址和控制
val HADDR = UInt(config.addressWidth bits)
val HSEL = Bool()
val HREADY = Bool()
val HWRITE = Bool()
val HSIZE = Bits(3 bits)
val HBURST = Bits(3 bits)
val HPROT = Bits(4 bits)
val HTRANS = Bits(2 bits)
val HMASTLOCK = Bool()
// 数据
val HWDATA = Bits(config.dataWidth bits)
val HRDATA = Bits(config.dataWidth bits)
// 传输回答
val HREADYOUT = Bool()
val HRESP = Bool()
override def asMaster(): Unit = {
out(HADDR,HWRITE,HSIZE,HBURST,HPROT,HTRANS,HMASTLOCK,HWDATA,HREADY,HSEL)
in(HREADYOUT,HRESP,HRDATA)
}
}
```
简单的使用样例:
```Scala
val ahbConfig = AhbLite3Config(
addressWidth = 12,
dataWidth = 32
)
val ahbX = AhbLite3(ahbConfig)
val ahbY = AhbLite3(ahbConfig)
when(ahbY.HSEL){
//...
}
```
2. 变式(Variations)
有一个AhbLite3Master变体。唯一的区别是没有`HREADYOUT`信号。当互连线和从端口使用`AhbLite3`时, 这个变式应该只被master使用。
### 二、Apb3
1. 简介
AMBA3-APB总线通常用于连接低带宽外设。
2. 配置和实例化
首先, 每次创建APB3总线时, 都需要一个配置对象。这个配置对象是`Apb3Config`, 有以下参数:
| 参数名 | 类型 | 默认值 | 描述 |
| :-----------: | :-----: | :----: | :-------------------: |
| addressWidth | Int | | HADDR的位宽(字节粒度) |
| dataWidth | Int | | PWDATA和PRDATA的位宽 |
| selWidth | Int | 1 | PSEL的位宽 |
| useSlaveError | Boolean | false | 指定PSLVERROR |
简而言之, APB3总线在SpinalHDL库中定义的方式如下:
```Scala
case class Apb3(config: Apb3Config) extends Bundle with IMasterSlave {
val PADDR = UInt(config.addressWidth bits)
val PSEL = Bits(config.selWidth bits)
val PENABLE = Bool()
val PREADY = Bool()
val PWRITE = Bool()
val PWDATA = Bits(config.dataWidth bits)
val PRDATA = Bits(config.dataWidth bits)
val PSLVERROR = if(config.useSlaveError) Bool() else null
//...
}
```
简单的使用样例:
```Scala
val apbConfig = Apb3Config(
addressWidth = 12,
dataWidth = 32
)
val apbX = Apb3(apbConfig)
val apbY = Apb3(apbConfig)
when(apbY.PENABLE){
//...
}
```
3. 函数和运算(Functions and operators)
| 参数名 | 返回 | 描述 |
| :----: | :---: | :------------------------: |
| X >> Y | | 连接X到Y。Y的地址可以小于X |
| X << Y | | 做与>>相反的操作 |
### 三、Axi4
1. 简介
AXI4是ARM定义的高带宽总线
2. 配置和实例化
首先, 每次创建AXI4总线时, 都需要一个配置对象。这个配置对象是一个`Axi4Config`, 它有以下参数:
注意:useXXX 指定总线是否有 XXX 信号。
| 参数名 | 类型 | 默认值 |
| :----------: | :-----: | :----: |
| addressWidth | Int | |
| dataWidth | Int | |
| idWidth | Int | |
| userWidth | Int | |
| useld | Boolean | true |
| useRegion | Boolean | true |
| useBurst | Boolean | true |
| useLock | Boolean | true |
| useCache | Boolean | true |
| useSize | Boolean | true |
| useQos | Boolean | true |
| useLen | Boolean | true |
| useLast | Boolean | true |
| useResp | Boolean | true |
| useProt | Boolean | true |
| useStrb | Boolean | true |
| useUser | Boolean | false |
简而言之, SpinalHDL库中定义AXI4总线的方式如下:
```Scala
case class Axi4(config: Axi4Config) extends Bundle with IMasterSlave{
val aw = Stream(Axi4Aw(config))
val w = Stream(Axi4W(config))
val b = Stream(Axi4B(config))
val ar = Stream(Axi4Ar(config))
val r = Stream(Axi4R(config))
override def asMaster(): Unit = {
master(ar,aw,w)
slave(r,b)
}
}
```
简单的使用样例:
```Scala
val axiConfig = Axi4Config(
addressWidth = 32,
dataWidth = 32,
idWidth = 4
)
val axiX = Axi4(axiConfig)
val axiY = Axi4(axiConfig)
when(axiY.aw.valid){
//...
}
```
3. 变式
Axi4总线有三个变式:
| 类型 | 述 |
| :-----------: :------------------------------------------------------------------------------------------------------------------------------------------------------------- ---------------------------------------------: |
| Axi4ReadOnly | 只有AR和R通 在 |
| Axi4WriteOnly | 只有AW、W和B通 在 |
| Axi4Shared | 这种变式是该库的首创。
它使用4个通道, W, B,R, 还有一个名为AWR的新通道。
AWR通道可以用来传输AR和AW事务。要分离它们, 需要一个信号`write`。
这种Axi4Shared变体的优点是使用更少的面积, 尤其是在互连方面。 |
4. 函数与操作
| 参数名 | 返回 | 描述 |
| :-----------: | :-----------: | :--------------------------------------------------------------------------: |
| X >> Y | | 连接X到Y。能够像AXI4规范中指定的那样推断默认值, 并以安全的方式调整一些宽度。 |
| X << Y | | 做与>>相反的操作 |
| X.toWriteOnly | Axi4WriteOnly | 返回一个由X驱动的Axi4WriteOnly总线 |
| X.toReadOnly | Axi4ReadOnly | 返回一个由X驱动的Axi4ReadOnly总线 |
### 四、AvalonMM
1. 简介
AvalonMM总线非常适合FPGA。它非常灵活:
+ 与APB一样简单
+ 在许多需要带宽的应用程序中, 比AHB表现更好, 因为AvalonMM有一种模式, 可以从命令中解耦读响应(减少延迟读延迟的影响)。
+ 性能不如AXI, 但使用的面积少得多(读写命令使用相同的握手通道。主端口不需要存储挂起请求的地址以避免读/写风险)
2. 配置和实例化
AvalonMM Bundle有一个构造参数`AvalonMMConfig`。由于Avalon总线的灵活性, `AvalonMMConfig`可以作为许多配置元素。
```Scala
case class AvalonMMConfig( addressWidth : Int,
dataWidth : Int,
burstCountWidth : Int,
useByteEnable : Boolean,
useDebugAccess : Boolean,
useRead : Boolean,
useWrite : Boolean,
useResponse : Boolean,
useLock : Boolean,
useWaitRequestn : Boolean,
useReadDataValid : Boolean,
useBurstCount : Boolean,
//useEndOfPacket : Boolean,
addressUnits : AddressUnits = symbols,
burstCountUnits : AddressUnits = words,
burstOnBurstBoundariesOnly : Boolean = false,
constantBurstBehavior : Boolean = false,
holdTime : Int = 0,
linewrapBursts : Boolean = false,
maximumPendingReadTransactions : Int = 1,
maximumPendingWriteTransactions : Int = 0, // unlimited
readLatency : Int = 0,
readWaitTime : Int = 0,
setupTime : Int = 0,
writeWaitTime : Int = 0
)
```
这样的配置类也有一些函数:
| 函数名 | 返回 | 描述 |
| :----------------: | :------------: | :--------------------------------------: |
| getReadOnlyConfig | AvalonMMConfig | 返回一个类似的配置, 但禁用所有写入属性。 |
| getWriteOnlyConfig | AvalonMMConfig | 返回一个类似的配置, 但禁用所有读属性 |
这个配置对象也有一些函数来提供一些AvalonMMConfig模板:
| 函数名 | 返回 | 描述 |
| :---------------------------------------------: | :------------: | :--------------------------------------: |
| fixed(addressWidth,dataWidth,readLatency) | AvalonMMConfig | 返回一个具有固定读取时间的简单配置。 |
| pipelined(addressWidth,dataWidth) | AvalonMMConfig | 返回一个配置, 读取延迟可变 |
| bursted(addressWidth,dataWidth,burstCountWidth) | AvalonMMConfig | 返回一个具有可变延迟读取和突发功能的配置 |
```Scala
// 创建一个只写的AvalonMM配置, 具有突发能力和字节使能
val myAvalonConfig = AvalonMMConfig.bursted(
addressWidth = addressWidth,
dataWidth = memDataWidth,
burstCountWidth = log2Up(burstSize + 1)
).copy(
useByteEnable = true,
constantBurstBehavior = true,
burstOnBurstBoundariesOnly = true
).getWriteOnlyConfig
// 创建一个利用该配置的总线实例
val bus = AvalonMM(myAvalonConfig)
```