Post on 28-Oct-2014
BÁO CÁO LAB 3ĐỒ ÁN VI XỬ LÝ VÀ CẤU TRÚC MÁY TÍNH
Nhóm 22A
1. Yêu cầu:
- Thiết kế chip Mips Single-Cycle 32bit bao gồm các lệnh LW, SW, J, JR,
BNE, XORI, ADD, SUB và SLT.
- Các lệnh đều được xử lý trong 1 chu kỳ lệnh (Single Cycle).
- Thiết kế dựa trên các module có sẵn regfife, alu, instrmem và datamem
2. Tập lệnh:
Các lệnh chia làm 3 nhóm:
- R-format: ADD, SUB, SLT, JR.
- I-format: LW, SW, BNE, XORI.
- J-format: J.
2.1. R-format:
- Ý nghĩa lệnh:
+ ADD rd, rs, rt:
Reg[rd] = Reg[rs] + Reg[rt].
+ SLT rd, rs, rt:
If (Reg[rs] < Reg[rt])
Reg[rd] = 1
else
Reg[rd] = 0.
+ SUB rd, rs, rt:
Reg[rd] = Reg[rs] – Reg[rt].
+ JR rs:
PC = Reg[rs].
- Khuôn dạng:
opcode rs rt rd shamt function
6 bit 5 bit 5 bit 5 bit 5 bit 6 bit
2.2. I-format:
- Ý nghĩa lệnh:
+ BNE rs, rt, imm16:
if (Reg[rs] != Reg[rt])
PC = PC + 4 + Sign_ext(Imm16)<<2
else
PC = PC + 4.
+ LW rt, imm16(rs):
Reg[rt] = Mem[Reg[rs] + Sign_ext(Imm16)].
+ SW rt, imm16(rs):
Mem[Reg[rs] + Sign_ext(Imm16)] = Reg[rt].
+ XORI rt, rs, imm16:
Reg[rt] = Reg[rs] XOR Zero_ext(Imm16).
- Khuôn dạng:
opcode rs rt address/immediate
6 bit 5 bit 5 bit 16 bit
2.3. J-format:
- Ý nghĩa lệnh:
+ J target:
PC = { PC[31:28], target, 00 }.
- Khuôn dạng:
opcode target address
6 bit 26 bit
3. Thiết kế:
3.1. Sơ đồ khối tổng quát:
3.2. Thiết kế các module:
3.2.1. Module Control:
MainControl
RegDst
Jump
Branch
MemRead
MemReg
ALUop
Memwrite
Aluscr
Regwrite
Instruction [31:26]
- Khối điều khiển trung tâm, có nhiệm vụ giải mã opcode của câu lệnh
thành các tín hiệu điều khiển đến các khối khác trong chip.
- Các tín hiệu điều khiển và giá trị tương ứng trong từng câu lệnh được
cho trong bảng sau:
R-format Jump BNE LW SW XORI
Opcode 000000 000010 000101 100011 101011 001110
RegDst 1 X X 0 X 0
ALUSrc 0 X 0 1 1 1
MemtoRe
g
0 X X 1 X 0
RegWrite 1 0 0 1 0 1
MemWrite 0 0 0 0 1 0
Branch 0 0 1 0 0 0
Jump 0 1 0 0 0 0
SignEx X X 1 1 1 0
ALUOp 0 1 X 0 0 0 1
ALUOp 1 1 X 1 0 0 0
- Từ bảng trạng thái, sử dụng các cổng logic AND và OR, ta lập được các tín
hiệu ra từ 6 bit Opcode
- Code:
module Control(ALUOp, RegDst, Branch, MemtoReg, MemWrite, ALUSrc, RegWrite, Jump, SignEx, InsOp);
output [1:0] ALUOp;output RegDst, Branch, MemtoReg, MemWrite, ALUSrc, RegWrite, Jump, SignEx;input [5:0] InsOp;
wire [5:0] nInsOp;wire ALUSrc1, ALUSrc2, ALUSrc3;wire RegWrite1, RegWrite2, RegWrite3;wire SignEx1, SignEx2, SignEx3;wire [1:0] ALUOp1, ALUOp2;
not #50 (nInsOp[0], InsOp[0]),(nInsOp[1], InsOp[1]),(nInsOp[2], InsOp[2]),(nInsOp[3], InsOp[3]),(nInsOp[4], InsOp[4]),(nInsOp[5], InsOp[5]);
and #100 (RegDst, nInsOp[0], nInsOp[1], nInsOp[2], nInsOp[3], nInsOp[4], nInsOp[5]);
and #100 (ALUSrc1, InsOp[0], InsOp[1], nInsOp[2], nInsOp[3], nInsOp[4], InsOp[5]), (ALUSrc2, InsOp[0], InsOp[1], nInsOp[2], InsOp[3], nInsOp[4], InsOp[5]), (ALUSrc3, nInsOp[0], InsOp[1], InsOp[2], InsOp[3], nInsOp[4], nInsOp[5]);
or #50 (ALUSrc, ALUSrc1, ALUSrc2, ALUSrc3);
and #100 (MemtoReg, InsOp[0], InsOp[1], nInsOp[2], nInsOp[3], nInsOp[4], InsOp[5]);
and #100 (RegWrite1, nInsOp[0], nInsOp[1], nInsOp[2], nInsOp[3], nInsOp[4], nInsOp[5]),
(RegWrite2, InsOp[0], InsOp[1], nInsOp[2], nInsOp[3], nInsOp[4], InsOp[5]),
(RegWrite3, nInsOp[0], InsOp[1], InsOp[2], InsOp[3], nInsOp[4], nInsOp[5]);
or #50 (RegWrite, RegWrite1, RegWrite2, RegWrite3);
and #100 (MemWrite, InsOp[0], InsOp[1], nInsOp[2], InsOp[3], nInsOp[4], InsOp[5]);
and #100 (Branch, InsOp[0], nInsOp[1], InsOp[2], nInsOp[3], nInsOp[4], nInsOp[5]);
and #100 (Jump, nInsOp[0], InsOp[1], nInsOp[2], nInsOp[3], nInsOp[4], nInsOp[5]);
and #100 (SignEx1, InsOp[0], nInsOp[1], InsOp[2], nInsOp[3], nInsOp[4], nInsOp[5]), (SignEx2, InsOp[0], InsOp[1], nInsOp[2], nInsOp[3], nInsOp[4], InsOp[5]), (SignEx3, InsOp[0], InsOp[1], nInsOp[2], InsOp[3], nInsOp[4], InsOp[5]);
or #50 (SignEx, SignEx1, SignEx2, SignEx3);
and #100 (ALUOp1[1], nInsOp[0], nInsOp[1], nInsOp[2], nInsOp[3], nInsOp[4], nInsOp[5]),
(ALUOp2[1], InsOp[0], nInsOp[1], InsOp[2], nInsOp[3], nInsOp[4], nInsOp[5]);
or #50 (ALUOp[1], ALUOp1[1], ALUOp2[1]);
and #100 (ALUOp1[0], nInsOp[0], nInsOp[1], nInsOp[2], nInsOp[3], nInsOp[4], nInsOp[5]),
(ALUOp2[0], nInsOp[0], InsOp[1], InsOp[2], InsOp[3], nInsOp[4], nInsOp[5]);
or #50 (ALUOp[0], ALUOp1[0], ALUOp2[0]);
endmodule
3.2.2. Module ALUControl:
- Giải mã tín hiệu điều khiển ALUOp từ khối Control, kết hợp với 6 bit
Function để đưa ra tín hiệu điều khiển cho khối ALU thực hiện một trong bốn phép
toán ADD, SUB, SLT và XOR
- Tín hiệu điều khiển cho ALU được cho trong bảng sau:
ALUOp Function ALUCtr
00 (Load hoặc Store) X 00 (ADD)
01 (XOR) X 01 (XOR)
10 (BNE) X 10 (SUB)
11 (Lệnh R)
100000 00 (ADD)
100010 10 (SUB)
101010 11 (SLT)
- Ngoài ra khối ALUControl còn đưa ra một tín hiệu điều khiển
JumpReg cho câu lệnh JR với ALUOp = 11 và Function = 001000.
- Code:
module ALUControl(ALUCtr, JumpReg, ALUOp, Function);output [1:0] ALUCtr;output JumpReg;input [1:0] ALUOp;input [5:0] Function;
wire [1:0] nALUOp;wire [5:0] nFunction;wire [1:0] R, nR;wire R1, R2, ALUCtr01, ALUCtr02, ALUCtr11, ALUCtr12, ALUCtr13;
not #50 (nALUOp[0], ALUOp[0]),(nALUOp[1], ALUOp[1]),(nFunction[0], Function[0]),
(nFunction[1], Function[1]),(nFunction[2], Function[2]),(nFunction[3], Function[3]),(nFunction[4], Function[4]),(nFunction[5], Function[5]),(nR[0], R[0]),(nR[1], R[1]);
and #100 (R[0], nFunction[0], Function[1], nFunction[2], Function[3], nFunction[4], Function[5]);
and #100 (R1, nFunction[0], Function[1], nFunction[2], Function[3], nFunction[4], Function[5]),
(R2, nFunction[0], Function[1], nFunction[2], nFunction[3], nFunction[4], Function[5]);
or #50 (R[1], R1, R2);
and #50 (ALUCtr11, nALUOp[0], ALUOp[1]), (ALUCtr12, nR[0], R[1], ALUOp[0], ALUOp[1]), (ALUCtr13, R[0], R[1], ALUOp[0], ALUOp[1]);
or #50 (ALUCtr[1], ALUCtr11, ALUCtr12, ALUCtr13);
and #50 (ALUCtr01, ALUOp[0], nALUOp[1]), (ALUCtr02, ALUOp[0], ALUOp[1], R[0], R[1]);
or #50 (ALUCtr[0], ALUCtr01, ALUCtr02);
and #100 (JumpReg, ALUOp[0], ALUOp[1], nFunction[0], nFunction[1], nFunction[2], Function[3], nFunction[4], nFunction[5]);endmodule
3.2.3. Khối dịch trái 2 (nhân 4):
- Do bộ nhớ chương trình được đánh địa chỉ byte và cấu trúc lệnh được
lưu trong 1 word, do đó đối với các lệnh rẽ nhánh, giá trị trước khi đưa vào thanh ghi
PC phải nhân với 4, hay nói cách khác là dịch trái giá trị nhị phân đi 2 đơn vị.
- Code:
module ShiftLeft2_1(data_out, data_in);output [31:0] data_out;input [31:0] data_in;
genvar i;generate
for (i=2; i<32; i=i+1) begin: SL2assign data_out[i] = data_in[i-2];
endendgenerate
assign data_out[0] = 0;assign data_out[1] = 0;
endmodule
module ShiftLeft2_2(data_out, data_in);output [27:0] data_out;input [25:0] data_in;
genvar i;generate
for (i=2; i<28; i=i+1) begin: SL2assign data_out[i] = data_in[i-2];
endendgenerateassign data_out[0] = 0;assign data_out[1] = 0;
endmodule
3.2.4. Khối mở rông (Extend):
- Phần address/immediate của các câu lệnh I-format gồm 16bit, trong khi
đối số của các lệnh hoặc địa chỉ bao gồm 32bit, do đó cần có bước mở rông trước khi
dùng để tính toán.
- Tùy theo lệnh mà mở rộng dấu hay mở rông zero, ta sử dụng 1 bit điều
khiển từ khối Control để lựa chọn kiểu mở rộng (SignEx).
- Code:
module Extend(data_out, data_in, SignEx);output [31:0] data_out;input [15:0] data_in;input SignEx;
assign data_out[15:0] = data_in;
genvar i;generate
for (i=16; i<32; i=i+1) begin: Exand #50 (data_out[i], data_in[15], SignEx);
endendgenerate
endmodule
3.2.5. Các bộ chọn kênh
- Các bộ chọn kênh được sử dụng để chọn 1 tín hiệu ra từ 2 tín hiệu vào
- Các tín hiệu điều khiển phụ thuộc vào từng câu lệnh và được đưa ra từ
khối Control
- Code:
module Muxer32(data_out, data_in1, data_in2, sel);output [31:0] data_out;input [31:0] data_in1, data_in2;input sel;
wire [31:0] f1, f2;wire nsel, dsel;
not #50 (nsel, sel);buf #50 (dsel, sel);
genvar i;generate
for (i=0; i<32; i=i+1) begin: Muxerand #50 (f1[i], nsel, data_in1[i]);and #50 (f2[i], dsel, data_in2[i]);or #50 (data_out[i], f1[i], f2[i]);
endendgenerate
endmodule
module Muxer5(data_out, data_in1, data_in2, sel);output [4:0] data_out;input [4:0] data_in1, data_in2;input sel;
wire [4:0] f1, f2;wire nsel, dsel;
not #50 (nsel, sel);buf #50 (dsel, sel);
genvar i;generate
for (i=0; i<5; i=i+1) begin: Muxerand #50 (f1[i], nsel, data_in1[i]);and #50 (f2[i], dsel, data_in2[i]);or #50 (data_out[i], f1[i], f2[i]);
endendgenerate
endmodule
3.2.6. Bộ nhớ chương trình và bộ nhớ dữ liệu:
- Bộ nhớ chương trình dùng để lưu mã máy của các câu lệnh. Bộ nhớ
chương trình có 210 word và được lưu trong file instr.dat.
- Bộ nhớ dữ liệu dùng để lưu các giá trị trong quá trình tính toán. Bộ nhớ
dữ liệu có 28 word và được lưu trong file data.dat.
- cả 2 bộ nhớ đều được đánh địa chỉ byte.
3.3. Module chính:
3.3.1. Thanh ghi PC:
- Thanh ghi PC được sử dụng để chỉ đến vị trí của câu lệnh tiếp theo sẽ
được thực hiện.
- Khi không có các câu lệnh rẽ nhánh, giá trị của thanh ghi PC sau mỗi
chu kỳ lệnh sẽ tự động tăng lên 4. Các câu lệnh rẽ nhánh J, JR, BNE sẽ có tác động
làm thay đổi giá trị của thanh ghi PC.
- Ta sử dụng 1 thanh ghi PC để lưu giá trị hiện thời và 1 thanh ghi PCIn
để lưu giá trị tiếp theo của PC khi có xung clk.
- Mỗi khi có xung clk, giá trị của thanh ghi PCIn sẽ được đặt vào thành
ghi PC, bộ nhớ chương trình sẽ sử dụng giá trị của thanh ghi PC để lấy ra câu lệnh tiếp
theo. Giá trị mới của PC sau khi thực hiện xong câu lệnh sẽ được lưu vào thanh ghi
PCIn để đợi đưa vào PC khi có xung clk tiếp theo.
3.3.2. Tính toán xung clk:
- Có 4 khối trong chip cần có xung clk theo thứ tự sau:
+ Thanh ghi PC
+ Bộ nhớ dữ liệu (data memory)
+ Bộ thanh ghi (Registers)
+ Thanh ghi PCIn
- Từ lúc có xung clk đến thanh ghi PC, tín hiệu đi qua bộ nhớ chương
trình (1000ps), bộ thanh ghi (khoảng 500ps), khối ALU (khoảng 6000ps). Do đó, ta
chọn độ trễ của xung clk cho bộ nhớ dữ liệu so với xung clk của PC là 10000ps để
đảm bảo giá trị nhận được là chính xác.
- Tương tự ta chọn độ trễ của xung clk cho thanh ghi PCIn là 10000ps.
- Tín hiệu đi qua bộ nhớ dữ liệu mất 1000ps, ta chọn độ trễ của xung clk
cho bộ thanh ghi so với bộ nhớ dữ liệu là 2000ps.
+ Việc thực hiện 1 câu lệnh phải hoàn tất trong vòng 1 chu kỳ xung clk,
do vậy ta phải chọn độ rộng của xung clk đủ lớn. Dựa vào tính toán ở trên, ta chọn độ
rộng của xung clk là 15000ps, hay chu kỳ của xung clk là 30000ps.
3.3.3. Code:
module CPU(clk);input clk;
reg reset;wire [31:0] PC, PCIn, PCIn1, PCIn2, PCIn3, PCplus4, Instruction, ExImm, SL2Imm,
JumpAdr, BranchAdr;
wire [31:0] ReadData1, ReadData2, RegWriteData, ALU2ndIn, ALUResult, MemOutput;wire [4:0] WriteRegister;wire [1:0] ALUOp, ALUCtr;wire CarryOut, zero, overflow, negative, nzero;wire RegDst, Branch, MemtoReg, MemWrite, ALUSrc, RegWrite, Jump, SignEx,
JumpReg, BranchSel;wire Memclk, Regclk, PCInclk, PCclk;
initial beginreset = 0;#50 reset = 1;#50 reset = 0;
end
assign PCclk = clk;buf #10000 (Memclk, PCclk);buf #1000 (Regclk, Memclk);buf #10000 (PCInclk, PCclk);
SinReg PCInReg(PCIn, PCIn3, reset, PCInclk, 1'b1);SinReg PCReg(PC, PCIn, 1'b0, PCclk, 1'b1);InstructionMemInsMem(Instruction, PC);Regfile Registers(ReadData1, ReadData2, RegWriteData, Instruction[25:21] ,
Instruction[20:16], WriteRegister, RegWrite, Regclk, reset);alu ALU(ALUResult, CarryOut, zero, overflow, negative,
ReadData1, ALU2ndIn, ALUCtr);DataMem DataMem(MemOutput, ALUResult, ReadData2, MemWrite,
Memclk);Control Ctrl(ALUOp, RegDst, Branch, MemtoReg, MemWrite, ALUSrc,
RegWrite, Jump, SignEx, Instruction[31:26]);ALUControl ALUCtrl(ALUCtr, JumpReg, ALUOp, Instruction[5:0]);Extend Ext(ExImm, Instruction[15:0], SignEx);ShiftLeft2_1 SL1(SL2Imm, ExImm);ShiftLeft2_2 SL2(JumpAdr[27:0], Instruction[25:0]);AddCPU Add1(PCplus4, PC, 32'h00000004);AddCPU Add2(BranchAdr, PCplus4, SL2Imm);
not #50 (nzero, zero);and #50 (BranchSel, Branch, nzero);assign JumpAdr[31:28] = PCplus4[31:28];
Muxer5 RegDstMux(WriteRegister, Instruction[20:16], Instruction[15:11], RegDst);Muxer32 ALUSrcMux(ALU2ndIn, ReadData2, ExImm, ALUSrc);Muxer32 MemtoRegMux(RegWriteData, ALUResult, MemOutput,
MemtoReg);Muxer32 BraSelMux(PCIn1, PCplus4, BranchAdr, BranchSel);Muxer32 JumpMux(PCIn2, PCIn1, JumpAdr, Jump);Muxer32 JumpRegMux(PCIn3, PCIn2, ReadData1, JumpReg);
Endmodule