- 指令分析
指令分析是第一步:MIPS指令集一共有三種指令。
R型(寄存器型):由Op(6位,下同)操作碼,Rs(5),Rt(5),Rd(5),shamt(5)移位位,func(6)功能碼組成
I型(立即數型):由Op(6),Rs(5),Rt(5),imm16(16)16位立即數組成
J型(跳轉型):由Op(6),imm26(26)26位立即數組成
下面是我選的一部分指令的分析
助記符 | 指令格式 | 示例 | 示例含義 | 操作及解釋 | ||||
R-型 | op | rs | rt | rd | shamt | func | 操作 | 解釋 |
Addu | 000000 | rs | rt | rd | 100001 | addu $1,$2,$3 | $1=$2+$3 | (rd)<-(rs)+(rt);rs=$2,rt=$3,rd=$1 |
Subu | 000000 | rs | rt | rd | 100011 | subu $1,$2,$3 | $1=$2-$3 | (rd)<-(rs)-(rt);rs=$2,rt=$3,rd=$1 |
or | 000000 | rs | rt | rd | 100101 | or $1,$2,$4 | $1=$2|$3 | (rd)<-(rs)|(rt);rs=$2,rt=$3,rd=$1 |
sltu | 000000 | rs | rt | rd | 101011 | sltu $1,$2,$3 | If($2<$3) $1=1else$1=0 | if(rs<rt)rd=1else rd=0;rs=$2,rt=$3,rd=$1 |
syscall | 000000 | rs | rt | rd | ||||
I-型 | Op | rs | rt | immediate | 示例 | 示例含義 | 操作及解釋 | |
Addiu | 001001 | Rs | Rt | immediate | Addiu $1,$2,10 | $1=$2+10 | (rt)<-(rs)+(sign-extend)immediate,rt=$1,rs=$2 | |
Andi | 001100 | Rs | Rt | immediate | Andi $1,$2,10 | $1=$2&10 | (rt)<-(rs)&(zero-extend)immediate,rt=$1,rs=$2 | |
Lw | 100011 | Rs | Rt | immediate | Lw $1,10($2) | $1=Memory[$2+10] | (rt)<-Memory(rs)+(sign_extend)offset),rt=$1,rs=$2 | |
Sw | 101011 | Rs | Rt | immediate | Sw $1,10($2) | MeMORY[$2+10]=$1 | Memory[(rs)+(sign_extend)offset]<-(rt),rt=$1,rs=$2 | |
Beq | 000100 | Rs | Re | immediate | Beq $1,$2,40 | If($1=$2) goto PC+4+40 | If((rt)=(rs))then (PC)<-(PC)+((sign_extend)offset<<2),rs=$1,rt=$2 | |
J-型 | op | address | 示例 | 示例含義 | 操作及解釋 | |||
Jal | 000011 | address | Jal 10000 | $31=PC+4 goto 10000 | ($31)<-(PC)+4;(PC)<-((zero_extend)address<<2),address=10000/4 |
2.基本資料通路設計
- 注意:此處NPC和PC合二為一成為PC
運作流程:pc開始->指令存儲器->取指令->控制器->分析指令->得到操作的控制信号->發送到各個器件
取完指令之後->IR送寄存器組->選擇通路->送到ALU進行計算->進行後續操作。
1.時序子產品設計與仿真
(1)原理圖
(2)功能
- 輸入引腳
- H_RUN輸入引腳,L_STEP輸入引腳,時序控制信号。
H_RUN | L_STEP | 功能 |
X | 時序電路不輸出節拍信号 | |
低變高 | 時序電路僅輸出一組節拍信号,供單步調試用。 | |
1 | 1 | 時序電路輸出連續節拍信号 |
- CLK輸入引腳,主時鐘信号。
- RST1輸入引腳,主複位控制信号,低電平複位。
- 輸出引腳
共4個節拍信号T1、T2、T3、T4。
(3)仿真圖
- 寄存器堆子產品
(1)原理圖
(2)功能
- 輸入引腳
clkread是寄存器堆的讀時鐘,clkwr是寄存器堆的寫時鐘,Reset是寄存器堆的複位信号,Regwr是寄存器堆的讀寫控制信号,高電平寫,低電平讀,RA[4..0]寄存器堆端口的輸入端,RB[4..0]寄存器堆端口的輸入端,RW[4..0]是寄存器堆的輸出端,BusW[31..0]是寄存器堆的輸入端,readnum[4..0]是寄存器堆的輸入端,j是jal型指令的控制信号。
- 輸出引腳
BusA[31..0]和BusB[31..0]是寄存器堆的通道輸出端,readdata[31..0]是讀取寄存器内容的輸出端。
- 仿真
- 資料存儲器ROM和程式存儲器RAM子產品
(1)原理圖
ROM
RAM
(2)功能
- 輸入引腳
address是RAM存儲器的位址輸入端口,clock是RAM存取器的讀寫時鐘控制信号。
data[31..0]是RAM存儲器的資料輸入端口,wren是讀寫控制信号,高電平寫,低電平讀,address[7..0]是RAM存儲器的位址輸入端口,clock是RAM存儲器的讀寫時鐘控制信号。
- 輸出引腳
q[31..0]是RAM和ROM存儲器的資料輸出端口。
(3)仿真圖
ROM
RAM
3.ALU運算部件
(1)原理圖
(2)功能
- 輸入引腳
A[31..0]和B[31..0]是運算器的輸入端,ALUop[2..0]是運算器的控制信号
- 輸出引腳
ALUout[31..0]是運算器輸出結果,zero是做減法時,結果為零時發出的信号
(3)仿真
- PC程式計數器
(1)原理圖
(2)功能
- 輸入引腳
reset是重置運算器的控制信号,enable是運算器的使能信号,clk是時鐘脈沖信号,PCop[1..0]是控制控制PC進行不同操作的信号,imm26[25..0]是傳輸的立即數,zero是ALU做減法時零标志位,beq是進行beq操作時發出的信号
- 輸出引腳
PCout[31..0]輸出下條指令的位址,PC4用于Jal操作時,下條指令位址的輸出。
(3)仿真
- MUX多路選擇器
(1)原理圖
(2)功能
- 輸入引腳
A0[31..0]、A1[31..0]、A2[31..0]、A3[31..0]是四個資料輸入端,S是控制選擇的控制信号。
- 輸出引腳
Y[31..0]是資料輸出端。
(3)仿真
- EXT拓展電路
(1)原理圖
(2)功能
- 輸入引腳
imm16[15..0]是16立即數資料輸入輸入端,Extop是控制ext拓展器進行符号拓展或者零拓展的控制信号。
- 輸出引腳
Extout[31..0]是資料輸出端,是拓展後輸出的數值。
(3)仿真
- 控制器的設計
(1)原理圖
- 功能
- 輸入引腳
op[5..0]和func[5..0]是資料輸入端,決定控制信号。
- 輸出引腳
ALUop[2..0]、PCop[1..0]、MUX_alub、MUX_busw[1..0]、MUX_rw[1..0]、extop、Regwr、DMwr、Beq、halt、j是資料輸出端,分别控制ALU的操作,控制PC做不同的指令跳轉,控制進入alu的線路,busw的輸出端,控制不同信号的讀寫功能,拓展
仿真
- 完整資料通路設計
- 各子產品的連接配接分析
指令 | PC | Im | RF | EXT | ALU | DM | ||||||
輸入引腳 | PCin | Imm26 | Imaddr | RA | RB | RW | BusW | Imm16 | BusA | BusB | Dmaddr | Dmin |
subu | PC.pcout | PC.pcout | IR[25:21] | IR[20:16] | IR[15:11] | ALU.aluout | RF.BusA | RF.BusB | ||||
addiu | PC.pcout | PC.pcout | IR[25:21] | IR[20:16] | ALU.aluout | IR[15:0] | RF.BusA | EXT.extout | ||||
beq | PC.pcout | IR[25:0] | PC.pcout | IR[25:21] | IR[20:16] | RF.BusA | RF.BusB | |||||
lw | PC.pcout | PC.pcout | IR[25:21] | IR[20:16] | DM.dmout | IR[15:0] | RF.BusA | EXT.extout | ALU.aluout | |||
sw | PC.pcout | PC.pcout | IR[25:21] | IR[20:16] | IR[15:0] | RF.BusA | EXT.extout | ALU.aluout | RF.BusB | |||
jal | PC.pcout | IR[25:0] | PC.pcout | 0x1F | PC.pc4 | |||||||
合并 | PC.pcout | IR[25:0] | PC.pcout | IR[25:21] | IR[20:16] | 0:IR[15:11] 1:IR[20:16] 2:OX1F | 0:ALU.aluout 1:DM.dmout 2:PC.pc4 | IR[15:0] | RF.BusA | 0:RF.BusB 1:EXT.extout | ALU.aluout | RF.BusB |
- 控制信号分析
Regwr | DMwr | Beq | halt | EXtop | MUX_alub | ALU_op | J | PCop | MUX_busw | MUX_RW |
addu | 1 | 000 | 10 | 00 | 00 | |||||
subu | 1 | 001 | 10 | 00 | 00 | |||||
sltu | 1 | 100 | 10 | 00 | 00 | |||||
or | 1 | 010 | 10 | 00 | 00 | |||||
syscall | 1 | 000 | 10 | 00 | 00 | |||||
addiu | 1 | 1 | 1 | 000 | 10 | 00 | 01 | |||
lw | 1 | 1 | 1 | 000 | 10 | 01 | 01 | |||
sw | 1 | 1 | 1 | 000 | 10 | 01 | 01 | |||
beq | 1 | 1 | 1 | 001 | 00 | 01 | 01 | |||
andi | 1 | 1 | 1 | 011 | 10 | 00 | 01 | |||
jal | 1 | 000 | 1 | 01 | 10 | 10 | ||||
addu+subu+sltu+or+addiu+lw+andi+jal | sw | beq | halt | addiu+lw+sw+beq+andi | addiu+lw+sw+bqe+andi | 000:addu+syscall+addiu+lw+sw+andi+jal,001:subu+beq,010:or,011:andi,100:sltu | jal | 10:addu+subu+sltu+or+syscall+addiu+lw+sw+andi,00:beq,01:jal | 00:addu+subu+sltu+or+syscal+addiu,01:lw+sw+beq,10:jal | 00:addu+subu+sltu+or+syscall+sw,01addiu+sw+lw+andi+beq,10:jal |
1、測試程式
為了驗證CPU的正确性,編寫了表6.1測試程式,其中的寄存器編碼、立即數、位址等指令格式中的資訊必須具體化。
表6.1 測試程式
序号 | 彙編語言 | 操作碼 | 位址碼 | 16進制機器編碼 | 功能 | |
Op | function | |||||
1 | addu $s0,$zero,$zero | 000000 | 100001 | 00008021 | $s0=$zero+$zero | |
2 | addiu $s1,$zero,5 | 001001 | 4 | 24110005 | $s1=$zero+5 | |
3 | subu $s2,$s1,$s0 | 000000 | 100001 | 8 | 02309023 | $s2=$s1-$s0 |
4 | or $s3,$s1,$s2 | 000000 | 100101 | 12 | 02329825 | $s3=$s1|$s2 |
5 | lw $s4,4($s0) | 100011 | 16 | 8e140004 | $s4=memory[$s0+4] | |
6 | sltu $s5,$s1,$s2 | 000000 | 101011 | 18 | 0232a82b | If($s1<$s2)$s5=1else$s5=0 |
7 | sw $s6,8($s0) | 101011 | 24 | ae160008 | Memory[($s0+8)/4]=$s6 | |
8 | andi $s7,$s0,5 | 001100 | 28 | 32170005 | $s7=$s0&5 | |
9 | beq $s1,$s2,4 | 000100 | 32 | 12320004 | If($s1=$s2)pc=pc+4+16else pc=pc+4 | |
10 | Jal 9 | 000011 | 40 | 0c000009 | Pc=36 | |
11 | syscall | 000000 | 001100 | 36 | 0000000c | Halt |
2、仿真圖
測試程式的仿真結果如圖6.1所示。
圖6.1 程式運作仿真圖
從仿真圖可見,程式運作完全正确,執行停機指令HALT時,指令不再跳轉。
alut.v
module alut(A,B,ALUop,ALUout,zero);
input [31:0] A,B;
input [2:0] ALUop;
output [31:0] ALUout;
output zero;
reg [31:0] res;
assign zero=(res==0)?1:0;
assign ALUout=res;
always @*
begin
case(ALUop)
3'b000:res<=A+B;
3'b001:res<=A-B;
3'b010:res<=A|B;
3'b011:res<=A&B;
3'b100:res<=A<B?1:0;
endcase
end
Endmodule
controll.v
module Controll(op,func,ALUop,PCop,MUX_alub,MUX_busw,MUX_rw,extop,Regwr,DMwr,Beq,halt,j);
input [5:0] op;
input [5:0] func;
output Regwr,DMwr,Beq,halt,extop,MUX_alub,j;
output [1:0] PCop,MUX_busw,MUX_rw;
output [2:0] ALUop;
//R
wire addu = (op == 6'b000000 & func == 6'b100001)?1:0;
wire subu = (op == 6'b000000 & func == 6'b100011)?1:0;
wire Or = (op == 6'b000000 & func == 6'b100101)?1:0;
wire sltu = (op == 6'b000000 & func == 6'b101011)?1:0;
wire syscall= (op == 6'b000000 & func == 6'b001100)?1:0;
//I
wire addiu= (op == 6'b001001)?1:0;
wire andi = (op == 6'b001100)?1:0;
wire lw = (op == 6'b100011)?1:0;
wire sw = (op == 6'b101011)?1:0;
wire beq = (op == 6'b000100)?1:0;
//J
wire jal = (op == 6'b000011)?1:0;
assign Regwr=addu | subu | Or | sltu | addiu | lw | andi | jal;
assign DMwr=sw;
assign Beq=beq;
assign halt=syscall;
assign extop=addiu | lw | sw | andi;
assign MUX_alub=addiu | lw | sw | andi;
assign j=jal;
assign ALUop[2]=sltu;
assign ALUop[1]=Or | andi;
assign ALUop[0]=subu | andi | beq;
assign PCop[1]=addu | subu | Or | sltu | syscall | addiu | andi | lw | sw;
assign PCop[0]=jal;
assign MUX_busw[1]=beq | jal ;
assign MUX_busw[0]=lw | sw;
assign MUX_rw[1]=jal;
assign MUX_rw[0]=addiu | andi | lw | sw | beq ;
endmodule
EXT.v
module EXT(imm16,Extop,Extout);
input [15:0] imm16;
input Extop;
output reg [31:0] Extout;
always @(imm16 or Extop)
if(Extop)
if(~imm16[15])
begin
Extout<={{16{1'b0}},imm16[15:0]};
end
else
begin
Extout<={{16{imm16[15]}},imm16[15:0]};
end
endmodule
MUX2.v
module MUX2(A0,A1,S,Y);
input [31:0]A0,A1;
input S;
output [31:0]Y;
function [31:0]select;
input [31:0]A0,A1;
input S;
case(S)
1'b0:select=A0;
1'b1:select=A1;
endcase
endfunction
assign Y = select(A0,A1,S);
Endmodule
MUX4_r.v
module MUX4_r (A0, A1, A2, A3, S, Y);
input [4:0] A0, A1, A3;
input [1:0] A2;
input [1:0] S;
output [4:0] Y;
function [31:0] select;
input [4:0] A0, A1, A3;
input [1:0] A2;
input [1:0] S;
case(S)
2'b00: select = A0;
2'b01: select = A1;
2'b10: select = A2;
2'b11: select = A3;
endcase
endfunction
assign Y = select (A0, A1, A2, A3, S);
endmodule
MUX4.v
module MUX4 (A0, A1, A2, A3, S, Y);
input [31:0] A0, A1, A2, A3;
input [1:0] S;
output [31:0] Y;
function [31:0] select;
input [31:0] A0, A1, A2, A3;
input [1:0] S;
case(S)
2'b00: select = A0;
2'b01: select = A1;
2'b10: select = A2;
2'b11: select = A3;
endcase
endfunction
assign Y = select (A0, A1, A2, A3, S);
endmodule
pcall.v
module pcall(reset,enable,clk,PCop,imm26,zero,beq,PCout,PC4);
input enable,reset,clk,zero,beq;
input [1:0] PCop;
input [25:0] imm26;
output reg [31:0] PC4;
output reg[31:0] PCout;
initial
begin
PCout<=32'h00000000;
end
always @(posedge clk or posedge reset )
begin
if (reset)
begin
PCout<=32'h00000000;
end
else
if (enable)
if(PCop==2'b00&&beq&&zero)
begin
PCout<=PCout+32'h00000004+{{16{imm26[15]}},imm26[15:0],2'b00};
end
else if(PCop==2'b01)
begin
PC4<=PCout+32'h00000004;
PCout<={PCout[31:28],imm26,2'b00};
end
else if(PCop==2'b10)
begin
PCout<=PCout+32'h00000004;
end
else
begin
PCout<=PCout+32'h00000004;
end
end
endmodule
RegisterFile.v
module RegisterFile(clkread,clkwr,Reset,RegWr,RA,RB,RW,BusW,BusA,BusB,readnum,readdata,j);
input clkread,clkwr,Reset,RegWr,j;
input [4:0] RA,RB,RW,readnum;
input [31:0] BusW;
output reg [31:0] BusA,BusB;
output [31:0] readdata;
reg [31:0] regfile[31:0];
integer i;
initial
begin
regfile[0]=32'h00000000;
end
assign readdata=regfile[readnum];
always @(posedge clkwr or posedge Reset)
begin
if (Reset)
begin
for (i=1;i<=31;i=i+1)
regfile[i]<=0;
end
else
begin
if (RegWr)
if(j)
begin
regfile[31]<=BusW;
end
else
begin
regfile[RW]<=BusW;
end
end
end
always @(posedge clkread)
begin
BusA<=regfile[RA];
BusB<=regfile[RB];
end
endmodule