由于最近的计算机组成原理的课设,从modelsim 到iSe的过渡,需要将自己设计的主机和外设下载到芯片(XC6SLX45)上,由于使用IP核封装的IM(指令存储器)在读取指令的时候需要一个时钟clk ,在J,JR ,Jal,BEQ等跳转指令时最后一个状态pc寄存器(地址寄存器)写使能置1,下一条指令的S0状态将地址写入pc寄存器,然后进入下一个状态(译码状态),这时才从指令存储器(IM)中读取到了目的指令,但是这条目的指令写不进指令寄存器(IMREG),所以在跳转类指令后面增加一个延时状态(不为所有的指令增加延时状态,提高机器的运算速度),在延时状态中将新的地址写入pc寄存器,在S0状态时可以读取Im中的内容,然后在S1(译码阶段)写入IM寄存器。其他非跳转指令不存在这种问题。
ISE中简单创建IM(指令存储器)教程:
第一步:右键工程名字——>点击new source
第二部:
选择IP核然后在filename 填上名字(自己设置)
第三步:
第四步:
点击next
第五步:
1024 X 32 4K的存储空间
点击next
点击next next next generate
控制器代码:
module controller(op,func,regdst,alusr,memtoreg,regwrite,memwrite,pcwr,imregwr,npc_sel,extop,aluctr,isaddi,stlo,islb,issb,clk,reset,zero,isda,intreq,cp0_wen,bridge_wen,MT,setexl,clearexl,intpc);
input [5:0] op,func;
input [4:0] MT;
input clk,reset,zero,isda,intreq;
output [1:0] regdst;
output alusr,regwrite,memwrite,isaddi,stlo,islb,issb,pcwr,imregwr,setexl,clearexl;
output [1:0] npc_sel;
output [1:0]memtoreg;
output[1:0]extop;
output [1:0] aluctr;
output cp0_wen,bridge_wen,intpc;
wire r_type = ~|op;
wire s0,s1,s2,s3,s4,s5,s6,s7,s8,s9,s10,s11;
wire addu = r_type & func[5] & ~func[4] & ~func[3] & ~func[2] & ~func[1] & func[0];
wire subu = r_type & func[5] & ~func[4] & ~func[3] & ~func[2] & func[1] & func[0];
wire ori = ~op[5]&~op[4]&op[3]&op[2]&~op[1]&op[0];
wire lw = op[5]&~op[4]&~op[3]&~op[2]&op[1]&op[0];
wire sw = op[5]&~op[4]&op[3]&~op[2]&op[1]&op[0];
wire beq = ~op[5]&~op[4]&~op[3]&op[2]&~op[1]&~op[0];
wire lui = ~op[5]& ~op[4]& op[3]& op[2]& op[1]& op[0];
wire j = ~op[5]&~op[4]&~op[3]&~op[2]&op[1]&~op[0];
wire addi = ~op[5] & ~op[4] & op[3] & ~op[2] & ~op[1] & ~op[0];
wire addiu = ~op[5] & ~op[4] & op[3] & ~op[2] & ~op[1] & op[0];
wire slt = r_type & func[5] & ~func[4] & func[3] & ~func[2] & func[1] & ~func[0];
wire jal = ~op[5] & ~op[4] & ~op[3] & ~op[2] & op[1] & op[0];
wire jr = r_type&~func[5]&~func[4]&func[3]&~func[2]&~func[1]&~func[0];
wire lb = op[5]&~op[4]&~op[3]&~op[2]&~op[1]& ~op[0];
wire sb = op[5]&~op[4]&op[3]&~op[2]&~op[1]& ~op[0];
wire isbgez = ~op[5]&~op[4]&~op[3]&~op[2]&~op[1]&op[0];
wire MTC0=~op[5]&op[4]&~op[3]&~op[2]&~op[1]&~op[0]&~MT[4]&~MT[3]&MT[2]&~MT[1]&~MT[0];
wire MFC0=~op[5]&op[4]&~op[3]&~op[2]&~op[1]&~op[0]&~MT[4]&~MT[3]&~MT[2]&~MT[1]&~MT[0];
wire ERET=~op[5]&op[4]&~op[3]&~op[2]&~op[1]&~op[0]&MT[4]&~func[5] & func[4] & func[3] & ~func[2] & ~func[1] & ~func[0];
parameter [3:0] S0 = 4'b0000,S1 = 4'b0001,S2 = 4'b0010,S3 = 4'b0011,S4 = 4'b0100,S5 = 4'b0101,S6 = 4'b0110,S7 = 4'b0111,S8 = 4'b1000,S9 = 4'b1001,S10=4'b1010,S11=4'b1011,S12=4'b1100;
reg [3:0] next,current;
always @(posedge clk,posedge reset)
begin
if(reset==1)
begin
current<=S0;
end
else
begin
current<=next;
end
end
always @(current,addu,subu,ori,lw,sw,beq,lui,j,addi,addiu,slt,jal,jr,lb,sb,isbgez,MTC0,MFC0,intreq,ERET)
begin
case(current)
S0:next=S1;
s1:begin
if(lw|sw|lb|sb|MTC0|MFC0)
begin
next=S2;
end
else if(addu|subu|ori|lui|addi|addiu|slt)
begin
next=S6;
end
else if(beq|isbgez)
begin
next=S8;
end
else if(j|jal|jr|ERET)
begin
next=S9;
end
end
S2: begin
if(lw|lb|MFC0)
begin
next=S3;
end
else if(sw|sb|MTC0)
begin
next=S5;
end
end
S3:begin
next=S4;
end
S4:
begin
if(intreq==1)
begin
next=S10;
end
else
begin
next=S0;
end
end
S5:begin
if(intreq==1)
begin
next=S10;
end
else
begin
next=S0;
end
end
S6:begin
if(addu|subu|ori|lui|addi|addiu|slt)
begin
next=S7;
end
end
S7:begin
if(intreq==1)
begin
next=S10;
end
else
begin
next=S0;
end
end
S8:begin
next=S11;
end
S9:begin
next=S11;
end
S10:next=S12;
S11:
begin
if(intreq==1)
begin
next=S10;
end
else
begin
next=S0;
end
end
default:next=S0;
endcase
end
assign s0=(~current[3])&(~current[2])&(~current[1])&(~current[0]);
assign s1=(~current[3])&(~current[2])&(~current[1])&( current[0]);
assign s2=(~current[3])&(~current[2])&( current[1])&(~current[0]);
assign s3=(~current[3])&(~current[2])&( current[1])&( current[0]);
assign s4=(~current[3])&( current[2])&(~current[1])&(~current[0]);
assign s5=(~current[3])&( current[2])&(~current[1])&( current[0]);
assign s6=(~current[3])&( current[2])&( current[1])&(~current[0]);
assign s7=(~current[3])&( current[2])&( current[1])&( current[0]);
assign s8=( current[3])&(~current[2])&(~current[1])&(~current[0]);
assign s9=( current[3])&(~current[2])&(~current[1])&( current[0]);
assign s10=( current[3])&(~current[2])&(current[1])&( ~current[0]);
assign intpc=intreq&&s10;
assign setexl=s10;
assign clearexl=ERET;
assign islb=(lb==1)?1:0;
assign issb=(sb==1)?1:0;
assign isaddi = (addi==1)?1:0;
assign stlo=(slt==1)?1:0;
assign imregwr=(s0==1)?1:0;
assign pcwr=(s0|(j|jr|jal)&s9|(beq&s8&zero)|(isbgez&s8&isda)|s10|ERET&s9);
assign regdst[0] = addu | subu | slt;//改动版
assign regdst[1]= jal;
assign alusr= ori | sw | lw | lui | addi | addiu | lb | sb ;
assign memtoreg[0]= lw|lb|MFC0;
assign memtoreg[1]= jal|MFC0;//MFC0 为11;
assign regwrite= ((addu | subu | ori | lui | addi | slt | addiu)&&s7)||(lw|lb|MFC0)&s4||(jal&s9);
assign memwrite= (sw|sb)&s5;
assign bridge_wen= (sw|sb)&s5;//SW向外设输出
assign cp0_wen=MTC0&s5;//向CP0写数据
assign npc_sel[0]= (isbgez|beq|jr)&(~s0);//改动
assign npc_sel[1]= (jr|jal|j)&(~s0);//改动ai
assign extop[0]= lw | sw | addi | addiu|lb|sb;
assign extop[1]= lui;
assign aluctr[1]= ori;
assign aluctr[0]= subu | beq | slt;
endmodule