计算机组成原理 实验五 单周期CPU设计与实现——十条指令CPU
ALU和寄存器堆
一、实验目的:
理解和掌握CPU中的算术逻辑运算部件(ALU)和寄存器堆(Register File)的工作原理,并使用Verilog和ModelSim进行设计和仿真。
二、实验内容:
- 使用Verilog完成ALU的设计,并编写测试仿真文件验证其正确性。要求:
ALU支持16位的加、减、与、或以及移位运算。 - 使用Verilog完成通用寄存器堆的设计,并编写测试仿真文件验证其正确性。要求:
寄存器堆包含8个16位的寄存器;
寄存器堆有两个读端口和一个写端口。
三、 源代码
MyALU.v
module ALU(
input wire [15:0] A_1, //操作数1
input wire [15:0] A_2, //操作数2
input wire [3:0] OP, //操作码
output [15:0] result,// 结果
//status[0:3] //0: zero, 1: carry, 2: negative, 3: overflow
//output reg [3:0] status
output zero,
output carry,
output negative,
output overflow
);
wire signed [15:0] tmpX = A_1, tmpY = A_2;
reg [16:0] res_T = 17'b0;//??????????16??17???????
always@* begin
case(OP)
3'b000:
res_T = A_1 + A_2;
3'b001:
res_T = A_1 -A_2;
3'b010:
res_T = A_1 & A_2;
3'b011:
res_T = A_1 | A_2;
3'b100:
res_T = A_1 >> A_2;
3'b101:
res_T = A_1 << A_2;
default:
res_T = 16'b1111111111111111;
endcase
end
assign ans = res_T[15:0];
assign zero = res_T == 16'b0 ? 0 : 1; //判断是否等于0
assign negative = res_T[15]; //判断是否为负数
assign overflow = res_T[16]; //判断是否溢出
endmodule
MyALU_tb.v
module MyALU_tb();
reg [15:0] inData_1, inData_2;
reg [3:0] OP [0:7];
wire [15:0] result;
wire zero, carry, negative, overflow;
initial begin
inData_1 = 16'b0101010101010101;//21845
inData_2 = 16'b1010101010101010;//43690
#10 OP[0] = 3'b000;
#10 OP[1] = 3'b001;
#10 OP[2] = 3'b010;
#10 OP[3] = 3'b011;
#10 OP[4] = 3'b100;
#10 OP[5] = 3'b101;
#100 $stop;
end
ALU test1(
.A_1(inData_1), .A_2(inData_2),
.OP( OP[0]),
.result(result),
.zero(zero),
.carry(carry),
.negative(negative),
.overflow(overflow)
);
ALU test2(
.A_1(inData_1), .A_2(inData_2),
.OP( OP[1]),
.result(result),
.zero(zero),
.carry(carry),
.negative(negative),
.overflow(overflow)
);
ALU test3(
.A_1(inData_1), .A_2(inData_2),
.OP( OP[2]),
.result(result),
.zero(zero),
.carry(carry),
.negative(negative),
.overflow(overflow)
);
ALU test4(
.A_1(inData_1), .A_2(inData_2),
.OP( OP[3]),
.result(result),
.zero(zero),
.carry(carry),
.negative(negative),
.overflow(overflow)
);
ALU test5(
.A_1(inData_1), .A_2(inData_2),
.OP( OP[4]),
.result(result),
.zero(zero),
.carry(carry),
.negative(negative),
.overflow(overflow)
);
ALU test6(
.A_1(inData_1), .A_2(inData_2),
.OP( OP[5]),
.result(result),
.zero(zero),
.carry(carry),
.negative(negative),
.overflow(overflow)
);
endmodule
registerBank.v
module registerBank(
input [2:0] addrA,addrB,inAddr,
output wire[15:0] outA,outB,
input wire[15:0] inData,
input clk,WE
);
reg[15:0] regs[0:7];
assign outA = regs[addrA];
assign outB = regs[addrB];
always@(negedge clk)begin
if( WE == 1 )
regs[inAddr] = inData;
end
endmodule
registerBank_tb.v
module registerBank_tb();
parameter CYCLE = 2;
reg [2:0] addrA, addrB, inAddr;
wire [15:0] outA, outB;
reg [15:0] inData;
reg clk, WE;
initial begin
clk = 1'b0;
//WE = 1'b0;
end
always #(CYCLE/2) clk = ~ clk;
always #(CYCLE/2) WE = ~ WE;
initial begin
//assign WE = 1'b0;
assign WE = 1'b1;
assign inData = 16'h35A1;
assign inAddr = 3'b010;
assign addrA = 3'b010;
assign addrB = 3'b100;
#(CYCLE*1)
assign WE = 1'b1;
assign inData = 16'h1234;
assign inAddr = 3'b001;
assign addrA = 3'b000;
assign addrB = 3'b001;
#(CYCLE*2)
assign WE = 1'b0;
assign inData = 16'h65df;
assign inAddr = 3'b101;
assign addrA = 3'b101;
assign addrB = 3'b010;
#(CYCLE*3)
assign WE = 1'b1;
assign inData = 16'h12ce;
assign inAddr = 3'b100;
assign addrA = 3'b100;
assign addrB = 3'b011;
#(CYCLE*2)
assign WE = 1'b1;
assign inData = 16'hefd3;
assign inAddr = 3'b110;
assign addrA = 3'b011;
assign addrB = 3'b110;
#(CYCLE*5)
$stop;
end
registerBank reg_file(
.clk(clk), .WE(WE),
.addrA(addrA), .addrB(addrB), .inData(inData),
.inAddr(inAddr),
.outA(outA), .outB(outB)
);
endmodule
PC和半导体存储器RAM
一、实验目的:
理解和掌握CPU中程序计数器PC和半导体存储器RAM的工作原理,并使用Verilog和ModelSim进行设计和仿真。
二、实验内容:
- 使用Verilog完成程序计数器PC的设计,要求:
PC为8位计数器 - 使用Verilog完成数据存储器的设计,并编写测试仿真文件验证其正确性。要求:
存储字长16位,存储容量1K字节;
一根读写控制信号线控制读写,低电平有效。
三、源代码
PC.v
module MyPC(
input clk,
input rst,
output [7:0] PC
);
reg [7:0] pc_T = 8'b0;
always @(posedge clk or posedge rst) begin
if(rst)
pc_T = 8'b0;//8'b01011010;
else
pc_T = pc_T + 1'b1;
end
assign PC = pc_T;
endmodule
PC_tb.v
module MyPC_tb();
reg clk;
reg rst = 1'b0;
wire [7:0] initAddr = 8'b10000000;
wire [7:0] pcAddr;
//wire [9:0] cnt = 10'd0;
always #60 assign rst = ~rst;//if(cnt%0==100) clk = ~clk;
//assign cnt = cnt + 1'd1;
initial begin
#0
assign clk = 1'b1;
//assign rst = 1'b0;
#10
assign clk = 1'b0;
#20
assign clk = ~clk;
#30
assign clk = 1'b1;
#40
assign clk = 1'b0;
#50
assign clk = ~clk;
/*
#50
assign clk = 1'b0;
#100 clk = ~clk;
*/
#100 $stop;
end
MyPC pc1(
.clk(clk),
.rst(rst),
//.initAddr(initAddr),
.PC(PC)
);
endmodule
RAM.v
module MyRAM #( parameter DATA_WIDTH = 16,DEPTH = 1024)(
//input;
input wire clk,
input wire WE, //write low enable;
input wire [clogb2(DEPTH)-1:0] address,
input wire [DATA_WIDTH-1:0] dataIn,
//output;
output wire [DATA_WIDTH-1:0] dataOut
);
function integer clogb2 (input integer depth);
begin
for (clogb2=0; depth>1; clogb2=clogb2+1)
depth = depth >>1;
end
endfunction
(* ramstyle = "M9K" *) reg [DATA_WIDTH-1:0] memory[0:DEPTH-1];
reg [clogb2(DEPTH)-1:0] address_reg;
//read;
always @(posedge clk ) begin
address_reg <= address;
end //always
assign dataOut = memory[address_reg];
//write;
always @(posedge clk ) begin
if(~WE) begin
memory[address] <= dataIn;
end
end //always
endmodule
RAM_tb.v
`timescale 1ns/1ns
module MyRAM_tb ();
parameter CYCLE = 8;
parameter ADDR_WIDTH = 10;
parameter DATA_WIDTH = 16;
reg clk;
reg WE;
reg [ADDR_WIDTH-1:0] address;
reg [DATA_WIDTH-1:0] dataIn;
wire [DATA_WIDTH-1:0] dataOut;
MyRAM tb_u1(
.clk (clk),
.WE (WE),
.address (address),
.dataIn (dataIn),
.dataOut (dataOut)
);
initial begin
clk = 1'b0;
end
always #(CYCLE/2) clk = ~ clk;
always #(CYCLE/2) WE = ~ WE;
initial begin
WE = 1'b1;
address = 10'd0;
dataIn = 0;
#(CYCLE*2)
WE = 1'b0;
address = 10'd1;
dataIn = 16'habcc;
#(CYCLE*3)
WE = 1'b0;
address = 10'd2;
dataIn = 16'hbbdd;
#(CYCLE*4)
WE = 1'b0;
address = 10'd3;
dataIn = 16'hccee;//
#(CYCLE*5)
WE = 1'b0;
address = 10'd4;
dataIn = 16'h1234;
#(CYCLE*6)
WE = 1'b0;
address = 10'd1;
dataIn = 16'h568f;
//#(CYCLE*100)
//$stop;
#(CYCLE*7)
WE = 1'b0;
address = 10'd2;
dataIn = 16'h568e;
#(CYCLE*8)
WE = 1'b0;
address = 8'd3;
dataIn = 16'h568c;
#(CYCLE*9)
WE = 1'b0;
address = 10'd4;
dataIn = 16'h568a;
#(CYCLE*10)
$stop;
end
endmodule
后记
既来之 则赞之
若有疑问,欢迎评论
本文仅供参考,务必独立思考