`timescale 1ns / 1ps `define STARTADDR 32'd0 // 程序开始地址 module single_cycle_cpu( input clk, // 时钟 input resetn, // 复位信号,低电平有效 //display data input [ 4:0] rf_addr, input [31:0] mem_addr, output [31:0] rf_data, output [31:0] mem_data, output [31:0] cpu_pc, output [31:0] cpu_inst ); //begin------------------------------------// reg [31:0] pc; wire [31:0] next_pc; wire [31:0] seq_pc; wire [31:0] jbr_target; wire jbr_taken; // 下一个指令地址:seq_pc=pc 4 assign seq_pc[31:2] = pc[31:2] 1'b1; assign seq_pc[1:0] = pc[1:0]; // 新指令:如果指令跳转,跳转地址;否则,下一个指令 assign next_pc = jbr_taken ? jbr_target : seq_pc; always @ (posedge clk) // PC程序计数器 begin if (!resetn) begin pc <= `STARTADDR; // 复位,取程序起始地址 end else begin pc <= next_pc; // 不复位,取新指令 end end wire [31:0] inst_addr; wire [31:0] inst; assign inst_addr = pc; // 指令地址:指令长度为32位 inst_rom inst_rom_module( // 指令存储器 .addr (inst_addr[6:2]), // I, 5,指令地址 .inst (inst ) // O, 32,指令 ); assign cpu_pc = pc; //display pc assign cpu_inst = inst; //end-------------------------------------// //begin------------------------------------// wire [5:0] op; //操作码 wire [4:0] rs; // 源操作数1 wire [4:0] rt; // 源操作数2 wire [4:0] rd; // 目的操作数 wire [4:0] sa; // 特殊域,可能存放偏移量 wire [5:0] funct; // 功能码 wire [15:0] imm; // 立即数 wire [15:0] offset; // 地址偏移 wire [25:0] target; // 目标地址 //补充上述变量的赋值,即译码 inst assign op = inst[31:26]; // 操作码 assign rs = inst[25:21]; // 源操作数1 assign rt = inst[20:16]; // 源操作数2 assign rd = inst[15:11]; // 目标操作数 assign sa = inst[10:6]; // 特殊域,可存储偏移量 assign funct = inst[5:0]; // 功能码 assign imm = inst[15:0]; // 立即数 assign offset = inst[15:0]; // 地址偏移量 assign target = inst[25:0]; // 目标地址 wire op_zero; // 操作码全0 wire sa_zero; // sa域全0 assign op_zero = ~(|op); assign sa_zero = ~(|sa); // 实现指令列表 wire inst_ADDU, inst_SUBU , inst_SLT, inst_AND; wire inst_NOR , inst_OR , inst_XOR, inst_SLL; wire inst_SRL , inst_ADDIU, inst_BEQ, inst_BNE; wire inst_LW , inst_SW , inst_LUI, inst_J; //补充: assign inst_ADDU = op_zero & sa_zero & (funct == 6'b100001);// 无符号加法 assign inst_SUBU = op_zero & sa_zero & (funct == 6'b100011);// 无符号减法 assign inst_SLT = op_zero & sa_zero & (funct == 6'b101010);// 小于则置位 assign inst_AND = op_zero & sa_zero & (funct == 6'b100100);// 逻辑与运算 assign inst_NOR = op_zero & sa_zero & (funct == 6'b100111);// 逻辑或非操作 assign inst_OR = op_zero & sa_zero & (funct == 6'b100101);// 逻辑或运算 assign inst_XOR = op_zero & sa_zero & (funct == 6'b100110);// 逻辑异或操作 assign inst_SLL = op_zero & (rs==5'd0) & (funct == 6'b000000);// 逻辑左移 assign inst_SRL = op_zero & (rs==5'd0) & (funct == 6'b000010);// 逻辑右移 assign inst_ADDIU = (op == 6'b001001); // 立即数无符号加法 assign inst_BEQ = (op == 6'b000100); // 判断相等跳转 assign inst_BNE = (op == 6'b000101); // 判断跳转不等 assign inst_LW = (op == 6'b100011); // 从内存装载 assign inst_SW = (op == 6'b101011); // 向内存存储 assign inst_LUI = (op == 6'b001111); // 立即装载高半字节 assign inst_J = (op == 6'b000010); // 直接跳转 // 无条件跳转判断 wire j_taken; wire [31:0] j_target; assign j_taken = inst_J; // 补充:无条件跳转目标地址:PC={PC[31:28],target<<2} assign j_target = {pc[31:28], target, 2'b00}; //分支跳转 wire beq_taken; wire bne_taken; wire [31:0] br_target; // 补充 assign beq_taken = (rs_value == rt_value); // BEQ跳转条件:GPR[rs]=GPR[rt] assign bne_taken = ~beq_taken; // BNE跳转条件:GPR[rs]≠GPR[rt] assign br_target[31:2] = pc[31:2] {
{14{offset[15]}}, offset}; assign br_target[1:0] = pc[1:0]; // 分支跳转目标地址:PC=PC offset<<2 //补充:跳转指令的跳转信号和跳转目标地址 assign jbr_taken = j_taken // 指令跳转:无条件跳转 或 满足分支跳转条件 | int_BEQ & beq_taken
| inst_BNE & bne_taken;
assign jbr_target = j_taken ? j_target : br_target;
// 寄存器堆
wire rf_wen;
wire [4:0] rf_waddr;
wire [31:0] rf_wdata;
wire [31:0] rs_value, rt_value;
regfile rf_module(
.clk (clk ), // I, 1
.wen (rf_wen ), // I, 1
.raddr1 (rs ), // I, 5
.raddr2 (rt ), // I, 5
.waddr (rf_waddr ), // I, 5
.wdata (rf_wdata ), // I, 32
.rdata1 (rs_value ), // O, 32
.rdata2 (rt_value ), // O, 32
//display rf
.test_addr(rf_addr),
.test_data(rf_data)
);
// 传递到执行模块的ALU源操作数和操作码
wire inst_add, inst_sub, inst_slt,inst_sltu;
wire inst_and, inst_nor, inst_or, inst_xor;
wire inst_sll, inst_srl, inst_sra,inst_lui;
assign inst_add = inst_ADDU | inst_ADDIU | inst_LW | inst_SW; // 做加法运算指令
assign inst_sub = inst_SUBU; // 减法
assign inst_slt = inst_SLT; // 小于置位
assign inst_sltu= 1'b0; // 暂未实现
assign inst_and = inst_AND; // 逻辑与
assign inst_nor = inst_NOR; // 逻辑或非
assign inst_or = inst_OR; // 逻辑或
assign inst_xor = inst_XOR; // 逻辑异或
assign inst_sll = inst_SLL; // 逻辑左移
assign inst_srl = inst_SRL; // 逻辑右移
assign inst_sra = 1'b0; // 暂未实现
assign inst_lui = inst_LUI; // 立即数装载高位
wire [31:0] sext_imm;
wire inst_shf_sa; //使用sa域作为偏移量的指令
wire inst_imm_sign; //对立即数作符号扩展的指令
assign sext_imm = {
{16{imm[15]}}, imm};// 立即数符号扩展
assign inst_shf_sa = inst_SLL | inst_SRL;
assign inst_imm_sign = inst_ADDIU | inst_LUI | inst_LW | inst_SW;
wire [31:0] alu_operand1;
wire [31:0] alu_operand2;
wire [11:0] alu_control;
assign alu_operand1 = inst_shf_sa ? {27'd0,sa} : rs_value;
assign alu_operand2 = inst_imm_sign ? sext_imm : rt_value;
assign alu_control = {inst_add, // ALU操作码,独热编码
inst_sub,
inst_slt,
inst_sltu,
inst_and,
inst_nor,
inst_or,
inst_xor,
inst_sll,
inst_srl,
inst_sra,
inst_lui};
//----------------------------------{译码}end-------------------------------------//
//---------------------------------{执行}begin------------------------------------//
wire [31:0] alu_result;
alu alu_module(
.alu_control (alu_control ), // I, 12, ALU控制信号
.alu_src1 (alu_operand1), // I, 32, ALU操作数1
.alu_src2 (alu_operand2), // I, 32, ALU操作数2
.alu_result (alu_result ) // O, 32, ALU结果
);
//----------------------------------{执行}end-------------------------------------//
//---------------------------------{访存}begin------------------------------------//
wire [3 :0] dm_wen;
wire [31:0] dm_addr;
wire [31:0] dm_wdata;
wire [31:0] dm_rdata;
assign dm_wen = {4{inst_SW}} & resetn; // 内存写使能,非resetn状态下有效
assign dm_addr = alu_result; // 内存写地址,为ALU结果
assign dm_wdata = rt_value; // 内存写数据,为rt寄存器值
data_ram data_ram_module(
.clk (clk ), // I, 1, 时钟
.wen (dm_wen ), // I, 1, 写使能
.addr (dm_addr[6:2]), // I, 32, 读地址
.wdata (dm_wdata ), // I, 32, 写数据
.rdata (dm_rdata ), // O, 32, 读数据
//display mem
.test_addr(mem_addr[6:2]),
.test_data(mem_data )
);
//----------------------------------{访存}end-------------------------------------//
//---------------------------------{写回}begin------------------------------------//
wire inst_wdest_rt; // 寄存器堆写入地址为rt的指令
wire inst_wdest_rd; // 寄存器堆写入地址为rd的指令
//补充
assign inst_wdest_rt = inst_ADDIU | inst_LW | inst_LUI;
assign inst_wdest_rd = inst_ADDU | inst_SUBU | inst_SLT | inst_AND | inst_NOR
| inst_OR | inst_XOR | inst_SLL | inst_SRL;
//补充
assign rf_wen = (inst_wdest_rt | inst_wdest_rd) & resetn; // 寄存器堆写使能信号,非复位状态下有效
assign rf_waddr = inst_wdest_rd ? rd : rt; // 寄存器堆写地址rd或rt
assign rf_wdata = inst_LW ? dm_rdata : alu_result;// 写回结果,为load结果或ALU结果
//----------------------------------{写回}end-------------------------------------//
endmodule
`timescale 1ns / 1ps
module tb;
// Inputs
reg clk;
reg resetn;
reg [4:0] rf_addr;
reg [31:0] mem_addr;
// Outputs
wire [31:0] rf_data;
wire [31:0] mem_data;
wire [31:0] cpu_pc;
wire [31:0] cpu_inst;
// Instantiate the Unit Under Test (UUT)
single_cycle_cpu uut (
.clk(clk),
.resetn(resetn),
.rf_addr(rf_addr),
.mem_addr(mem_addr),
.rf_data(rf_data),
.mem_data(mem_data),
.cpu_pc(cpu_pc),
.cpu_inst(cpu_inst)
);
initial begin
// Initialize Inputs
clk = 1;
resetn = 0;
rf_addr = 0;
mem_addr = 0;
#50;
resetn = 1;
rf_addr = 1;
#10;
rf_addr = 2;
#10;
rf_addr = 3;
#10;
rf_addr = 4;
#10;
rf_addr = 5;
#10;
mem_addr = 32'H00000014;
#10;
rf_addr = 6;
#10;
rf_addr = 7;
#10;
rf_addr = 8;
#10;
rf_addr = 9;
#10;
mem_addr = 32'H0000001c;
#10;
rf_addr = 10;
#10;
rf_addr = 11;
mem_addr = 32'H00000000;
#10;
end
always #5 clk=~clk;
endmodule
`timescale 1ns / 1ps
module inst_rom(
input [4 :0] addr, // 指令地址
output reg [31:0] inst // 指令
);
wire [31:0] inst_rom[19:0]; // 指令存储器,字节地址7'b000_0000~7'b111_1111
//------------- 指令编码 ---------|指令地址|--- 汇编指令 -----|- 指令结果 -----//
assign inst_rom[ 0] = 32'h24010001; // 00H: addiu $1 ,$0,#1 | $1 = 0000_0001H
assign inst_rom[ 1] = 32'h00011100; // 04H: sll $2 ,$1,#4 | $2 = 0000_0010H
assign inst_rom[ 2] = 32'h00411821; // 08H: addu $3 ,$2,$1 | $3 = 0000_0011H
assign inst_rom[ 3] = 32'h00022082; // 0CH: srl $4 ,$2,#2 | $4 = 0000_0004H
assign inst_rom[ 4] = 32'h00642823; // 10H: subu $5 ,$3,$4 | $5 = 0000_000DH
assign inst_rom[ 5] = 32'hAC250013; // 14H: sw $5 ,#19($1) | Mem[0000_0014H] = 0000_000DH
assign inst_rom[ 6] = 32'h00A23027; // 18H: nor $6 ,$5,$2 | $6 = FFFF_FFE2H
assign inst_rom[ 7] = 32'h00C33825; // 1CH: or $7 ,$6,$3 | $7 = FFFF_FFF3H
assign inst_rom[ 8] = 32'h00E64026; // 20H: xor $8 ,$7,$6 | $8 = 0000_0011H
assign inst_rom[ 9] = 32'hAC08001C; // 24H: sw $8 ,#28($0) | Mem[0000_001CH] = 0000_0011H
assign inst_rom[10] = 32'h00C7482A; // 28H: slt $9 ,$6,$7 | $9 = 0000_0001H
assign inst_rom[11] = 32'h08000000; // 4CH: j 00H | 跳转指令00H
//读指令,取4字节
always @(*)
begin
case (addr)
5'd0 : inst <= inst_rom[0 ];
5'd1 : inst <= inst_rom[1 ];
5'd2 : inst <= inst_rom[2 ];
5'd3 : inst <= inst_rom[3 ];
5'd4 : inst <= inst_rom[4 ];
5'd5 : inst <= inst_rom[5 ];
5'd6 : inst <= inst_rom[6 ];
5'd7 : inst <= inst_rom[7 ];
5'd8 : inst <= inst_rom[8 ];
5'd9 : inst <= inst_rom[9 ];
5'd10: inst <= inst_rom[10];
5'd11: inst <= inst_rom[11];
5'd12: inst <= inst_rom[12];
5'd13: inst <= inst_rom[13];
5'd14: inst <= inst_rom[14];
5'd15: inst <= inst_rom[15];
5'd16: inst <= inst_rom[16];
5'd17: inst <= inst_rom[17];
5'd18: inst <= inst_rom[18];
5'd19: inst <= inst_rom[19];
default: inst <= 32'd0;
endcase
end
endmodule
(88条消息) 【计算机组成原理实验】单周期cpu的实现_源码文件-单片机文档类资源-CSDN文库

使能==1时开始,
先向$1写入数据0000_0001H,
然后将$1数据逻辑左移并存入$2,
然后将$1与$2相加存于$3,
然后将$2逻辑右移存入$4,
随后$3减$4,存入$5,将结果存入地址为0000_0014H的mem中,
随后将$5和$2做或非运算,存入$6,
随后将$6和$3做或运算,存入$7,
随后将$7和$6做异或运算,存入$8,
随后将$8中数据写入地址为0000_001CH的mem中。
最后进行跳转指令跳转到开头的00H指令。