前言:
本专栏旨在记录高频笔面试手撕代码题,以备数字前端秋招,本专栏所有文章提供原理分析、代码及波形,所有代码均经过本人验证。
目录如下:
10.数字IC手撕代码-数据位宽转换器(宽-窄,窄-宽转换)
13.数字IC手撕代码-流水握手(利用握手解决流水线断流、反压问题)
18.数字IC手撕代码-双端口RAM(dual-port-RAM)
...持续更新
为了方便可以收藏导览博客: 数字IC手撕代码-导览目录
目录
半加器
所谓半加器,就是不考虑进位的加法器,只有两个输入和两个输出;输入A和B,输出和数sum和进位cout,半加器真值表如下:
写一个半加器其实就是把各个参数之间的关系用verilog描述出来。很容易可以得到:
代码
module half_adder(
input A ,
input B ,
output cout ,
output sum
);
assign sum = A ^ B;
assign cout = A & B;
endmodule
然而大多数公司的手撕代码完半加器和全加器后,还会让你手绘门电路,所以在这里我也提一下门电路画法。
门电路其实很好画,知道了信号之间的与非关系,就很好处理了,比如半加器的cout就是A和B的与,直接用一个两输入与门就能连接。而sum是A和B的异或,用一个异或门就可以得到,当然也不排除公司故意不让你用异或门的情况。异或转换成与门如下:
异或会用门电路画了,那么半加器的门电路就很简单了。
全加器
全加器就是在半加器的基础上引入一个进位输入,总共三个输入两个输出。全加器真值表如下:
这个不要背表达式,如果背表达式,正式手撕代码的时候很容易忘记,然后写错(虽然全加器很简单。)我们推导一下表达式。
这里的输出一共有两个,一个sum,一个进位cout。sum的值是A+B+cin然后去掉进位得到的,也就是说A、B、cin 中,如果输入1的个数是奇数,则sum为1,输入1的个数为偶数(含零)则sum为0。根据这个奇偶判定,可以想到用异或操作,所以得到表达式:
cout的值也好分析,cout是加和出来的进位,也就是说,如果A、B、cin三个数中,有两个及以上个1,则cout为1,这个容易得到表达式:
代码
module full_adder(
input A ,
input B ,
input cin ,
output sum ,
output cout
);
assign sum = A ^ B ^ cin;
assign cout = (A&B)|(B&cin)|(A&cin);
endmodule
全加器的门电路就不画了,原理和半加器是一致的,信号有点多容易弄混,所以画的时候细心一点,就没什么问题。