實驗內容
1. 掌握MIPS R型和I型指令的綜合資料通路設計,掌握資料流的多路選通控制方法
2. 掌握取數指令lw和存數指令sw的尋址方式及其有效地址產生的方法
3. 實作MIPS的部分I型和 R型指令的功能
解決方法
1. 分析MIPS I型指令的特點,與R型指令有明顯的不同:沒有rd暫存器,使用rt作為目的暫存器;源運算元中有一個為立即數,位于指令的低16位
2. 在暫存器堆模塊的寫地址輸入埠設定二選一選擇器,由于R型和I型的目的暫存器不同,由rd_rt_s控制
3. 16位的立即數imm需要經過擴展才能與rs執行運算操作,對于有符號數的操作,執行的是符號擴展,對于無符號數的操作,執行的是0擴展
4. R型指令執行rs和rt運算,結果送rd;而I型立即數即數尋址指令則執行rs和擴展后的立即數imm運算,結果送rt,因此ALU的輸入資料B端有兩個選擇:rt或者imm,仍可以通過二選一資料選擇器,用rt_imm_s控制信號
5. 需要添加一個資料存盤器RAM存放指令訪問的資料,讀出的資料,意味著要在暫存器堆的寫埠加個選擇器,用alu_mem_s控制信號,其中要注意一點就是資料存盤器的clk至少是CPU頻率的2倍以上,我使用了兩個clk輸入解決這個問題
6. 在實際寫代碼時,要注意頂層模塊中,實體下層模塊的順序,由于譯碼模塊變數多,我將其抽離出來,為了使頂層模塊看起來簡潔
7. 涉及實驗: 具體用到的實驗是多功能ALU設計實驗、暫存器堆設計實驗、取指令與指令譯碼實驗
8. 代碼展示
頂層模塊
module CPU(clk,rst,OF,ZF,F,ALU_OP,M_R_Data,rd_rt_s,imm_s,rt_imm_s,Mem_Write,alu_mem_s,Write_Reg,clk_M,R_Data_B,Inst_code);
input clk,rst,clk_M;
wire [31:0]Inst_code;
wire [5:0]op_code,funct;
wire [4:0]rs_addr,rt_addr,rd_addr,shamt;
output [31:0]F;
output OF,ZF;
output [31:0]M_R_Data;
output [2:0]ALU_OP;
wire [31:0]Mem_Addr;
wire [4:0]W_Addr;
output rd_rt_s,imm_s,rt_imm_s,Mem_Write,alu_mem_s,Write_Reg;
output [31:0]Inst_code;
wire [31:0]imm_data;
wire [31:0]R_Data_A;
output [31:0] R_Data_B;
wire [15:0]imm;
wire [31:0]ALU_B;
wire [31:0]W_Data;
PC pc1(clk,rst,Inst_code);
assign op_code = Inst_code[31:26];
assign rs_addr = Inst_code[25:21];
assign rt_addr = Inst_code[20:16];
assign rd_addr = Inst_code[15:11];
assign shamt = Inst_code[10:6];
assign funct = Inst_code[5:0];
assign imm = Inst_code[15:0];
OP_Func op(op_code,funct,Write_Reg,ALU_OP,rd_rt_s,imm_s,rt_imm_s,Mem_Write,alu_mem_s);
assign W_Addr = (rd_rt_s)?rt_addr:rd_addr;
assign imm_data = (imm_s)?{{16{imm[15]}},imm}:{{16{1'b0}},imm};
assign W_Data = alu_mem_s?M_R_Data:F;
Fourth_experiment_first F1(rs_addr,rt_addr,Write_Reg,R_Data_A,R_Data_B,rst,~clk,W_Addr,W_Data);
assign ALU_B = (rt_imm_s)?imm_data:R_Data_B;
Third_experiment_first T1(OF,ZF,ALU_OP,R_Data_A,ALU_B,F);
RAM RAM_B (
.clka(clk_M), // input clka
.wea(Mem_Write), // input [0 : 0] wea
.addra(F[5:0]), // input [5 : 0] addra
.dina(R_Data_B), // input [31 : 0] dina
.douta(M_R_Data) // output [31 : 0] douta
);
endmodule
PC(取指令模塊)
module PC(clk,rst,Inst_code);
input clk,rst;
wire [31:0]PC_new;
reg[31:0]PC;
initial
PC = 32'h0000_0000;
output [31:0]Inst_code;
assign PC_new = PC +4;
Inst_Rom rom(
.clka(clk), // input clka
.addra(PC[7:2]), // input [5 : 0] addra
.douta(Inst_code) // output [31 : 0] douta
);
always@(posedge clk or posedge rst)
begin
if(rst)
begin PC <= 32'h0000_0000; end
else
begin PC <= PC_new; end
end
endmodule
OP_Func(譯碼模塊)
module OP_Func(op_code,funct,Write_Reg,ALU_OP,rd_rt_s,imm_s,rt_imm_s,Mem_Write,alu_mem_s);
input [5:0]op_code;
input [5:0]funct;
output reg[2:0]ALU_OP;
output reg Write_Reg;
output reg rd_rt_s;
output reg imm_s;
output reg rt_imm_s;
output reg Mem_Write;
output reg alu_mem_s;
always@(*)
begin
Write_Reg=1;
ALU_OP=0;
rd_rt_s=0;
imm_s=0;
rt_imm_s=0;
Mem_Write=0;
alu_mem_s=0;
if(op_code==0)
begin
case(funct)
6'b100000:begin ALU_OP=3'b100; end
6'b100010:begin ALU_OP=3'b101; end
6'b100100:begin ALU_OP=3'b000;end
6'b100101:begin ALU_OP=3'b001;end
6'b100110:begin ALU_OP=3'b010;end
6'b100111:begin ALU_OP=3'b011;end
6'b101011:begin ALU_OP=3'b110;end
6'b000100:begin ALU_OP=3'b111;end
endcase
end
else
begin
case(op_code)
6'b001000:begin rd_rt_s=1;imm_s=1;rt_imm_s=1;ALU_OP=100;end
6'b001100:begin rd_rt_s=1;rt_imm_s=1;ALU_OP=000; end
6'b001110:begin rd_rt_s=1;rt_imm_s=1;ALU_OP=010;end
6'b001011:begin rd_rt_s=1;rt_imm_s=1;ALU_OP=110; end
6'b100011:begin rd_rt_s=1;imm_s=1;rt_imm_s=1;alu_mem_s=1;ALU_OP=100; end
6'b101011:begin imm_s=1;rt_imm_s=1;ALU_OP=100;Write_Reg=0;Mem_Write=1; end
endcase
end
end
endmodule
Fourth_experiment_first(暫存器堆模塊)
module Fourth_experiment_first(R_Addr_A,R_Addr_B,Write_Reg,R_Data_A,R_Data_B,Reset,Clk,W_Addr,W_Data);
input [4:0]R_Addr_A,R_Addr_B,W_Addr;
input Write_Reg,Reset,Clk;
input[31:0] W_Data;
output [31:0] R_Data_A,R_Data_B;
reg [31:0] REG_Files[0:31];
integer i=0;
initial
for(i=0;i<32;i=i+1) REG_Files[i]<=0;
always @ (posedge Clk or posedge Reset)
begin
if(Reset)
begin
for(i=0;i<=31;i=i+1)
REG_Files[i]<=0;
end
else
begin
if(Write_Reg)
REG_Files[W_Addr]<=W_Data;
end
end
assign R_Data_A = REG_Files[R_Addr_A];
assign R_Data_B = REG_Files[R_Addr_B];
endmodule
Third_experiment_first(ALU模塊)
module Third_experiment_first(OF,ZF,ALU_OP,A,B,F);
input [2:0]ALU_OP;
input [31:0]A,B;
output reg[31:0]F;
reg C32;
output reg OF;
output reg ZF;
always @(ALU_OP or A or B)
begin
OF = 0;
C32 = 0;
case(ALU_OP)
3'b000:F<=A&B;
3'b001:F<=A|B;
3'b010:F<=A^B;
3'b011:F<=A~^B;
3'b100:{C32,F}<=A+B;
3'b101:{C32,F}<=A-B;
3'b110:begin if(A<B) F<=32'h0000_0001;else F<=32'h0000_0000;end
3'b111:begin F<=B<<A;end
endcase
if(F==32'h0000_0000)
ZF<=1;
else
ZF<=0;
if(ALU_OP == 3'b100 || ALU_OP == 3'b101)
OF<=C32^F[31]^A[31]^B[31];
else
OF <=0;
end
endmodule
MIPS32.coe
memory_initialization_radix=16;
memory_initialization_vector=38011234,20026789,20039000,38040010,00822804,00253025,00833804,00464020,00414822,00225022,206b7fff,206c8000,314dffff,2c4e6788,2c4f678a,ac8b0000,ac0c0014,ac8d0010,ac8e0014,8c100010,8c910004,02119025,8c930010,8c940014,0274a827,8c96fff0,8c97fff4,02d7c02b;
測驗模塊
module test;
reg clk;
reg rst;
reg clk_M;
wire OF;
wire ZF;
wire [31:0] F;
wire [2:0] ALU_OP;
wire [31:0] M_R_Data;
wire rd_rt_s;
wire imm_s;
wire rt_imm_s;
wire Mem_Write;
wire alu_mem_s;
wire Write_Reg;
wire [31:0] R_Data_B;
wire [31:0] Inst_code;
CPU uut (
.clk(clk),
.rst(rst),
.OF(OF),
.ZF(ZF),
.F(F),
.ALU_OP(ALU_OP),
.M_R_Data(M_R_Data),
.rd_rt_s(rd_rt_s),
.imm_s(imm_s),
.rt_imm_s(rt_imm_s),
.Mem_Write(Mem_Write),
.alu_mem_s(alu_mem_s),
.Write_Reg(Write_Reg),
.clk_M(clk_M),
.R_Data_B(R_Data_B),
.Inst_code(Inst_code)
);
always #9 clk_M = ~clk_M;
always #20 clk =~clk;
initial begin
clk = 0;
rst = 1;
clk_M = 0;
#2;
rst = 0;
end
endmodule
友情提示
1.有的同學會把在頂層模塊存資料存盤器的地址和PC的地址弄混,大家會問為什么PC的存盤器是取[7:2],而頂層模塊存資料存盤器的地址[5:0],主要原因就在PC=PC+4這個陳述句上,我們的存盤器還是按照位元組去尋址的,如果我們不取[7:2]的地址就會導致中間幾條指令跳過,而頂層資料模塊就是逐一增加的
2.資料存盤器的clk至少是CPU頻率的2倍以上
3.開始的時候,rst一定要拉高哦
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/240574.html
標籤:其他
下一篇:【ArcGIS風暴】ArcGIS tif轉jpg:JPEG壓縮僅支持8位或16位無符號資料(具有一個或三個波段,且沒有色彩映射表)解決方案!
