本周刷题覆盖范围:Verilog Language差一道题,组合电路部分Basic Gates差五道题,时序电路部分Latches and Flip-Flops差四道题,counters差四道题。
目前刷题比较基础,原理上都能看懂,但是由于数电已经学完很久了,很多零散的知识点记不得了,再就是verilog代码比较细节的部分掌握的不好以及由verilog代码思考RTL电路的能力还没有培养好。希望可以早日做到师兄说的看到问题先想如何用RTL电路搭建,之后再用verilog语言来翻译。
本周将总结分为三部分:零散知识点、verilog代码细节分析以及代码风格学习。
一.零散知识点:
1.逻辑门:
xor 异或 异或符号:^
xnor 同或 同或符号:~^
2.进制:
0x34 16进制数34
0o 8进制
0b 2进制
3.单目、双目、三目运算符的区别:
单目只有一个操作数,例如; 逻辑非运算符!、按位取反运算符~、自增自减运算符i++、负号运算符-。
双目: +、-、*、/、=、==
三目:<表达式1> ? <表达式2> : <表达式3>;
4.加减法器的原理
首先需要先了解原码补码反码的定义
原码原码就是符号位加上真值的绝对值,即用第一位表示符号,其余位表示值。比如如果是8位二进制
[+1]原 = 0000 0001 [-1]原 = 1000 0001
反码:反码的表示方法是:正数的反码是其本身。负数的反码是在其原码的基础上, 符号位不变,其余各个位取反。
[+1] = [00000001]原 = [00000001]反 [-1] = [10000001]原 = [11111110]反
补码的表示方法是:正数的补码就是其本身。负数的补码是在其原码的基础上,符号位不变,其余各位取反,最后+1。(即在反码的基础上+1)。
[+1] = [00000001]原 = [00000001]反 = [00000001]补
[-1] = [10000001]原 = [11111110]反 = [11111111]补
8位的数据表示范围是:-128——127
通过原码反码补码可以将减法改为加法进行运算即将a-b改为a+(-b)
二.verilog代码细节分析:
HDLBits中 Combinational for-loop - 255-bit population count 一题需要实现查256位2进制数中1的个数。实现代码如下
1. module top_module(
2. input [254:0] in,
3. output [7:0] out );
4. integer i;
5. always@(*)
6. begin
7. out=0;
8. for(i=0;i<255;i=i+1)
9. if(in[i]==1)
10. out=out+1;
11. else
12. out=out;
13. end 这里没有begin and会报错
14. endmodule
设计如下三个问题:
1.这里的always后不加begin_end会报错,原因是begin_end顺序块用于将多条语句组成顺序块,语句按顺序一条一条执行,与之相对应的是fork-join并行块。这里不用begin_end,后面的语句无法顺序执行,也就无法生成对应的RTL电路。
2.for循环在这里用来复制电路,这里复制了255个电路输出都是out,为什么没有出现赋值冲突,即将多个输入给到一个输出的问题呢?这也是因为这个for循环在begin_end顺序块内部执行,可以理解为255个电路串联,前一个电路的输出是后一个电路的输入,其RTL电路如下图所示。
3.always@(*)模块可以理解为一整个封装好的RTL电路,输入是in,输出是out,每次in改变值时,输出out就会改变值,所以只要输入in的值发生改变,always@(*)内部所有语句都会执行一遍。
三.代码风格学习:
1. always @(*) begin
2. {up, down, left, right} = 4'b0;
//您必须为所有四种情况下的所有四个输出和默认情况下的输出分配一个值。这可能涉及许多不必要的输入。一个简单的方法是在case语句之前给输出赋一个“默认值”:
3. case (scancode)
4. 16'he06b: left = 1;
5. 16'he072: down = 1;
6. 16'he074: right = 1;
7. 16'he075: up = 1;
8. endcase
9. end
先分配默认值可以省去很多重复代码的编写,否则需要在每一个case都列很一个情况的输出,并且要写default。
RTL电路如下图所示