Verilog有符号数运算,四舍五入,饱和截位

该博客探讨了如何使用Verilog实现四舍五入和饱和截位的无符号整数运算。通过两个设计方案,详细展示了将有符号整数转换为无符号整数的过程,并提供了MATLAB的量化比较。内容包括模块定义、中间变量赋值和四舍五入判断,以及测试激励的生成和验证。
摘要由CSDN通过智能技术生成

参考文章【设计经验】5、Verilog对数据进行四舍五入(round)与饱和(saturation)截位

当前还有存疑,请大家指正

题目:
请用Verilog实现算法 Q = K * (D - 16),其中输入数据D和输出数据D和输出数据Q都是无符号8位整数(无符号,8位整数,0位小数),输入参数K的数值为13Q10(共13位,1位符号位,10位小数位),中间过程保留完整精度,最后四舍五入。
答案1

1.先按照参考文章得到有符号整数输出,然后变到无符号输出
在这里插入图片描述
assign Q = Q1 + 128;转成无符号数。

module DaHua_2021_17(
    input [7:0] D,
    input signed [12:0] K,//13Q10
    output [7:0] Q
    );
    
    wire signed [8:0] D_min_16;//9Q0
    wire signed [21:0] K_mul;//22Q10
    wire signed [12:0] rou_K_mul; //13Q0;
    wire cin;
    wire [13:0] un;
    wire signed [7:0] Q1;
    
    assign D_min_16 = D - 16;
    assign K_mul = K * D_min_16;
    
    assign cin = K_mul[21]? K_mul[9]&(|K_mul[8:0]) : K_mul[9];
    assign rou_K_mul = {K_mul[21],K_mul[21:10]} + cin;
    assign Q1 = (rou_K_mul[12:7] == 6'b111111 || rou_K_mul[12:7] == 6'b000000)? rou_K_mul[7:0]:{rou_K_mul[12],{7{!rou_K_mul[12]}}};
    assign Q = Q1 + 128;
endmodule

在这里插入图片描述

答案2
按照matlab函数
quan_U8Q0_pattern = quantizer(‘ufixed’,‘round’,‘saturate’,[8,0]),
s_U8Q0 = quantize(quan_U8Q0_pattern,s);的结果而来

module DaHua_2021_17(
    input [7:0] D,
    input signed [12:0] K,//13Q10
    output [7:0] Q
    );
    
    wire signed [8:0] D_min_16;//9Q0
    wire signed [21:0] K_mul;//22Q10
    wire signed [12:0] rou_K_mul; //13Q0;
    wire cin;
    wire [13:0] un;
    wire signed [8:0] Q1;
    
    assign D_min_16 = D - 16;
    assign K_mul = K * D_min_16;
    
    assign cin = K_mul[21]? K_mul[9]&(|K_mul[8:0]) : K_mul[9];
    assign rou_K_mul = {K_mul[21],K_mul[21:10]} + cin;
    assign Q1 = (rou_K_mul[12:8] == 5'b11111 || rou_K_mul[12:8] == 5'b00000)? rou_K_mul[8:0]:{rou_K_mul[12],{8{!rou_K_mul[12]}}};
    assign Q = !Q1[8]? Q1[7:0]:0;
endmodule

对比s_U8Q0与Q,此时quan_U8Q0_pattern = quantizer(‘ufixed’,‘round’,‘saturate’,[8,0]);
在这里插入图片描述
结果和matlab s_U8Q0 = quantize(quan_U8Q0_pattern,s);得到的结果一样

中间过程
验证四舍五入结果
对比s = K_13Q10 .* s0与rou_K_mul
在这里插入图片描述
若要求输出有符号整数输出,答案1的Q1即为答案
quan_U8Q0_pattern = quantizer(‘fixed’,‘round’,‘saturate’,[8,0]);
D_U8Q0 = quantize(quan_U8Q0_pattern,D);
当D小于等于127时,D_U8Q0 = D,大于127时,输出127

s_U8Q0 = quantize(quan_U8Q0_pattern,s);
对比答案1的Q1与s_U8Q0
在这里插入图片描述
tb文件

module tb_dahua_2021_17();

reg [7:0] D;
reg [12:0] K;
reg I_clk,I_rst_n;
wire [7:0] Q;

parameter C_DATA_LENGTH = 4096;

reg [7:0] M_men_D[0:C_DATA_LENGTH-1];
reg [12:0] M_men_K[0:C_DATA_LENGTH-1];
reg [13:0] R_men_addr;
reg R_data_valid;
reg R_data_valid_t;
DaHua_2021_17 ins(
    .D(D),
    .K(K),//13Q10
    .Q(Q)
    );
  
initial  begin
    I_clk = 0;
    I_rst_n = 0;
    #67;
    I_rst_n = 1;
end   
always #5 I_clk = !I_clk; 
initial begin
    $readmemh("D:/job/signed_cal/D_U8Q0.txt",M_men_D);
    $readmemh("D:/job/signed_cal/K_13Q10.txt",M_men_K);
end

always@(posedge I_clk or negedge I_rst_n) begin
    if(!I_rst_n) begin
        D <= 0;
        K <= 0;
        R_men_addr <= 14'd0;
        R_data_valid <= 1'b0;
    end
    else if (R_men_addr == C_DATA_LENGTH) begin
        R_men_addr <= C_DATA_LENGTH;
        R_data_valid <= 1'b0;
    end
    else begin
        D <= M_men_D[R_men_addr];
        K <= M_men_K[R_men_addr];
        R_data_valid <= 1'b1;
        R_men_addr <= R_men_addr + 1;
    end
end

always@(posedge I_clk or negedge I_rst_n) begin
    if(!I_rst_n)
        R_data_valid_t <= 1'b0;
    else
        R_data_valid_t <= R_data_valid;
end

integer fid;
initial begin
    fid = $fopen("D:/job/signed_cal/s_vivado.txt" , "w");
    if(!fid) begin
        $display("**************************Can Not Open File**************");
        $finish;
    end
    else begin
        $display("**************************Open File Sucess****************");
    end
end

matlab程序

clear
clc
data_length = 4096 - 8 ; % 定义数据长度,其中排除8种边界条件

D_min = 0 ;             %D的数据格式为U80,所以它的最小值为0
D_max = 2^8-1 ;    %a的数据格式为16Q14,所以它的最大值为2 - 1/(2^14)

K_min = -4 ;            %b的数据格式为13Q10,所以它的最小值为-2^(13-10-1)
K_max = 4 - 1/(2^10) ;    %b的数据格式为13Q10,所以它的最大值为2^(13-10-1) - 1/(2^10)



% 产生4088个均匀分布在a、b、c最大值与最小值之间的随机数
D_rand = D_min + (D_max - D_min)*rand(1,data_length) ;
K_rand = K_min + (K_max - K_min)*rand(1,data_length) ;

% 产生8种边界条件
K_boundary = [K_min K_min K_min K_min K_max K_max K_max K_max] ;
D_boundary = [D_min D_min D_max D_max D_min D_min D_max D_max] ;


% 随机数与边界值组合成为待量化的数据
K = [K_boundary K_rand];
D = [D_boundary D_rand];

% 定义量化规则,根据题目要求量化需采用四舍五入与饱和截位的方式
quan_13Q10_pattern = quantizer('fixed','round','saturate',[13,10]);
quan_U8Q0_pattern = quantizer('ufixed','round','saturate',[8,0]);

% 把a、b、c三个数据按照要求进行量化
K_13Q10 = quantize(quan_13Q10_pattern,K);
D_U8Q0 = quantize(quan_U8Q0_pattern,D);


% 计算Q = K *(D-16)的值
s0 = D_U8Q0 - 16;
s = K_13Q10 .* s0;

% 根据题目要求,s的数据格式为16Q14,所以这里把s量化为16Q14格式的数据
s_U8Q0 = quantize(quan_U8Q0_pattern,s);

% 把量化后的a、b、c变成整数方便写入.txt文件中
D_integer = D_U8Q0 ;
K_integer = K_13Q10 * 2^10 ;
s_integer = s_U8Q0 ;

% 由于在Verilog中测试激励文件的系统调用$readmemh读入的数据格式为16进制,所以
% 把数据写入.txt文件中之前需要把数据转化为补码的格式,这样负数才不会写错
K_complement = zeros(1,length(K_integer));


% 把量化后的a转化为补码
for i = 1:length(K_complement)
   if(K_integer(i) < 0)
       K_complement(i) = 2^13 + K_integer(i) ;
   else
       K_complement(i) = K_integer(i) ;
   end
end


% 把量化后的a的补码写入txt文件
fid_a = fopen('K_13Q10.txt','w');
fprintf(fid_a, '%x\n', K_complement);
fclose(fid_a);

% 把量化后的b的补码写入txt文件
fid_b = fopen('D_U8Q0.txt','w');
fprintf(fid_b, '%x\n', D_integer);
fclose(fid_b);

存疑:
Q1及之前都是有符号数表示,有符号数怎么转成无符号数?

最后的无符号表示应为啥样的?不太清楚。

  • 2
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值