## 总线(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) ```