RTL范围之外的两个最大值

这是本人在实际工作中遇到的设计任务,借此研究状态机设计的优化策略


1. 功能描述

串行输入一组无符号数据,要求输出这组数据的最大值及其索引 和 次大值及其索引,并且满足这两个值的索引相差大于某个数字。

例如串行输入 29 31 1 20 4 6 7 2 100 99 38 52 2 91 97 96 21,两个最大值相距≥3,结果应为(100,9)和(97,15)。

注意99和100相邻,不符合题意。

此处直接给出伪代码

if(data > data_max) begin
	if(|data - data_max| > eps) begin
		data_submax = data_max;
		index_submax = index_max;
		data_max = data;
		index_max = index;
	end
	else if(|data - data_min| <= eps) begin
		data_submax =;
		index_submax =;
		data_max = data;
		index_max = index;
	end
	else begin
		data_submax = data_submax;
		index_submax = index_submax;
		data_max = data;
		index_max = index;
	end
end
else if(data > data_submax) begin
	if(|data - data_max| > eps) begin
		data_submax = data;
		index_submax = index;
		data_max = data_max;
		index_max = index_max;
	end
	else begin
		data_submax = data_submax ;
		index_submax = index_submax ;
		data_max = data_max;
		index_max = index_max;
	end
end

2. 参数设计

Signal Direction Width(bits) Description
rstninput1异步复位
clkinput1时钟
datainput32串行输入数组
data_valinput1串行输入数组有效标志
data_max_valoutput1数组中最大值有效标志,持续一拍
data_maxoutput32数组中最大值
index_maxoutput32最大值对应的索引
data_submax_valoutput1数组中次大值有效标志,持续一拍
data_submaxoutput32数组中次大值
index_submaxoutput32次大值对应的索引
Parameter Units Description
EPOSILON禁止的索引偏差

3. 逻辑设计

有了伪代码,算法部分就不用费神思考了,所以重点在于时序设计。

按照状态机的思路,整个状态是获取data、计算data与data_max、data_submax的差、更新data_max和data_submax,不断循环,如下图

在这里插入图片描述
由此可以直接绘制如下时序图,注意下方时序图中data不是连续输入的,可以在该模块输入处连接一个同步FIFO,然从FIFO中读出数据进行计算。

在这里插入图片描述
代码忽略!

4. 逻辑优化

从上述波形图中可以看出WAIT_DATA状态下只有data和data_val动作、GET_DIFF下只有diff_data动作、在UPDATE下只有data_max和data_submax动作,所以可以将状态机优化成流水

在这里插入图片描述
注意更新data_max和data_submax时不仅需要diff_data还需要用于计算diff_data的data,所以要对data打一拍,时序图如下

在这里插入图片描述
按照上图可以正常输出data_max和data_submax,但是别忘了如何输出索引呢?由于不知道data_val拉高的时刻,所以可以为data_d1标记索引。

由于计算diff_data是时序逻辑,所以需要将data与diff_data对齐,所以data_d1还要再打一拍成data_d2与diff_data对齐

在这里插入图片描述

4.1. 代码

module	find_max_submax#(
	parameter	eps		=	3
	)(
	input			clk,
	input			rstn,
	
	input	[31:0]	data,
	input			data_val,
	
	output	[31:0]	data_max,
	output			data_max_val,
	output	[7:0]	index_max,
	
	output	[31:0]	data_submax,
	output			data_submax_val,
	output	[7:0]	index_submax
	);

reg	[31:0]	data_d1;
reg			data_d1_val;
reg	[7:0]	index_d1;

reg	[31:0]	data_d2;
reg			data_d2_val;
reg	[7:0]	index_d2;

reg [7:0]	diff_index_max;
reg [7:0]	diff_index_submax;

reg	[31:0]	data_max_r;
reg			data_max_submax_val;
reg	[7:0]	index_max_r;

reg	[31:0]	data_submax_r;
reg	[7:0]	index_submax_r;

always@(posedge clk or negedge rstn) begin
	if(!rstn) begin
		data_d1 <= 32'd0;
		data_d1_val <= 1'b0;
		
		data_d2 <= 32'd0;
		data_d2_val <= 1'b0;
	end
	else begin
		data_d1 <= data;
		data_d1_val <= data_val;
		
		data_d2 <= data_d1;
		data_d2_val <= data_d1_val;
	end
end

always@(posedge clk or negedge rstn) begin
	if(!rstn) 
		data_max_submax_val <= 1'b0;
	else 
		data_max_submax_val <= data_d2_val;
end

assign data_max_val = data_max_submax_val;
assign data_submax_val = data_max_submax_val;

always@(posedge clk or negedge rstn) begin
	if(!rstn) 
		index_d1 <= 8'd0;
	else if(data_val)
		index_d1 <= index_d1 + 8'd1;
end

always@(posedge clk or negedge rstn) begin
	if(!rstn) 
		index_d2 <= 8'd0;
	else 
		index_d2 <= index_d1;
end

always@(posedge clk or negedge rstn) begin
	if(!rstn) begin
		diff_index_max <= 8'd0;
		diff_index_submax <= 8'd0;
	end
	else if(data_d1_val) begin
		diff_index_max <=  (index_d1 > index_max)?(index_d1 - index_max):(index_max - index_d1);
		diff_index_submax <=  (index_d1 > index_submax)?(index_d1 - index_submax):(index_submax - index_d1);
	end
end

always@(posedge clk or negedge rstn) begin
	if(!rstn) begin
		data_max_r <= 32'd0;
		index_max_r <= 8'd0;
		
		data_submax_r <= 32'd0;
		index_submax_r <= 8'd0;
	end
	else if(data_d2_val) begin
		if(data_d2 > data_max) begin
			if(diff_index_max > eps) begin
				data_submax_r <= data_max;
				index_submax_r <= index_max;
				data_max_r <= data_d2;
				index_max_r <= index_d2;
			end
			else if(diff_index_submax <= eps) begin
				data_submax_r <= 32'd0;
				index_submax_r <= 8'd0;
				data_max_r <= data_d2;
				index_max_r <= index_d2;
			end
			else begin
				data_submax_r <= data_submax;
				index_submax_r <= index_submax;
				data_max_r <= data_d2;
				index_max_r <= index_d2;
			end
		end
		else if(data_d2 > data_submax) begin
			if(diff_index_max > eps) begin
				data_submax_r <= data_d2;
				index_submax_r <= index_d2;
				data_max_r <= data_max;
				index_max_r <= index_max;
			end
		end
	end
end

assign data_max = data_max_r;
assign index_max = index_max_r;

assign data_submax = data_submax_r;
assign index_submax = index_submax_r;

endmodule	

5. 测试

5.1. testbench

所写的简单tb如下

`timescale 1ns/1ps

module find_max_submax_tb();

logic			clk;
logic			rstn;

logic	[31:0]	data;
logic			data_val;

logic	[31:0]	data_max;
logic			data_max_val;
logic	[7:0]	index_max;

logic	[31:0]	data_submax;
logic			data_submax_val;
logic	[7:0]	index_submax;

initial begin
	clk = 1'b0;
	forever		#2.5	clk = !clk;
end

initial begin
	rstn = 1'b1;
	#50;
	rstn = 1'b0;
	#50;
	rstn = 1'b1;
end

initial begin
	data = 'd0;
	data_val = 'd0;
	#200;
	find_max_submax_test();
end

task find_max_submax_test();
	
	automatic bit [31:0] nums[17] = {'d29,'d31,'d1,'d20, 'd4, 'd6, 'd7, 'd2, 'd100, 'd99, 'd38, 'd52, 'd2, 'd91, 'd97, 'd96, 'd21};
	
	foreach(nums[i]) begin
		@(posedge clk);
		#0.1;
		data = nums[i];
		data_val = 1;
		
		repeat($urandom_range(2,5)) begin
			@(posedge clk);
			#0.1;
			data = 'd10;
			data_val = 0;
		end
	end
endtask

	

find_max_submax#(
	.eps					(3					)
	)	DUT(
	.clk					(clk				),
	.rstn                  	(rstn				),
								
	.data                  	(data				),
	.data_val              	(data_val			),
								
	.data_max              	(data_max			),
	.data_max_val          	(data_max_val		),
	.index_max             	(index_max			),
								
	.data_submax           	(data_submax		),
	.data_submax_val       	(data_submax_val	),
	.index_submax           (index_submax		)
);                  

endmodule

5.2. 测试结果

预期输出为(100,9)和(97,15),波形符合预期

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Starry丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值