多周期cpu设计(verilog)
Posted sysu_zjl
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了多周期cpu设计(verilog)相关的知识,希望对你有一定的参考价值。
由于之前设计过单周期,所以这里很多模块都是类似的
我是把所有数据选择器的模块都单独拿出来,这里主要有
32位的4选1数据选择器,5位的3选1选择器,32位的2选1选择器,对于pc+4、j和jal指令跳转的pc值都单独变成一个模块
上代码
写control unit时要根据不同的指令并且不同的状态发出不同的信号,其他信号为默认信号
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 14:24:34 05/12/2016
// Design Name:
// Module Name: sc_cpu
// Project Name:
// Target Devices:
// Tool versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module sc_cpu(op, func, z, clock, resetn,
wpc, wir, Inswmem, Datawmem, wreg, regrt, m2reg, aluc, alusrcb, pcsource, sext, state, wrRegData);
input [5:0] op, func;
input z, clock, resetn;
output reg wpc, wir, Inswmem, wreg,m2reg, wrRegData;
output reg Datawmem;
output reg [2:0] aluc;
output reg [1:0] pcsource, regrt;
output reg sext,alusrcb;
output reg [2:0] state;
parameter [2:0] sif = 3'b000, // IF state
sid = 3'b001, // ID state
sexe = 3'b010, // EXE state
smem = 3'b011, // MEM state
swb = 3'b100; // WB state
reg [2:0] next_state;
wire i_add,i_addi,i_sub,i_ori,i_and,i_or,i_sll, i_slt, i_j, i_jr, i_jal, i_move,i_sw,i_lw,i_beq,i_halt;
assign i_add = (op[5:0] == 6'b000000) ? 1 : 0;
assign i_sub = (op[5:0] == 6'b000001) ? 1 : 0;
assign i_addi = (op[5:0] == 6'b000010) ? 1 : 0;
assign i_or = (op[5:0] == 6'b010000) ? 1 : 0;
assign i_and = (op[5:0] == 6'b010001) ? 1 : 0;
assign i_ori = (op[5:0] == 6'b010010) ? 1 : 0;
assign i_sll = (op[5:0] == 6'b011000) ? 1 : 0;
assign i_move = (op[5:0] == 6'b100000) ? 1 : 0;
assign i_slt = (op[5:0] == 6'b100111) ? 1 : 0;
assign i_sw = (op[5:0] == 6'b110000) ? 1 : 0;
assign i_lw = (op[5:0] == 6'b110001) ? 1 : 0;
assign i_beq = (op[5:0] == 6'b110100) ? 1 : 0;
assign i_j = (op[5:0] == 6'b111000) ? 1 : 0;
assign i_jr = (op[5:0] == 6'b111001) ? 1 : 0;
assign i_jal = (op[5:0] == 6'b111010) ? 1 : 0;
assign i_halt = (op[5:0] == 6'b111111) ? 1 : 0;
always @* begin // control signals' default outputs:
wpc =0; // do not write pc
wir =0; // do not write ir
Inswmem =0; // do not write memory
Datawmem = 0;
wreg =0; // do not write register file
aluc = 4'bx000; // ALU operation: add
alusrcb = 2'h0; // ALU input b: reg b
regrt = 2'h0; // reg dest no: rd
m2reg =0; // select reg c
pcsource = 2'b00; // select alu output
sext = 1; // sign extend
wrRegData = 0;
case (state) //---------------------------------------- IF:
sif: begin // IF state
wpc = 0;
wir =1; // write IR
pcsource = 2'h0;
Inswmem = 0;
//alusrca = 1; //PC
//alusrcb = 2'h1; // 4
next_state = sid; // next state: ID
end //--------------------------------------------- ID:
sid: begin // ID state
if (i_j || i_jal || i_jr || i_halt) begin
next_state = sif;
if (i_j) begin
wir = 0;
wpc = 1;
pcsource = 2'h3;
end else if (i_jr) begin
pcsource = 2'h2;
wpc = 1;
wir = 0;
wreg = 0;
end else if (i_jal) begin
wpc = 1;
pcsource = 2'h3;
wreg = 1;
wir = 0;
wrRegData = 0;
regrt = 2'h0;
end else if (i_halt) begin
wpc = 0;
wreg = 0;
end
end else if (i_add || i_sub || i_addi || i_and || i_or || i_ori || i_move || i_slt || i_sll || i_beq || i_sw || i_lw) begin
next_state = sexe;
wpc = 0;
wir = 0;
aluc = 3'h0;
alusrcb = 1;
sext = 1;
wreg = 0;
end
end //--------------------------------------------- EXE:
sexe: begin // EXE state
if (i_sll) begin
wir = 0;
alusrcb = 1;
aluc = 3'b100;
next_state = swb;
end else if (i_add || i_sub || i_and || i_or || i_move || i_slt) begin
wir = 0;
alusrcb = 0;
next_state = swb;
if (i_add || i_move) begin
aluc = 3'b000;
end else if (i_sub) begin
aluc = 3'b001;
end else if (i_and) begin
aluc = 3'b110;
end else if (i_slt) begin
aluc = 3'b010;
end else begin
aluc = 3'b101;
end
end else if (i_ori || i_addi) begin
wir = 0;
alusrcb = 1;
next_state = swb;
if (i_addi) begin
sext = 1;
aluc = 3'b000;
end else begin
sext = 0;
aluc = 3'b101;
end
end else if (i_beq) begin
wpc = 1;
wir = 0;
next_state = sif;
if (z)
pcsource = 2'b01;
else
pcsource = 2'b00;
aluc = 3'b001;
alusrcb = 0;
end else if (i_lw || i_sw) begin
sext = 1;
aluc = 3'b000;
alusrcb = 1;
next_state = smem;
end
end //--------------------------------------------- MEM:
smem: begin // MEM state
if (i_sw) begin
Datawmem = 1;
wir = 0;
wpc = 1;
next_state = sif;
end else if (i_lw) begin
Datawmem = 0;
wir = 0;
next_state = swb;
m2reg = 1;
wrRegData = 1;
end
end //--------------------------------------------- WB:
swb: begin // WB state
next_state = sif;
wpc = 1;
if (i_lw) begin
m2reg = 1;
wrRegData = 1;
regrt = 2'h1;
wreg = 1;
wir = 0;
end else if (i_addi || i_ori) begin
wreg = 1;
m2reg = 0;
wrRegData = 1;
regrt = 2'h1;
wir = 0;
end else if (i_add || i_sub || i_and || i_or || i_move || i_slt) begin
wreg = 1;
m2reg = 0;
wrRegData = 1;
regrt = 2'h2;
wir = 0;
end else if (i_sll) begin
wreg = 1;
m2reg = 0;
wrRegData = 1;
regrt = 2'h1;
wir = 0;
end
end //--------------------------------------------- END
endcase
end
always @ (posedge clock) begin
if (resetn == 1) begin
state <= sif;
end else begin
state <= next_state;
end
end
endmodule
regfile.v
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 15:17:50 05/12/2016
// Design Name:
// Module Name: sc_regfile
// Project Name:
// Target Devices:
// Tool versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module sc_regfile(rs, rt, i_data, rd, we, clk, o_data_1, o_data_2
);
input [4:0] rs, rt, rd;
input [31:0] i_data;
input we, clk;
output [31:0] o_data_1, o_data_2;
reg [31:0] register [0:31];
initial begin
register[0] = 0;
end
assign o_data_1 = register[rs];
assign o_data_2 = register[rt];
always @(posedge clk) begin
if ((rd != 0) && (we == 1)) begin
register[rd] = i_data;
end
end
endmodule
imem.v
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 14:56:43 05/12/2016
// Design Name:
// Module Name: sc_imem
// Project Name:
// Target Devices:
// Tool versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module sc_imem( addr, read_en_, instruction
);
input read_en_;
input [31:0] addr;
output reg [31:0] instruction;
reg [7:0] mem [0:350];
initial begin
mem[251] = 8'b11100000;
mem[250] = 8'b00000000;
mem[249] = 8'b00000000;
mem[248] = 8'b01000100;
mem[275] = 8'b00001000;
mem[274] = 8'b00000001;
mem[273] = 8'b00000000;
mem[272] = 8'b00110000;
mem[279] = 8'b01001000;
mem[278] = 8'b00000010;
mem[277] = 8'b00000000;
mem[276] = 8'b00000011;
mem[283] = 8'b00000000;
mem[282] = 8'b00100010;
mem[281] = 8'b00011000;
mem[280] = 8'b00000000;
mem[287] = 8'h04;
mem[286] = 8'h61;
mem[285] = 8'h20;
mem[284] = 8'h00;
mem[291] = 8'h44;
mem[290] = 8'h62;
mem[289] = 8'h28;
mem[288] = 8'h00;
mem[295] = 8'h40;
mem[294] = 8'h25;
mem[293] = 8'h40;
mem[292] = 8'h00;
mem[299] = 8'h81;
mem[298] = 8'h00;
mem[297] = 8'h50;
mem[296] = 8'h00;
mem[303] = 8'he8;
mem[302] = 8'h00;
mem[301] = 8'h00;
mem[300] = 8'h51;
mem[307] = 8'h9c;
mem[306] = 8'h22;
mem[305] = 8'h30;
mem[304] = 8'h00;
mem[311] = 8'h9c;
mem[310] = 8'h41;
mem[309] = 8'h38;
mem[308] = 8'h00;
mem[315] = 8'h60;
mem[314] = 8'h42;
mem[313] = 8'h00;
mem[312] = 8'h02;
mem[319] = 8'hd0;
mem[318] = 8'h22;
mem[317] = 8'hff;
mem[316] = 8'hfe;
mem[323] = 8'hfc;
mem[322] = 8'h00;
mem[321] = 8'h00;
mem[320] = 8'h00;
mem[327] = 8'hc0;
mem[326] = 8'h25;
mem[325] = 8'h00;
mem[324] = 8'h02;
mem[331] = 8'hc4;
mem[330] = 8'h2c;
mem[329] = 8'h00;
mem[328] = 8'h02;
mem[335] = 8'he7;
mem[334] = 8'he0;
mem[333] = 8'h00;
mem[332] = 8'h00;
instruction = 0;
end
always @(addr or read_en_) begin
instruction[31:24] = mem[addr+3];
instruction[23:16] = mem[addr+2];
instruction[15:8] = mem[addr+1];
instruction[7:0] = mem[addr];
end
endmodule
signExtend.v
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 18:50:53 05/12/2016
// Design Name:
// Module Name: sc_signExtend
// Project Name:
// Target Devices:
// Tool versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module sc_signExtend(i_num, extSel, o_num
);
input wire[15:0] i_num;
input wire extSel;
output reg[31:0] o_num;
initial begin
o_num = 0;
end
always @(i_num or extSel) begin
if (extSel) begin
o_num <= 16i_num[15], i_num[15:0];
end else begin
o_num <= 160, i_num[15:0];
end
end
endmodule
alu.v
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 14:25:48 05/12/2016
// Design Name:
// Module Name: sc_alu
// Project Name:
// Target Devices:
// Tool versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module sc_alu(A, B, ALUOp, zero, result
);
input [31:0] A, B;
input [2:0] ALUOp;
output zero;
output reg [31:0] result;
initial begin
result = 0;
end
assign zero = (result? 0 : 1);
always @(A or B or ALUOp) begin
case(ALUOp)
3'b000: result = A + B;
3'b001: result = A - B;
3'b010: result = (B > A? 1: 0);
3'b011: result = A>>B;
3'b100: result = A<<B;
3'b101: result = A | B;
3'b110: result = A & B;
3'b111: result = (~A & B) | (A & ~B);
default: result = 0;
endcase
end
endmodule
pc.v
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 19:07:29 05/12/2016
// Design Name:
// Module Name: sc_pc
// Project Name:
// Target Devices:
// Tool versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module sc_pc(clk, i_pc, pcWire, reset, o_pc, set_pc
);
input wire clk, pcWire, reset;
input wire [31:0] i_pc;
input wire [31:0]set_pc;
output reg [31:0] o_pc;
always @(posedge clk) begin
if (reset) begin
o_pc = set_pc;
end else if (pcWire) begin
o_pc = i_pc;
end else if (!pcWire) begin //í£?ú
o_pc = o_pc;
end
end
endmodule
datemen.v(时钟下降沿触发完美解决竞争冒险问题。。)
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 18:43:30 05/12/2016
// Design Name:
// Module Name: sc_datemem
// Project Name:
// Target Devices:
// Tool versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module sc_datemem(clk, i_data, addr, rw, o_data
);
input [31:0] i_data;
input [31:0] addr;
input rw, clk;
output reg [31:0] o_data;
reg [7:0] memory [0:63];
initial begin
o_data = 0;
end
always @(negedge clk) begin
if (rw) begin
memory[addr+3] = i_data[31:24];
memory[addr+2] = i_data[23:16];
memory[addr+1] = i_data[15:8];
memory[addr] = i_data[7:0];
end else begin
o_data[31:24] = memory[addr+3];
o_data[23:16] = memory[addr+2];
o_data[15:8] = memory[addr+1];
o_data[7:0] = memory[addr];
end
end
endmodule
pcaddFour.v
module sc_addfour(i_pc, o_pc
);
input wire [31:0] i_pc;
output wire [31:0] o_pc;
assign o_pc[31:0] = i_pc[31:0] + 4;
endmodule
pcaddmin.v(pc+立即数的模块)
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 19:32:56 05/12/2016
// Design Name:
// Module Name: sc_pcaddmin
// Project Name:
// Target Devices:
// Tool versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module sc_pcaddmin(now_pc, addNum, o_pc
);
input [31:0] now_pc, addNum;
output [31:0] o_pc;
assign o_pc = now_pc + (addNum * 4);
endmodule
pcdirect.v(pc直接跳转地址)
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 19:35:07 05/12/2016
// Design Name:
// Module Name: sc_pcdirect
// Project Name:
// Target Devices:
// Tool versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module sc_pcdirect(i_pc, addr, o_pc
);
input [31:0] i_pc;
input [25:0] addr;
output reg [31:0] o_pc;
initial begin
o_pc = 0;
end
always @(i_pc or addr) begin
o_pc[31:28] = i_pc[31:28];
o_pc[27:2] = addr[25:0];
o_pc[1:0] = 2'b00;
end
endmodule
dataselect.v ( 包含三个选择器)
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 19:14:04 05/12/2016
// Design Name:
// Module Name: sc_dataselect
// Project Name:
// Target Devices:
// Tool versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module dataSelect_5_Bit(B, C, Ctrl, S);
input [4:0] B, C;
input [1:0]Ctrl;
output reg [4:0] S;
wire [4:0] A;
assign A = 5'h1f;
initial begin
S = 0;
end
always @(*) begin
if (Ctrl == 2'b00)
S = A;
else if (Ctrl == 2'b01)
S = B;
else
S = C;
end
endmodule
module dataSelect_32_Bit(A, B, Ctrl, S);
input [31:0] A, B;
input Ctrl;
output [31:0] S;
assign S = (Ctrl == 1'b1 ? B : A);
endmodule
module dataSelect_32_Bit_reg(A, B, Ctrl, S);
input [31:0] A, B;
input Ctrl;
output reg [31:0] S;
always @(*) begin
if (Ctrl == 1) begin
S = A;
end
else begin
S = B;
end
end
endmodule
module dataSelect4_32_Bit(A, B, C, D, Ctrl, S);
input [31:0] A, B, C, D;
input [1:0]Ctrl;
output reg [31:0] S;
always @(*) begin
if (Ctrl == 2'b00) begin
S = A;
end
else if (Ctrl == 2'b01) begin
S = B;
end else if (Ctrl == 2'b10) begin
S = C;
end else begin
S = D;
end
end
endmodule
接下来是各个寄存器的代码
首先是IR.v
`timescale 1ns / 1ps
/////////////////////////////////////////////////////////P4-verilog实现mips单周期CPU