【SpinalHDL快速入门】4.5、复合类型之Bundle-LMLPHP

1.1、描述

Bundle是一种复合类型,它定义了一组命名信号(任何SpinalHDL基本类型)在一个名称下。

Bundle可用于建模数据结构、总线和接口

1.2、声明

声明一个 bundle 的语法如下:

case class myBundle extends Bundle {
	val bundleItem0 = AnyType
	val bundleItem1 = AnyType
	val bundleItemN = AnyType
}
case class Color(channelWidth: Int) extends Bundle {
	val r, g, b = UInt(channelWidth bits)
}

例如,一个包含Color的Bundle可以被定义为

1.2.1、条件信号(Conditional signals)

Bundle中的信号可以有条件地定义。除非dataWidth大于0,否则在展开的myBundle中将没有数据信号,如下面的示例所示。

case class myBundle(dataWidth: Int) extends Bundle {
	val data = (dataWidth > 0) generate (UInt(dataWidth bits))
}

1.3、运算符

Bundle类型支持以下运算符:

1.3.1、比较(Comparison)

【SpinalHDL快速入门】4.5、复合类型之Bundle-LMLPHP

val color1 = Color(8)
color1.r := 0
color1.g := 0
color1.b := 0

val color2 = Color(8)
color2.r := 0
color2.g := 0
color2.b := 0

myBool := color1 === color2

1.3.2、类型转换(Type cast)

【SpinalHDL快速入门】4.5、复合类型之Bundle-LMLPHP

val color1 = Color(8)
val myBits := color1.asBits

Bundle的元素将按照定义的顺序映射到其位置。因此,color1中的r将占用myBits(LSB)的0到8位,然后是g和b。

1.3.3、将比特转换回 Bundle

.assignFromBits 运算符可以被视为 .asBits 的反向操作。

【SpinalHDL快速入门】4.5、复合类型之Bundle-LMLPHP

以下示例将名为CommonDataBus的Bundle保存到循环缓冲区(第三方内存)中,稍后读取Bits并将其转换回CommonDataBus格式。

【SpinalHDL快速入门】4.5、复合类型之Bundle-LMLPHP

case class TestBundle () extends Component {
	val io = new Bundle {
		val we 		= in Bool()
		val addrWr 	= in UInt (7 bits)
		val dataIn 	= slave (CommonDataBus())
		val addrRd 	= in UInt (7 bits)
		val dataOut = master (CommonDataBus())
	}
	val mm = Ram3rdParty_1w_1rs (	G_DATA_WIDTH = io.dataIn.getBitsWidth,
									G_ADDR_WIDTH = io.addrWr.getBitsWidth,
									G_VENDOR 	 = "Intel_Arria10_M20K")
	mm.io.clk_in := clockDomain.readClockWire
	mm.io.clk_out := clockDomain.readClockWire
	
	mm.io.we := io.we
	mm.io.addr_wr := io.addrWr.asBits
	mm.io.d := io.dataIn.asBits
	
	mm.io.addr_rd := io.addrRd.asBits
	io.dataOut.assignFromBits(mm.io.q)
}

1.4、IO元素方向

当您在组件的IO定义中定义Bundle时,需要指定其方向。

1.4.1、in/out

如果您的Bundle中所有元素都朝着同一个方向,您可以使用in(MyBundle())或out(MyBundle())。

例如:

val io = new Bundle {
	val input  = in (Color(8))
	val output = out(Color(8))
}

1.4.2、master/slave

如果您的接口遵循master/slave拓扑结构,可以使用IMasterSlave特性。然后,您需要实现函数def asMaster(): Unit设置每个元素相对于master的方向。然后,在IO定义中可以使用master(MyBundle())slave(MyBundle())语法。

有一些被定义为toXXX的函数,例如Flow类的toStream方法。这些函数通常由master调用。此外,fromXXX函数是为Slave设计的。通常情况下,Master可用的功能比Slave多。

case class HandShake(payloadWidth: Int) extends Bundle with IMasterSlave {
	val valid = Bool()
	val ready = Bool()
	val payload = Bits(payloadWidth bits)
	
	// 你需要实现asMaster函数。
	// 这个函数应该从master的角度设置每个信号的方向
	override def asMaster(): Unit = {
		out(valid, payload)
		in(ready)
	}
}

val io = new Bundle {
	val input = slave(HandShake(8))
	val output = master(HandShake(8))
}
06-07 14:45