Vec

一、描述(Description)

Vec是定义了一组带有标号的信号的复合信号(基于SpinalHDL基础类别)

二、声明(Declaration)

声明向量的语法如下:

声明 描述
Vec(type: Data, size: Int) 创建一个能容纳sizedata类元素的向量
Vec(x, y, ...) 创建一个标号对应给定元素的向量, 这种方式支持混合元素宽度

Examples

//创建一个有两个有符号整型的向量
val myVecOfSInt = Vec(SInt(8 bits), 2)
myVecOfSInt(0) := 2
myVecOfSInt(1) := myVecOfSInt(0) + 3

//创建一个有三个不同类型元素的向量
val myVecOfMixedInt = Vec(UInt(3 bits), UInt(5 bits), UInt(8 bits))

val x, y, z = UInt(8 bits)
val myVecOf_xyz_ref = Vec(x, y, z)

//向量的迭代
for(element <- myVecOf_xyz_ref) {
    element := 0    //给所有元素赋值0
}

//向量Map映射
myVecOfMixedInt.map(_ := 0) //给所有元素赋值0

//给向量的第一个元素赋值3
myVecOf_xyz_ref(1) := 3

Verilog:

  wire       [7:0]    _zz_myVecOfSInt_1;
  wire       [7:0]    myVecOfSInt_0;
  wire       [7:0]    myVecOfSInt_1;
  wire       [2:0]    myVecOfMixedInt_0;
  wire       [4:0]    myVecOfMixedInt_1;
  wire       [7:0]    myVecOfMixedInt_2;
  wire       [7:0]    x;
  wire       [7:0]    y;
  wire       [7:0]    z;
  reg        [7:0]    counter;

  assign _zz_myVecOfSInt_1 = 8'h03;
  assign myVecOfSInt_0 = 8'h02;
  assign myVecOfSInt_1 = ($signed(myVecOfSInt_0) + $signed(_zz_myVecOfSInt_1));
  assign x = 8'h0;
  assign y = 8'h0;
  assign z = 8'h0;
  assign myVecOfMixedInt_0 = 3'b000;
  assign myVecOfMixedInt_1 = 5'h0;
  assign myVecOfMixedInt_2 = 8'h0;

三、操作符(Operators)

以下操作符是Vec类型所支持的:

  1. 比较操作(Comparison)

操作符 描述 返回类型
x===y 相等 Bool
x=/=y 不相等 Bool
//创建一个有两个有符号整型的向量
val vec2 = Vec(SInt(8 bits), 2)
val vec1 = Vec(SInt(8 bits), 2)

myBool := vec2 === vec1 //比较两个向量

Verilog:

wire       [7:0]    vec2_0;
wire       [7:0]    vec2_1;
wire       [7:0]    vec1_0;
wire       [7:0]    vec1_1;
wire                myBool;

assign myBool = (($signed(vec2_0) == $signed(vec1_0)) && ($signed(vec2_1) == $signed(vec1_1)));
  1. 类型转换(Type cast)

操作符 描述 返回类型
x.asBits 二进制转换为Bits Bits(w(x) bits)
//创建一个有两个有符号整型的向量
val vec1 = Vec(SInt(8 bits), 2)

myBits_16bits := vec1.asBits
  1. Misc

操作符 描述 返回类型
x.getBitsWidth 返回Vec的长度 Int
//创建一个有两个有符号整型的向量
val vec1 = Vec(SInt(8 bits), 2)

println(vec1.getBitsWidth)  //16

4. 库辅助函数(Lib Helper functions)

> 使用这些函数, 需要`import spinal.lib._`

<table border="1" class="docutils">
<thead>
<tr>
<th style="text-align: center;">操作符</th>
<th style="text-align: center;">描述</th>
<th style="text-align: center;">返回类型</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: center;">x.sCount(condition: T=&gt;Bool)</td>
<td style="text-align: center;">计算Vec中与给定条件相匹配的个数</td>
<td style="text-align: center;">UInt</td>
</tr>
<tr>
<td style="text-align: center;">x.sCount(value: T)</td>
<td style="text-align: center;">计算与给定值相等的个数</td>
<td style="text-align: center;">UInt</td>
</tr>
<tr>
<td style="text-align: center;">x.sExists(condition: T=&gt;Bool)</td>
<td style="text-align: center;">检查Vec中是否有匹配的条件</td>
<td style="text-align: center;">Bool</td>
</tr>
<tr>
<td style="text-align: center;">x.sContains(value: T)</td>
<td style="text-align: center;">检查Vec中是否有给定的值存在</td>
<td style="text-align: center;">Bool</td>
</tr>
<tr>
<td style="text-align: center;">x.sFindFirst(condition: T=&gt;Bool)</td>
<td style="text-align: center;">找到Vec中第一个与给定条件相匹配的元素, 返回那个元素的标号</td>
<td style="text-align: center;">UInt</td>
</tr>
<tr>
<td style="text-align: center;">x.reduceBalancedTree(op:(T, T)=&gt;T)</td>
<td style="text-align: center;">平衡化的归约函数, 能尽量减小生成电路的深度。<code>op</code>应该是可交换的且可结合的</td>
<td style="text-align: center;">T</td>
</tr>
<tr>
<td style="text-align: center;">x.shuffle(indexMapping: Int=&gt;Int)</td>
<td style="text-align: center;">用一个Map函数把旧索引映射到新索引上, 对Vec重组</td>
<td style="text-align: center;">Vec[T]</td>
</tr>
</tbody>
</table>

```Scala
import spinal.lib._

//创建有4个无符号整型的向量
val vec1 = Vec(UInt(8bits), 4)

//...向量在某些地方被赋值后

val c1: UInt = vec1.sCount(_ < 128)     //向量中有多少值小于128
val c2: UInt = vec1.sCount(0)           //向量中有多少0值

val b1: Bool = vec1.sExist(_ > 250)    //向量中有没有比250大的
val b2: Bool = vec1.sContains(0)        //向量中有没有0

val u1: UInt = vec1.sFindFirst(_ < 10)  //得到第一个比10小的元素的标号, 该函数在转化时有问题, 有待商榷
val u2: UInt = vec1.reduceBalancedTree(_ + _)   //向量求和

Verilog:

wire       [1:0]    _zz_c1;
wire       [1:0]    _zz_c1_1;
wire       [0:0]    _zz_c1_2;
wire       [2:0]    _zz_c1_3;
wire       [1:0]    _zz_c1_4;
wire       [1:0]    _zz_c1_5;
wire       [0:0]    _zz_c1_6;
wire       [1:0]    _zz_c2;
wire       [1:0]    _zz_c2_1;
wire       [0:0]    _zz_c2_2;
wire       [2:0]    _zz_c2_3;
wire       [1:0]    _zz_c2_4;
wire       [1:0]    _zz_c2_5;
wire       [0:0]    _zz_c2_6;
wire       [7:0]    _zz_u2;
wire       [7:0]    _zz_u2_1;
wire       [7:0]    vec1_0;
wire       [7:0]    vec1_1;
wire       [7:0]    vec1_2;
wire       [7:0]    vec1_3;
wire       [2:0]    c1;
wire       [2:0]    c2;
wire                b1;
wire                b2;
wire       [7:0]    u2;
reg        [7:0]    counter;

assign _zz_c1 = ({1'b0,(vec1_0 < 8'h80)} + _zz_c1_1);
assign _zz_c1_2 = (vec1_1 < 8'h80);
assign _zz_c1_1 = {1'd0, _zz_c1_2};
assign _zz_c1_4 = ({1'b0,(vec1_2 < 8'h80)} + _zz_c1_5);
assign _zz_c1_3 = {1'd0, _zz_c1_4};
assign _zz_c1_6 = (vec1_3 < 8'h80);
assign _zz_c1_5 = {1'd0, _zz_c1_6};
assign _zz_c2 = ({1'b0,(vec1_0 == 8'h0)} + _zz_c2_1);
assign _zz_c2_2 = (vec1_1 == 8'h0);
assign _zz_c2_1 = {1'd0, _zz_c2_2};
assign _zz_c2_4 = ({1'b0,(vec1_2 == 8'h0)} + _zz_c2_5);
assign _zz_c2_3 = {1'd0, _zz_c2_4};
assign _zz_c2_6 = (vec1_3 == 8'h0);
assign _zz_c2_5 = {1'd0, _zz_c2_6};
assign _zz_u2 = (vec1_0 + vec1_1);
assign _zz_u2_1 = (vec1_2 + vec1_3);
assign c1 = ({1'b0,_zz_c1} + _zz_c1_3);
assign c2 = ({1'b0,_zz_c2} + _zz_c2_3);
assign b1 = ((((1'b0 || (8'hfa < vec1_0)) || (8'hfa < vec1_1)) || (8'hfa < vec1_2)) || (8'hfa < vec1_3));
assign b2 = ((((1'b0 || (vec1_0 == 8'h0)) || (vec1_1 == 8'h0)) || (vec1_2 == 8'h0)) || (vec1_3 == 8'h0));
assign u2 = (_zz_u2 + _zz_u2_1);

备注:sXXX前缀用来与接受lambda函数作为参数的同名Scala函数的歧义