Verilog 典型电路(零):向量 1 检测

1 问题描述

给定位宽为 N 的向量,检测其从 高位到低位(MSB) 第一个 1 出现的位置,向量为 0 时输出 0。示例如下

输入向量 输出向量
8’b0010_1101 8’b0010_0000
8’b0100_0000 8’b0100_0000
8’b0000_0000 8’b0000_0000

下述模块均采用 组合逻辑 实现,例化参数如下

参数 描述
VECTOR_WIDTH 向量位宽

端口定义如下

端口 方向 类型 说明
seq IN [VECTOR_WIDTH-1:0] 输入向量
pos OUT [VECTOR_WIDTH-1:0] 输出位置

1.1 仿真验证

由于不同方法所设计的模块端口完全相同,此处通过修改 VECTOR_DETECT_MODE 参数完成对不同模块的仿真测试,仿真文件如下

`timescale 1ns / 1ns

`define VECTOR_WIDTH 16
`define VECTOR_DETECT_MODE `VECTOR_DETECT_COMPL
`define VECTOR_DETECT_CASEZ 0
`define VECTOR_DETECT_DIVDE 1
`define VECTOR_DETECT_COMPL 2
`define VECTOR_DETECT_SHIFT_XOR 3

module vector_detect_tb;

    reg  [`VECTOR_WIDTH-1:0] seq;
    wire [`VECTOR_WIDTH-1:0] pos;

    generate
        if (`VECTOR_DETECT_MODE == `VECTOR_DETECT_CASEZ) begin
            vector_detect_casez vector_detect_casez_inst (
                .seq(seq),
                .pos(pos)
            );
        end else if (`VECTOR_DETECT_MODE == `VECTOR_DETECT_DIVDE) begin
            vector_detect_divide #(
                .VECTOR_WIDTH(`VECTOR_WIDTH)
            ) vector_detect_divde_inst (
                .seq(seq),
                .pos(pos)
            );
        end else if (`VECTOR_DETECT_MODE == `VECTOR_DETECT_COMPL) begin
            vector_detect_compl #(
                .VECTOR_WIDTH(`VECTOR_WIDTH)
            ) vector_detect_compl_inst (
                .seq(seq),
                .pos(pos)
            );
        end else if (`VECTOR_DETECT_MODE == `VECTOR_DETECT_SHIFT_XOR) begin
            vector_detect_shift_xor #(
                .VECTOR_WIDTH(`VECTOR_WIDTH)
            ) vector_detect_shift_xor_inst (
                .seq(seq),
                .pos(pos)
            );
        end
    endgenerate

    initial begin
        for (seq = 0; seq < ~0; seq = seq + 1'b1) begin
            #1;
        end
        #10 $stop;
    end

endmodule

注意:暴力破解法(VECTOR_DETECT_CASEZ)不支持参数化,因此修改 VECTOR_WIDTH 参数无效

1.2 性能测试

为对比不同模块的 资源占用时序性能,此处在所有模块上对位宽 16 的向量进行综合测试,所有模块均在 Artix-7 系列 XC7A100TFTG256-1 平台综合实现(采用 默认综合策略),顶层模块和约束如下

`define VECTOR_WIDTH 16
`define VECTOR_DETECT_MODE `VECTOR_DETECT_COMPL
`define VECTOR_DETECT_CASEZ 0
`define VECTOR_DETECT_DIVDE 1
`define VECTOR_DETECT_COMPL 2
`define VECTOR_DETECT_SHIFT_XOR 3

module vector_detect_top (
    input                          clk,
    input                          rst_n,
    output reg [`VECTOR_WIDTH-1:0] pos
);

    reg  [`VECTOR_WIDTH-1:0] seq;
    wire [`VECTOR_WIDTH-1:0] pos_w;

    generate
        if (`VECTOR_DETECT_MODE == `VECTOR_DETECT_CASEZ) begin
            vector_detect_casez vector_detect_casez_inst (
                .seq(seq),
                .pos(pos_w)
            );
        end else if (`VECTOR_DETECT_MODE == `VECTOR_DETECT_DIVDE) begin
            vector_detect_divide #(
                .VECTOR_WIDTH(`VECTOR_WIDTH)
            ) vector_detect_divde_inst (
                .seq(seq),
                .pos(pos_w)
            );
        end else if (`VECTOR_DETECT_MODE == `VECTOR_DETECT_COMPL) begin
            vector_detect_compl #(
                .VECTOR_WIDTH(`VECTOR_WIDTH)
            ) vector_detect_compl_inst (
                .seq(seq),
                .pos(pos_w)
            );
        end else if (`VECTOR_DETECT_MODE == `VECTOR_DETECT_SHIFT_XOR) begin
            vector_detect_shift_xor #(
                .VECTOR_WIDTH(`VECTOR_WIDTH)
            ) vector_detect_shift_xor_inst (
                .seq(seq),
                .pos(pos_w)
            );
        end
    endgenerate

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            seq <= 'b0;
        end else begin
            seq <= seq + 1'b1;
        end
    end

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            pos <= 'b0;
        end else begin
            pos <= pos_w;
        end
    end
    
endmodule
create_clock -period 3.000 -name clk [get_ports clk]

不同模块的综合结果如下,综合考虑灵活性、资源占用和时序性能,推荐使用 二分法

FMAX LUT WNS TNS 参数化 资源占用 工作频率
穷举法 435 MHz 20 0.057 ns 0.156 ns ⭐⭐ ⭐⭐
二分法 455 MHz 19 0.006 ns 0.203 ns ⭐⭐⭐ ⭐⭐⭐
独热加法 345 MHz 33 0.007 ns 0.193 ns
错位相或法 435 MHz 19 0.045 ns 0.216 ns ⭐⭐⭐ ⭐⭐
  1. FMAX 即最大工作频率,由满足 WNS 和 TNS 均大于 0 条件的最小时钟周期换算而来
  2. 为了满足时序要求,综合工具往往会通过插入寄存器等方法对模块进行优化,因此同一模块不同工作频率下的资源占用不尽相同。此处资源数据为 FMAX 工作频率下 顶层文件 的资源占用,仅供参考
  3. 不同模块 FMAX 相同时 不能 通过 WNS 和 TNS 比较性能,因为 Vivado 采用 尽力而为 的综合策略,即以满足时序要求为目标,不追求宽裕的 WNS 和 TNS

2 模块实现

本文提供了常用的 穷举法二分法独热加法错位相减法 四种向量 1 检测思路和具体实现,实际上向量 1 检测的思路还有很多,比如遍历向量所有比特位

generate
    for (genvar i = 0; i < VECTOR_WIDTH - 1; i = i + 1) begin
        assign pos[i] = seq[VECTOR_WIDTH-1:i+1] ? 1'b0 : seq[i];
    end
endgenerate

assign pos[VECTOR_WIDTH-1] = seq[VECTOR_WIDTH-1];

或者使用 if-else

if (seq[15]) begin
	pos = 16'b1000_0000_0000_0000;
end
else if (seq[14]) begin
	pos = 16'b0100_0000_0000_0000;
end
else if ...

上述方法或与本文所提方法 思路相似,或 性能和资源占用 没有优势,因此没有列出

2.1 穷举法

简洁明了,无需多言

module vector_detect_casez (
    input      [15:0] seq,
    output reg [15:0] pos
);

    always @(*) begin
        casex (seq)
            16'b1xxx_xxxx_xxxx_xxxx: pos = 16'b1000_0000_0000_0000;
            16'bx1xx_xxxx_xxxx_xxxx: pos = 16'b0100_0000_0000_0000;
            16'bxx1x_xxxx_xxxx_xxxx: pos = 16'b0010_0000_0000_0000;
            16'bxxx1_xxxx_xxxx_xxxx: pos = 16'b0001_0000_0000_0000;
            16'bxxxx_1xxx_xxxx_xxxx: pos = 16'b0000_1000_0000_0000;
            16'bxxxx_x1xx_xxxx_xxxx: pos = 16'b0000_0100_0000_0000;
            16'bxxxx_xx1x_xxxx_xxxx: pos = 16'b0000_0010_0000_0000;
            16'bxxxx_xx
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值