赞
踩
module test( input [7:0]data_in, input [3:0]out ); reg [3:0]cnt; integer i; always@(data_in)begin cnt <= 'd0; for(i = 0;i < 8;i = i + 1)begin if(data_in[i]) cnt <= cnt + 1'b1; else cnt <= cnt; end end assign out = cnt; //写法二 //assign out = data_in[0] + data_in[1] + data_in[2] + data_in[3] + data_in[4] + data_in[5] + data_in[6] + data_in[7]; endmodule
Testbench:
`timescale 1ns/1ns module test_tb; reg [7:0]data_in; wire [3:0]out; test test_inst( .data_in (data_in ), .out (out ) ); initial begin data_in = 8'b0000_0000; #200; data_in = 8'b1111_0010; #200; data_in = 8'b1100_0010; #200; data_in = 8'b1111_1111; #200; $stop; end endmodule
仿真结果:
独热码是一种二进制编码方式,它的特点是,用来编码这个数的N位bit中,有且只有一位是1,其余位全部为0。因为只有1位是1,所以叫做one-hot (对应的,还有一种编码方式是只有1位是0,其余位都是1,叫做one-cold)
状态机中使用独热码的好处
利用one-hot来编码状态机,好处就是一个flop就表示一个状态,用来判断状态机在哪一个状态的时候就只需要看第几个flop为1即可,而不需要像binary编码那样是所有flop在一起参与比较。这样可以省下一点点逻辑的比较电路的延时,代价显而易见,用one-hot编码状态机需要的寄存器比binary编码要多,这就是一个典型的利用面积换性能的trade off。
00 | 01 | 11 | 10 | |
---|---|---|---|---|
00 | 0 | 1 | 0 | 1 |
01 | 1 | 0 | 0 | 0 |
11 | 0 | 0 | 0 | 0 |
10 | 1 | 0 | 0 | 0 |
Y = (A[0] & (!A[1]) & (!A[2]) & (!A[3]))
|((!A[0]) & A[1] & (!A[2]) & (!A[3]))
|((!A[0]) & (!A[1]) & A[2] & (!A[3]))
|((!A[0]) & (!A[1]) & (!A[2]) & A[3]);
其实有个很简单的思路,就是从独热码的定义出发:只有一位是1,其余位都是0。那么不管我输入信号有多少位,有一个性质是不变的 – 把这些位各自相加,最后的结果肯定得是1。那么我们就可以利用一个for循环,把每一位相加,最后再把最终的结果和1比较一下,如果是1,那就是独热码,如果不是1,那就是其他的数
module test_1(
input [3:0]data_in,
input out
);
integer i;
reg [3:0]sum
always@(*)begin
sum <= 'd0;
for(i = 0;i < 4; i = i + 1)begin
sum <= sum + data_in[i];
end
end
assign out = sum == 1?1'b1:1'b0;
endmodule
system verilog代码:
function automatic logic is_onehot(input [WIDTH-1:0] sig);
logic [WIDTH-1:0] parity;
parity[0] = sig[0];
for(int i = 1; i < WIDTH; i++)
parity[i] = parity[i-1] ^ sig[i];
is_onehot = parity[i-1] & (&(parity | ~sig));
endfunction
SUM_WIDTH要用$clog2之后再加1,为什么呢?因为加入输入为4位信号,如果SUM_WIDTH要用clog2之后不加1的话,SUM_WIDTH的位宽为2bit,最大表达为11(3),而4位信号全为1时,sum应该为4,表达位宽不够。
对于一个4位的二进制数,我们对这4位奇偶校验,利用异或门依次进行每一位,最后的结果如果是奇数个1那么4位异或之后结果就是1,如果偶数个1那么结果就是0。看到了吗,我们要找的独热码其实是奇数个1的特殊情况,即只有1位是1。所以更加巧妙的方法就来自于这个按位异或。
把A相应按位XOR的结果记为P,其中P[0] = A[0], P[i] = A[i] ^ P[i-1]
即对于独热码,我们得到的P会是这样一个数:如果独热码A的第i位为1,那么P的第i-1到第0位都是0,而第i位和更高位都是1。注意,这个规律只对独热码适用,大家可以试验一下其他任何数,只要多于1位是1,那么就不会出现高位连续的都是1,高位必然会出现0。
将A按位取反,然后再和P按位OR起来会得到什么?A既然是独热码,那么除了为1的那一位(假设是第i位),取反之后都会变成1,只有第i位会是0。而P的第i位是1,那么最后按位OR的结果是什么?全部每一位都是1。
那么如果A不是独热码,而是有两个1或者更多1,假设第i位和第k位是1(k是i之后第一个1),我们进行上面的操作会得到什么?P[k]会得到0。A反和P按位OR之后第k位也是0.
一个特殊情况,即A为全0。当A为全0的时候,P也是全0,但是A取反之后是全1,所以A反和P按位OR之后也会得到全1。幸好,特殊情况就只有这一种,我们只需要对A进行一下全0判断就可以了。
system verilog代码:
function automatic logic is_onehot(input [WIDTH-1:0] sig);
logic [WIDTH-1:0] parity;
parity[0] = sig[0];
for(int i = 1; i < WIDTH; i++)
parity[i] = parity[i-1] ^ sig[i];
is_onehot = parity[i-1] & (&(parity | ~sig));
endfunction
设计一个组合逻辑电路,检测输入32位0/1向量中从高到低第一个1出现的位置,如果向量为全0则输出32。例如:
输入00011000 10000000 00000000 00000000,输出3;
输入00000000 11111111 00000000 00000000,输出8;
输入00000000 00000000 00000000 00001010,输出28.
即输出从左向右,出现第一个1的位置
module seq_head_detect( input [31:0] data_in, output pos_out ); reg [31:0] tmp; reg [5:0] pos_out_tmp; reg [5:0] pos_out; always @(*) begin tmp = data_in; casex(tmp) 32'b1xxx_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx : pos_out_tmp = 6'd0; 32'b01xx_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx : pos_out_tmp = 6'd1; 32'b001x_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx : pos_out_tmp = 6'd2; 32'b0001_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx : pos_out_tmp = 6'd3; //第4位为1 32'b0000_1xxx_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx : pos_out_tmp = 6'd4; 32'b0000_01xx_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx : pos_out_tmp = 6'd5; 32'b0000_001x_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx : pos_out_tmp = 6'd6; 32'b0000_0001_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx : pos_out_tmp = 6'd7; //8 32'b0000_0000_1xxx_xxxx_xxxx_xxxx_xxxx_xxxx : pos_out_tmp = 6'd8; 32'b0000_0000_01xx_xxxx_xxxx_xxxx_xxxx_xxxx : pos_out_tmp = 6'd9; 32'b0000_0000_001x_xxxx_xxxx_xxxx_xxxx_xxxx : pos_out_tmp = 6'd10; 32'b0000_0000_0001_xxxx_xxxx_xxxx_xxxx_xxxx : pos_out_tmp = 6'd11; //12 32'b0000_0000_0000_1xxx_xxxx_xxxx_xxxx_xxxx : pos_out_tmp = 6'd12; 32'b0000_0000_0000_01xx_xxxx_xxxx_xxxx_xxxx : pos_out_tmp = 6'd13; 32'b0000_0000_0000_001x_xxxx_xxxx_xxxx_xxxx : pos_out_tmp = 6'd14; 32'b0000_0000_0000_0001_xxxx_xxxx_xxxx_xxxx : pos_out_tmp = 6'd15; //16 32'b0000_0000_0000_0000_1xxx_xxxx_xxxx_xxxx : pos_out_tmp = 6'd16; 32'b0000_0000_0000_0000_01xx_xxxx_xxxx_xxxx : pos_out_tmp = 6'd17; 32'b0000_0000_0000_0000_001x_xxxx_xxxx_xxxx : pos_out_tmp = 6'd18; 32'b0000_0000_0000_0000_0001_xxxx_xxxx_xxxx : pos_out_tmp = 6'd19; //20 32'b0000_0000_0000_0000_0000_1xxx_xxxx_xxxx : pos_out_tmp = 6'd20; 32'b0000_0000_0000_0000_0000_01xx_xxxx_xxxx : pos_out_tmp = 6'd21; 32'b0000_0000_0000_0000_0000_001x_xxxx_xxxx : pos_out_tmp = 6'd22; 32'b0000_0000_0000_0000_0000_0001_xxxx_xxxx : pos_out_tmp = 6'd23; //24 32'b0000_0000_0000_0000_0000_0000_1xxx_xxxx : pos_out_tmp = 6'd24; 32'b0000_0000_0000_0000_0000_0000_01xx_xxxx : pos_out_tmp = 6'd25; 32'b0000_0000_0000_0000_0000_0000_001x_xxxx : pos_out_tmp = 6'd26; 32'b0000_0000_0000_0000_0000_0000_0001_xxxx : pos_out_tmp = 6'd27; //28 32'b0000_0000_0000_0000_0000_0000_0000_1xxx : pos_out_tmp = 6'd28; 32'b0000_0000_0000_0000_0000_0000_0000_01xx : pos_out_tmp = 6'd29; 32'b0000_0000_0000_0000_0000_0000_0000_001x : pos_out_tmp = 6'd30; 32'b0000_0000_0000_0000_0000_0000_0000_0001 : pos_out_tmp = 6'd31; //32 default : pos_out_tmp = 6'd32; //全0 endcase pos_out = pos_out_tmp; end endmodule
module seq_head_detect( input [31:0] data_in, output pos_out ); reg [31:0] tmp; reg [5:0] pos_out_tmp; reg [5:0] pos_out; always @(*) begin tmp = data_in; if(tmp[31]) pos_out_tmp = 6'd0; else if(tmp[30]) pos_out_tmp = 6'd1; else if(tmp[29]) pos_out_tmp = 6'd2; else if(tmp[28]) pos_out_tmp = 6'd3; else if(tmp[27]) pos_out_tmp = 6'd4; else if(tmp[26]) pos_out_tmp = 6'd5; else if(tmp[25]) pos_out_tmp = 6'd6; else if(tmp[24]) pos_out_tmp = 6'd7; else if(tmp[23]) pos_out_tmp = 6'd8; else if(tmp[22]) pos_out_tmp = 6'd9; else if(tmp[21]) pos_out_tmp = 6'd10; else if(tmp[20]) pos_out_tmp = 6'd11; else if(tmp[19]) pos_out_tmp = 6'd12; else if(tmp[18]) pos_out_tmp = 6'd13; else if(tmp[17]) pos_out_tmp = 6'd14; else if(tmp[16]) pos_out_tmp = 6'd15; else if(tmp[15]) pos_out_tmp = 6'd16; else if(tmp[14]) pos_out_tmp = 6'd17; else if(tmp[13]) pos_out_tmp = 6'd18; else if(tmp[12]) pos_out_tmp = 6'd19; else if(tmp[11]) pos_out_tmp = 6'd20; else if(tmp[10]) pos_out_tmp = 6'd21; else if(tmp[9]) pos_out_tmp = 6'd22; else if(tmp[8]) pos_out_tmp = 6'd23; else if(tmp[7]) pos_out_tmp = 6'd24; else if(tmp[6]) pos_out_tmp = 6'd25; else if(tmp[5]) pos_out_tmp = 6'd26; else if(tmp[4]) pos_out_tmp = 6'd27; else if(tmp[3]) pos_out_tmp = 6'd28; else if(tmp[2]) pos_out_tmp = 6'd29; else if(tmp[1]) pos_out_tmp = 6'd30; else if(tmp[0]) pos_out_tmp = 6'd31; else pos_out_tmp = 6'd32; pos_out = pos_out_tmp; end endmodule
module seq_head_detect( input [31:0] data_in, output [ 5:0] pos_out ); //mark:assign不能给reg赋值,只能赋给wire wire [4:0] data_chk; wire [15:0] data_1; wire [7:0] data_2; wire [3:0] data_3; wire [1:0] data_4; assign data_chk[4] = |data_in[31:16];//高16位相或,依此类推 assign data_chk[3] = |data_1[15:8]; assign data_chk[2] = |data_2[7:4]; assign data_chk[1] = |data_3[3:2]; assign data_chk[0] = |data_4[1]; assign data_1 = (data_chk[4]) ? data_in[31:16] : data_in[15:0]; //若data_in高16位有1,则data1取其高16位,否则取低16位 assign data_2 = (data_chk[3]) ? data_1[15:8] : data_1[7:0]; //若data_1高8位有1,则data2取其高8位,否则取低8位 assign data_3 = (data_chk[2]) ? data_2[7:4] : data_2[3:0]; //若data_2高4位有1,则data3取其高4位,否则取低4位 assign data_4 = (data_chk[1]) ? data_3[3:2] : data_3[1:0]; //若data_3高2位有1,则data4取其高2位,否则取低2位 assign pos_out = (|data_in) ? {1'b0, ~data_chk} : 6'd32; //若data_in为全0,posout = 6'd32 /*data_in中有1时,用低5位表示足够,则最高位为0*/ /*假定data_in首位为1,则data_chk = 11111,应有pos_out = 00000,类推可知data_chk取反*/ endmodule
Testbench:
`timescale 1ns / 1ps module tb_seq_head_detect(); reg [31:0] data_in; wire [5:0] pos_out; initial begin data_in = 32'b0000_0000_0000_0000_0000_0000_0000_0000; #100 data_in = 32'b0000_0001_0000_0000_0000_0000_0000_1101;//第8位,pos_out = 7 #100 data_in = 32'b0000_0000_0000_0000_0010_0000_0000_1101;//第19位,pos_out = 18 end seq_head_detect u_seq_head_detect( .data_in (data_in), .pos_out (pos_out) ); endmodule
仿真结果:
module find_first #( parameter WIDTH = 6 )( input [WIDTH-1:0] req, output [WIDTH-1:0] grant ); genvar i; if(lsb_first) begin:lsb_to_msb assign grant[0] = req[0]; for(i=1;i<WIDTH;i=i+1)begin grant[i] = req[i] & ~|grant[i-1:0]; end end else if(!lsb_first) begin:msb_to_lsb assign grant[WIDTH-1] = req[WIDTH-1]; for(i=WIDTH-2;i>0;i=i-1)begin grant[i] = req[i] & ~|grant[WIDTH-1:i+1]; end end endmodule
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。