基础电路分析 (一)

决定写一些基础电路方面的笔记, 免得自己把一些很基础的概念、电路忘得一干二净。 这篇文章就介绍三个, 并且这三个电路经常出现在笔试或者面试。

统计电路

我们知道matlab有一个函数hist, 可以画出随机数的分布, 其实这个函数用电路也可以实现。看下面一个例子:

假设每个周期输入一个16bit的随机数, enable 和capture_data指定一个数据, 假设是W, 电路要统计W之前出现的次数, 并且要求下一周期输出,如何实现?

如果不考虑overflow, 那么便可以用一个2p-RAM来实现。 把随机数当做地址。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
ram_dp_ar_sw
#(
.DATA_WIDTH (16),
.ADDR_WIDTH (16)
) dpRAM_u
(
.wr_clk (clk),
.wr_en (rnd_valid),
.wr_addr (rnd_in),
.data_in (adder_out),

.rst_n (rst_n),
.rd_en (1'b1),
.rd_addr (rd_addr),
.data_out (ram_out)

);

assign adder_out = ram_out + {15'd0,1'b1};
assign rd_addr = (capture_en == 1'b1)? capture_data : rnd_in;

log2(X) 电路设计

如何实现log2(x)? 假设X是16bit定点数(有整数部分和小数部分), 并且输入的值大于1。

其实如果输入数据是整数, 那么优先编码器可以解决该问题,但是输入是定点数,就不可以那么处理了。设计实现的思路有两点:

  • LUT 查表
  • 归一化

计算方法如下面的公式:

如果我们选择$n$ 使得$(2^{-n}\cdot x) \in [1,2)$, 那么n就是log结果的整数部分, 可以通过优先编码器得到。 然后经过barrel shifter得到$2^{-n}\cdot x$.

最后用LUT计算低bit, 也就是log的小数部分。 因为我们把数值范围进行了归一化, 这样LUT就会比较小了。

电路的结构如图所示:

其中 LUT部分的rtl code 可以写成:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function real rlog2;
input real x;
begin
rlog2 = $ln(x)/$ln(2);
end
endfunction

integer i;
initial
begin : init_lut
lut[0] = 0;
for (i=1; i < (1<<ADDR_WIDTH); i=i+1)
lut[i] = $rtoi(rlog2(1.0 + $itor(i)/$itor(1<<ADDR_WIDTH)) * $itor(1<<DATA_WIDTH)+0.5);
end

assign data_out = lut[addr];

而优先编码器的rtl code 可以写成:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
generate 
if (WIDTH == 2) begin
assign valid = |enc_in;
assign enc_out = enc_in[1];
end
else if (WIDTH & (WIDTH-1)) begin
prior_enc #(1 << $clog2(WIDTH))
prior_enc_u({(1 << $clog2(WIDTH)){1'b0}}|enc_in,enc_out,valid);
end
else begin
wire [$clog2(WIDTH)-2:0] encode_low;
wire [$clog2(WIDTH)-2:0] encode_high;
wire valid_low,valid_high;
prior_enc #(WIDTH >> 1) low_u (enc_in[(WIDTH>>1)-1:0],encode_low,valid_low);
prior_enc #(WIDTH >> 1) high_u (enc_in[WIDTH-1:(WIDTH>>1)],encode_high,valid_high);
assign valid = valid_low | valid_high;
assign enc_out = (valid_high)? {1'b1,encode_high} : {1'b0,encode_low};
end
endgenerate

测试结果如下所示: