如何通过原SystemVerilog数组索引从转换后数组获取可综合对应数据?
问题:基于原数组索引规则访问转换后的固定位宽SystemVerilog数组
背景
原数组定义(元素位宽和数量可变):
reg [49:0] wvu[0:63] = { 50'b00001111111101100111101111101010000010000000110011, 50'b00000000000000000000000000000000000000000000000000, 50'b00000000000001000000100100011111110001101001111010, //... 50'b01111111111111111111111111111111011101111111111111 };
为避免修改位宽,转换为固定32位宽的数组(两者所有元素拼接后得到的总寄存器完全一致):
reg [31:0] wvu_prime [0:100] = { 32'b00001111111101100111101111101010, 32'b00001000000011001100000000000000, 32'b00000000000000000000000000000000, 32'b00000000000000000100000010010001, 32'b11111100011010011110100000000000, //... 32'b00000000000000011111111111111111, 32'b11111111111111011101111111111111 };
需求:通过原数组的wvu[x][y:z]索引规则,从wvu_prime中获取对应数据,且实现方案可综合。
解决方案
核心思路是将原数组的索引转换为全局位位置,再映射到转换后数组的索引和位位置,最终通过组合逻辑拼接数据。
1. 定义参数(编译时常量)
parameter ORIG_WIDTH = 50; // 原数组元素位宽 parameter ORIG_DEPTH = 64; // 原数组元素个数 parameter PRIME_WIDTH = 32; // 转换后数组元素位宽 localparam TOTAL_BITS = ORIG_DEPTH * ORIG_WIDTH; localparam PRIME_DEPTH = (TOTAL_BITS + PRIME_WIDTH - 1) / PRIME_WIDTH; // 向上取整计算转换后数组深度
2. 索引映射逻辑
对于原数组的wvu[x][y:z](假设y >= z,即高位到低位):
- 计算全局位位置:原数组第x个元素的y/z位,对应总寄存器的全局位索引:
start_w = (ORIG_DEPTH - 1 - x) * ORIG_WIDTH + y; // 区间高位的全局索引 end_w = (ORIG_DEPTH - 1 - x) * ORIG_WIDTH + z; // 区间低位的全局索引 - 映射到转换后数组:将全局位索引转换为
wvu_prime的索引和元素内位位置:start_p = (TOTAL_BITS - 1 - start_w) / PRIME_WIDTH; // 转换后数组的起始元素索引 start_b = PRIME_WIDTH - 1 - ((TOTAL_BITS - 1 - start_w) % PRIME_WIDTH); // 起始元素内的高位索引 end_p = (TOTAL_BITS - 1 - end_w) / PRIME_WIDTH; // 转换后数组的结束元素索引 end_b = PRIME_WIDTH - 1 - ((TOTAL_BITS - 1 - end_w) % PRIME_WIDTH); // 结束元素内的低位索引
3. 可综合的组合逻辑实现
通过always @*块实现数据提取,分两种情况处理:
input int x, y, z; output reg [ORIG_WIDTH-1:0] wvu_out; int start_w, end_w; int start_p, start_b; int end_p, end_b; int num_bits; always @* begin num_bits = y - z + 1; wvu_out = '0; // 初始化输出 // 计算全局位索引 start_w = (ORIG_DEPTH - 1 - x) * ORIG_WIDTH + y; end_w = (ORIG_DEPTH - 1 - x) * ORIG_WIDTH + z; // 映射到wvu_prime的索引和位位置 start_p = (TOTAL_BITS - 1 - start_w) / PRIME_WIDTH; start_b = PRIME_WIDTH - 1 - ((TOTAL_BITS - 1 - start_w) % PRIME_WIDTH); end_p = (TOTAL_BITS - 1 - end_w) / PRIME_WIDTH; end_b = PRIME_WIDTH - 1 - ((TOTAL_BITS - 1 - end_w) % PRIME_WIDTH); // 情况1:目标区间在同一个wvu_prime元素内 if (start_p == end_p) begin wvu_out[num_bits-1:0] = wvu_prime[start_p][start_b:end_b]; end // 情况2:目标区间跨多个wvu_prime元素 else begin // 提取起始元素的低位部分 wvu_out[num_bits-1 : num_bits - (start_b + 1)] = wvu_prime[start_p][start_b:0]; // 提取中间完整的元素 for (int p = start_p + 1; p < end_p; p++) begin int offset = num_bits - (start_b + 1) - (p - start_p - 1)*PRIME_WIDTH; wvu_out[offset-1 : offset - PRIME_WIDTH] = wvu_prime[p]; end // 提取结束元素的高位部分 wvu_out[end_b : 0] = wvu_prime[end_p][31:end_b]; end end
4. 合法性检查(可选)
添加断言确保输入索引合法,避免越界:
assert (x >= 0 && x < ORIG_DEPTH) else $error("x out of range: %0d", x); assert (y >= 0 && y < ORIG_WIDTH) else $error("y out of range: %0d", y); assert (z >= 0 && z < ORIG_WIDTH) else $error("z out of range: %0d", z); assert (y >= z) else $error("y must be >= z, got y=%0d, z=%0d", y, z);
关键说明
- 所有参数必须是编译时常量,确保综合工具能展开逻辑。
- 跨元素拼接的逻辑会被综合为多路选择器和拼接电路,无动态内存分配,符合可综合要求。
- 总位宽
TOTAL_BITS过大时,避免使用临时总向量存储全部数据,采用逐段拼接方式节省资源。
内容的提问来源于stack exchange,提问作者Roy Meijer
相关产品推荐
相关产品推荐

