HELP!求最大最小值
正在整合系统,有个IP缺一个叫做DW_minmax.v的文件,然后老板说,你自己写一个吧,结果发现比较困难。寻求各位的帮助。接口如下:
module DW_minmax(
a,
tc,
min_max,
value,
index
);
parameter WIDTH = 4; // element WIDTH
parameter NUM_INPUTS = 8; // number of elements in input array
parameter INDEX_WIDTH = 3; // size of index pointer = ceil(log2(NUM_INPUTS))
input [WIDTH*NUM_INPUTS-1:0] a; //Concatenated input vector
input tc; //0=unsigned,1=signed
input min_max; //0=find min,1=find max
output [WIDTH-1:0] value; //min or max value found
output [INDEX_WIDTH-1:0] index; //index to value found
大概是:输入一个32位的数,实际上它是8个4位的数组成的。找出这8个数中的最大/最小值,并且给出相应的index值。而且,这八个数还有可能是有符号的。
我做起来有以下几个困难之处,不知道该怎么办:1.没有时钟,我的想法是需要寄存器保存一下中间值;2.待比较的数目不定,要是确定的,比较好一次性把数全分开。
大概可能不行吧,需要确定功能。
确定什么功能?
用三层共七个比较器选出最大/最小的值
具体又分成两种情况:无符号数比较和有符号数比较
这两种情况比较器的设计稍微有些不同
乱写的,不知道对不对。
a0和a1比较,大值记为max1,然后和a2比,大值记为max2,然后和a3比,.......一直循环;
a0和a1比较,大值记为min1,然后和a2比,大值记为min2,然后和a3比,.......一直循环;
各位:
比较的基本思想我知道,问题是多少个数要比较不知道,数的位宽不知道,是否有符号位不知道,得适用各种情况。
还好姐姐我自己搞定了。
搞定了应该把自己的方法给出来大家好一起交流交流啊
那好吧。我贴上代码:
` timescale 1ns/1ns
// define WIDTH 4
// define NUM_INPUTS 8
// define INDEX_WIDTH 3
module DW_minmax(
a,
tc,
min_max,
value,
index
);
parameter WIDTH = 4; // element WIDTH
parameter NUM_INPUTS = 8; // number of elements in input array
parameter INDEX_WIDTH = 3; // size of index pointer = ceil(log2(NUM_INPUTS))
input [ WIDTH* NUM_INPUTS-1:0] a; //Concatenated input vector
input tc; //0=unsigned,1=signed
input min_max; //0=find min,1=find max
output [ WIDTH-1:0] value; //min or max value found
output [ INDEX_WIDTH-1:0] index; //index to value found
reg [ WIDTH-1:0]b[ NUM_INPUTS-1:0];
reg [ WIDTH* NUM_INPUTS-1:0] a_tmp;
reg [ INDEX_WIDTH-1:0] pi;
reg [ WIDTH-1:0] max_tmp;
reg [ WIDTH-1:0] min_tmp;
reg [ INDEX_WIDTH-1:0] max_index;
reg [ INDEX_WIDTH-1:0] min_index;
wire [ WIDTH-1:0] value;
wire [ INDEX_WIDTH-1:0] index;
always @(a)
begin: takeout
a_tmp=a;
for (pi=0;pi< NUM_INPUTS-1;pi=pi+1)
begin
b[pi] = a_tmp[ WIDTH-1:0];
a_tmp = a_tmp>> WIDTH;
end
b[pi] = a_tmp[ WIDTH-1:0];
a_tmp = a_tmp>> WIDTH;
end
always @(a)
begin: max_min
max_tmp=b[0];
min_tmp=b[0];
max_index=0;
min_index=0;
for(pi=1;pi< NUM_INPUTS-1;pi=pi+1)
begin
if(tc==1'b0)
begin
if(max_tmp<b[pi])
begin
max_tmp=b[pi];
max_index=pi;
end
if(min_tmp>b[pi])
begin
min_tmp=b[pi];
min_index=pi;
end
end
else if(tc==1'b1)
begin
//find max
if(max_tmp[ WIDTH-1] > b[pi][ WIDTH-1])//when highest bit =1,the number is less then the number of highest bit=0
begin //change
max_tmp=b[pi];
max_index=pi;
end
else if(max_tmp[ WIDTH-1] < b[pi][ WIDTH-1])//when highest bit =0,the number is greater then the number of highest bit=1
begin //dont change (latch)
max_tmp=max_tmp;
max_index=max_index;
end
else if(max_tmp[ WIDTH-1] == b[pi][ WIDTH-1])//when highest bit equal, normal compare
begin
if(max_tmp<b[pi])
begin
max_tmp=b[pi];
max_index=pi;
end
end
//find min
if(min_tmp[ WIDTH-1] < b[pi][ WIDTH-1])
begin
min_tmp=b[pi];
min_index=pi;
end
else if(min_tmp[ WIDTH-1] > b[pi][ WIDTH-1])
begin
min_tmp=min_tmp;
min_index=min_index;
end
else if(min_tmp[ WIDTH-1] == b[pi][ WIDTH-1])
begin
if(min_tmp>b[pi])
begin
min_tmp=b[pi];
min_index=pi;
end
end
end
end
if(tc==1'b0)
begin
if(max_tmp<b[pi])
begin
max_tmp=b[pi];
max_index=pi;
end
if(min_tmp>b[pi])
begin
min_tmp=b[pi];
min_index=pi;
end
end
else if(tc==1'b1)
begin
//find max
if(max_tmp[ WIDTH-1] > b[pi][ WIDTH-1])//when highest bit =1,the number is less then the number of highest bit=0
begin //change
max_tmp=b[pi];
max_index=pi;
end
else if(max_tmp[ WIDTH-1] < b[pi][ WIDTH-1])//when highest bit =0,the number is greater then the number of highest bit=1
begin //dont change (latch)
max_tmp=max_tmp;
max_index=max_index;
end
else if(max_tmp[ WIDTH-1] == b[pi][ WIDTH-1])//when highest bit equal, normal compare
begin
if(max_tmp<b[pi])
begin
max_tmp=b[pi];
max_index=pi;
end
end
//find min
if(min_tmp[ WIDTH-1] < b[pi][ WIDTH-1])
begin
min_tmp=b[pi];
min_index=pi;
end
else if(min_tmp[ WIDTH-1] > b[pi][ WIDTH-1])
begin
min_tmp=min_tmp;
min_index=min_index;
end
else if(min_tmp[ WIDTH-1] == b[pi][ WIDTH-1])
begin
if(min_tmp>b[pi])
begin
min_tmp=b[pi];
min_index=pi;
end
end
end
end
assign value=min_max?max_tmp:min_tmp;
assign index=min_max?max_index:min_index;
endmodule
感觉求最大最小的那个for循环那还是太多行了,写的时候好几次begin和end没对上。有谁能精简一下?
3个问题:
1:比较器没必要逐位比较。建议做个标准比较器模块:位宽参数化;一个符号控制信号;输出2bits结果信号,表示大,小,或相等。
2:如果不要求可综合,那此条不算问题。你的代码出来的一定是锁存器。
3:如果不要求可综合,那此条不算问题。循环次数必须是常数,每次的循环结果必须有专门的名称定义。
最后说下,除非你是大妈级人物,否则不自称姐姐。你不知道看你贴和回你贴的人的年龄。
闲话少说,给出代码吧。我比较愚钝,您指出问题之后不知道如何避免及改进。不知道您有没有办法避免?
注:模块的接口是指定好的,不能改变。
对无符号数(有符号数转化成2补)可以直接比较的 a>b
ls说到点子上了。不用按位比较,直接“大于”“小于”这么判断就好了,综合器帮你转化成门级操作
抱歉,年关了,我自己都忙得晕头转向的。没时间帮你写。
小编的代码能综合不,频率跑多少?
有个兄弟说的3级比较靠谱
不能综合的。通常在可综合verilog里很少用到for这类的语法。当然也可以用,但是有诸多限制。楼猪的写法肯定无法综合
从你定义的数据个数的参数宽度来看,最大个数为7;则定义out_1~out_6;
a1和a2比较,比较结果存入out_1(当需要最大值时,out_1等于a1和a2中的大值,需要最小值时,out_1等于a1和a2中的小值);
out_1和a3比较,结果存入out_2;
out_2和a4比较,结果存入out_3;
out_3和a5比较,结果存入out_4;
out_4和a6比较,结果存入out_5;
out_5和a7比较,结果存入out_6;
由实际数据个数i决定最后输出结果:out_(i-1)。
1:因为从i+1到7的数据是假的,所以out_i~out_6;但因为选择的是out_(i-1),不受后续虚假比较影响。能够输出正确结果。
2:硬件消耗:硬件消耗取决于数据的最大个数;当最大个数为7时,需要6个比较器。
还是建议你做个比较器模块,然后调用6次就行。
想要课综合,避免循环语句,除非循环次数固定。
比较器的实现很简单:
首先判定是由符号数比较还是无符号数比较;
无符号数直接作为比较器输入;
有符号数将最高位取反再作为比较器输入;(最高位取反可以理解为加上一个无符号数的8,将有符号数-8~7平移成0~15)。比如0111经操作后变成1111;1000经操作后变成0000;
只需要一个比较器。
上面有一层楼给出了一个图。
已经给出了结构了,那个结构可以把问题解决在log复杂度内。
用comp比较的结果来控制mux输出当前max/min的index和值。
这个二叉树型结构的建立可以通过parameter来控制。
代码写出来应该很清楚,很漂亮。
小编加油
您这个代码是软件思维下写的。
综合工具应该还没您这么聪明。
该模块只做验证环境的一部分使用,不需要综合。
主要是一共有多少个数要比较,然后每个数多少位,这些都不知道(是可配置的)。所以上面有人说调用6次比较模块,这个就不能确定到底需要调用多少次了。所以......要是要求该模块是可综合的,然后所有参数又是可配置的,然后又没有时钟(模块接口定死了)。这个模块该写成什么样的?最好能提供代码(部分也可以),因为我想了一下,不知道该怎么做,目前只能做成这样。有更好的办法当然要学习了。先说声谢谢了。
好像上面有说到我是一位一位比较的,不知道是我写错了呢,还是有人看错了,我只比较了符号位。tc=1时(signed),在我觉得,如果两者符号位相同的话,当然是值大的数更大了,如果符号位不同的话,正的肯定比负的大。
至于没有用补码比较的问题,我的想法是这样的:由于比较之后还要输出最大最小值,所以不大想对数值进行改变。要是采用补码的话,我还得输出前给它变回去。
以上是我写该模块的一些想法,不知道有哪些地方是没考虑到的,哪些地方又过于担心了,还请大家帮忙勘正。
确实啊。多少个数不确定这点最恼火。另外,取补码之后,如果这个数是最大值或者最小值,那么,我还需要把它的值输出,这时肯定不能给出补码,还是要给它自己。那我不是得在补码比较之前,先记录一下哪几个数是负的?这点我不知道怎么解决,所以才没用补码。
那么,年后,我等着,您什么时候有空?
我觉得我还是挺要求上进的,既然被说的一无是处,当然要刨根问底了。尊驾稍微花个十几分钟,半个小时的,就低得上我一个月的苦思冥想了。您,这点时间都没有么?
module comparator (
a,
b,
tc ,
cmp_out
);
parameter DAT_WID = 4 ;
input [DAT_WID-1:0] a ,b;
input tc ; //0 :unsigned ; 1: signed
output [DAT_WID-1:0] cmp_out ; // 00 : a=b ;
// 01 : a>b ;
// 10 : a<b ;
wire [DAT_WID-1:0] cmp_a ,cmp_b;
assign cmp_a = tc ? {~cmp_a[DAT_WID-1],cmp_a[DAT_WID-2:0]}:a;
assign cmp_b = tc ? {~cmp_b[DAT_WID-1],cmp_b[DAT_WID-2:0]}:b;
always @ ( cmp_a or cmp_b )
begin
if ( cmp_a > cmp_b ) cmp_out = 2'b10 ;
else if ( cmp_a < cmp_b ) cmp_out = 2'b01 ;
else cmp_out = 2'b00 ;
end
endmodule
原理参看我18楼的回复。
楼上的代码很好,简洁明了!
谢谢百忙之中拨冗相助!
不过调用的时候还是有些疑问:调用的时候好像没办法参数化自动化吧,是否是parameter的值一变,就得修改一下代码呢?
学习一下!
参数化的调用格式: 调用模块名 #(传递参数) 例化名 (端口);
参数传递跟端口例化一样,不写的采用模块内的默认参数。
comparator #(
.DAT_WID ( 8)
)
DUT
(
.a ( data_a ) ,
.b( data_b) ,
.
.
) ;
如果整个工程调用的这个模块参数都一致的话,可以把parameter 的参数化方式改为define的方式,就不需要在调用时传递参数,只需要把difne声明放到最顶层。
但这种声明是全局影响的,不是很推荐。
学习了!
