Reg_File:
Reg_File 原件示意图:
Reg_File实验总的来讲比较简单,其要求实现的操作是在每一次上升沿读取一个地址和一个要求写入的数,如果该地址不为0,且wen信号处于高电平,那么就将该数写入目标地址。实现操作非常的简单,才每个上升沿时判断是否符合写入标准,如果符合,那么写入。在读出的时候,注意特判0位置即可。
波形示意:
上升沿来临,向01写入值,读出是组合逻辑,因此在赋值后直接读出了01写入的值。
访问0号位置,输出为0。
ALU实验详细电路示意图:
ALU实验总体来讲要复杂一些,它包含了几个主要的部分:
最简单的两个部分是求与和或,直接使用|,&运算符即可:
随后的Add、Sub和Slt本质上可以使用一套加法器电路。对于Add,直接使用A+B便可以得到预期的结果。对于减法,则可以考虑使用补码运算,但是值得注意的是进行补码运算所得到的Carryout结果和实际预想到的结果是不一致的:
对于计算A-B:
在补码计算时实际上是:2^{33}+A-B,对于carryout,它此时实际上就是第33位的值,如果其为1,则这代表这A-B\geq0。反之,如果其为0,则这代表A-B<0,这恰好和期望的溢出结果相反,所以在Sub运算和Slt运算中,要对实际运算结果取反。
波形说明:
读入SUB的信号:
A
=
0
X
664
D
9757
=
1716361047
,
B
=
0
X
6
C
2
A
01
B
C
=
1814692284
A=0X664D9757=1716361047,B=0X6C2A01BC=1814692284
A=0X664D9757=1716361047,B=0X6C2A01BC=1814692284
A-B自然是小于0的,但是此时
B
=
0
X
93
D
5
F
E
43
=
2480275011
~B=0X93D5FE43=2480275011
B=0X93D5FE43=2480275011则
A
+
B
+
1
=
4196636059
=
0
X
F
A
23959
B
A+~B+1=4196636059=0XFA23959B
A+ B+1=4196636059=0XFA23959B
该结果并没有溢出,这正是源于先前说明的A-B<0,因此
2
33
+
A
−
B
2^{33}+A-B
233+A−B的第33位值为0。因此减法求得的Carryout需要取反。
其次一个比较重要的问题是要调整取得相反数补码的运算流程。如果使用一般的三目运算符尝试直接取得B的补码是不正确的,因为这经历了一个先求得补码再取数的过程,那么实际电路中是使用了两个加法器,这明显影响了ALU的效率,因此需要先选出B是否取反,得到反码然后在加法器中利用进位输入功能加上1,则这仅需要一个加法器电路。
电路示意图:
可以看出在这种写法下仅需要一个32位全加器就能得到加法结果。
Overflow判定:
在最开始时,我选择了一种非常朴素的判定方法:
这个判定的基本思路是,在进行加法时当且仅当AB同号,并且计算结果与之异号才会出现Overflow,在减法时只有A-(-B)时符号位为负和(-A)-B时符号位为正时才会出现Overflow。
实际代码如上,基本含义为当ALUop[2]=0,即加法时,即分别判断A,B=1,Result_Add=0和A,B=0,Result_Add=1.减法时判断A、B异号和A是否与Result异号。
电路图示意:
在得到最终的Result时,直接使用与或判断选数即可,对于利用overflow获得Result_slt。
在经过思考后我发现可以直接利用overflow和result直接得到结果:
这个代码正确的原因是如果overflow为0,那么结果没有问题,直接用result符号位判断就好了,如果overflow为1,那么结果溢出,符号位和实际的值相反,因此只需要用符号位和overflow异或就好了。
在书写zero判断时,我学习了一种新的verilog语法,也就是|Result它是指将所有位按位或,因此为快速判零提供了一种更加便捷的办法
`timescale 10 ns / 1 ns
`define DATA_WIDTH 32
module alu(
input [`DATA_WIDTH - 1:0] A,
input [`DATA_WIDTH - 1:0] B,
input [ 2:0] ALUop,
output Overflow,
output CarryOut,
output Zero,
output [`DATA_WIDTH - 1:0] Result
);
wire op_and = ALUop == 3'b000;
wire op_or = ALUop == 3'b001;
wire op_add = ALUop == 3'b010;
wire op_sltu= ALUop == 3'b011;
wire op_xor = ALUop == 3'b100;
wire op_nor = ALUop == 3'b101;
wire op_sub = ALUop == 3'b110;
wire op_slt = ALUop == 3'b111;
/*pretreatment for getting the operation that the ALUop referred*/
wire [`DATA_WIDTH - 1:0] Result_or = A | B;
wire [`DATA_WIDTH - 1:0] Result_and = A & B;
wire [`DATA_WIDTH - 1:0] Result_xor = A ^ B;
wire [`DATA_WIDTH - 1:0] Result_nor =~(A | B);
wire [`DATA_WIDTH - 1:0] Result_add;
/*Result add contains the result of add and sub, and we can also using this wire to get slt*/
wire [`DATA_WIDTH - 1:0] B1;
wire C1,Cin;
assign B1={`DATA_WIDTH{op_slt|op_sub|op_sltu}}&~B|{`DATA_WIDTH{~(op_slt|op_sub|op_sltu)}}&B;
assign Cin=op_slt|op_sub|op_sltu;
assign {C1,Result_add}=A+B1+Cin;
/*by using this method, Cin will be recognized as a carry signal, so only one full adder is required*/
assign CarryOut=(op_sub|op_sltu)&(C1^1)|~(op_sub|op_sltu)&C1;
/*in the substraction case the calculation result is 2^{33}+A-B,
so the only cases for C1 to be 1 is that A-B is a natural number.
In this case, the carryout should be 0. When A-B<0, C1 will be 1,
so in the case of substraction, the appropriate solution is to reverse C1 to get carryout.
*/
assign Overflow=A[`DATA_WIDTH - 1 ]&(ALUop[2]^B[`DATA_WIDTH - 1 ])&~Result_add[`DATA_WIDTH - 1 ]|~A[`DATA_WIDTH - 1 ]&(ALUop[2]^~B[`DATA_WIDTH - 1 ])&Result_add[`DATA_WIDTH - 1 ];//simplification by Karnaugh map
/*this overflow is fully simplied, and the original one is:
assign Overflow=(ALUop==3'b010)?(((A[`DATA_WIDTH - 1 ]==B[`DATA_WIDTH - 1 ])&&(~R1[`DATA_WIDTH - 1 ]==A[`DATA_WIDTH - 1 ]))?1:0):
((ALUop==3'b110)?(((A[`DATA_WIDTH - 1 ]==0&&B[`DATA_WIDTH - 1 ]==1&&R1[`DATA_WIDTH - 1 ]==1)||(A[`DATA_WIDTH - 1 ]==1&&B[`DATA_WIDTH - 1 ]==0&&R1[`DATA_WIDTH - 1 ]==0))?1:0):0);
in the case of addition, overflow only occurs when A and B are both positive or negative, and the symbol of result differed to A.
in the case of substraction, overflow occurs when A - (-B) or (-A)-B
*/
assign Result={`DATA_WIDTH{op_slt}}&(Overflow^Result_add[`DATA_WIDTH - 1 ])|{`DATA_WIDTH{op_add|op_sub}}&Result_add|{`DATA_WIDTH{op_and}}&Result_and|{`DATA_WIDTH{op_or}}&Result_or|{`DATA_WIDTH{op_xor}}&Result_xor|{`DATA_WIDTH{op_nor}}&Result_nor|{`DATA_WIDTH{op_sltu}}&CarryOut;
/*we can use the result of substraction to get the slt:
when overflow does not occur, the symbol of Result is answer.
when overflow occurs, the symbol of Result differs, so using the overflower to xor can get the answer.
*/
assign Zero=~|Result;
endmodule