一、实验内容
1. 处理器功能
本实验的任务是设计一个简单的RISC处理器,该处理器是在给定的指令集(与MIPS32类似)下构建的,支持12条指令。假定存储器分为数据缓冲存储器和指令缓冲存储器,且都可以在一个时钟周期内完成一次同步存取操作,时钟信号和CPU相同。处理器的指令字长为32位,包含32个32位通用寄存器R0~R31,1个32位的指令寄存器IR和1个32位的程序计数器PC,1个256×32位指令缓冲存储器,1个256×32位的数据缓冲存储器。
2. 指令系统定义
处理器所支持的指令包括 LW
,SW
,ADD
,SUB
,SLL
, AND
,OR
,XOR
,SLT
,MOVZ
,BNE
,J
。
其中仅有 LW
和 SW
是字访存指令,所有的存储器访问都通过这两条指令完成;ADD
、SUB
、SLL
、AND
、OR
、XOR
、SLT
、MOVZ
是运算指令,他们都在处理器内部完成;BNE
是分支跳转指令,根据寄存器的内容进行相对跳转;J
是无条件转移指令。
二、实验环境
Vivado 集成开发环境
龙芯 Artix-7 实验平台
三、设计思想
1. CPU接口信号定义
信号名 | 位数 | 方向 | 来源/去向 | 意义 |
clk | 1 | Input | 输入 | clock, 100MHz |
resetn | 1 | Input | 输入 | 复位,active low |
debug_wb_pc | 32 | Output | 输出 | 当前正在执行指令的PC |
debug_wb_rf_wen | 1 | Output | 寄存器组 | 当前通用寄存器组的写使能信号 |
debug_wb_rf_addr | 5 | Output | 寄存器组 | 当前通用寄存器组写回的寄存器编号 |
debug_wb_rf_wdata | 32 | Output | 寄存器组 | 当前指令需要写回的数据 |
2. 处理器的设计方案
(1)指令格式设计
处理器是一个简单的RISC处理器,该处理器是在给定的指令集(与MIPS32类似)下构建的,支持12条指令。所支持的指令包括 LW,SW,ADD,SUB,SLL, AND,OR,XOR,SLT,MOVZ,BNE,J。
其中仅有 LW和 SW是字访存指令,所有的存储器访问都通过这两条指令完成;ADD、SUB、SLL、AND、OR、XOR、SLT、MOVZ是运算指令,他们都在处理器内部完成;BNE是分支跳转指令,根据寄存器的内容进行相对跳转;J是无条件转移指令。
类型 | 助记符号 | 指令格式 | 指令功能 | |||||
运算 | ADD RD,RS,RT |
| [RD]←[RS] + [RT] | |||||
SUB RD,RS,RT |
| [RD]←[RS] - [RT] | ||||||
AND RD,RS,RT |
| [RD]←[RS] & [RT] | ||||||
OR RD,RS,RT |
| [RD]←[RS] | [RT] | ||||||
XOR RD,RS,RT |
| [RD]←[RS]⊕[RT] | ||||||
SLT RD,RS,RT |
| [RD]←[RS]<[RT]?1:0 | ||||||
MOVZ RD,RS,RT |
| if ([RT] == 0) then [RD]←[RS] | ||||||
SLL RD,RT,sa |
| [RD]←[RT]<<sa | ||||||
访存 | SW RT,offset(base) |
| Mem[[base] + offset] ← [RT] | |||||
LW RT,offset(base) |
| [RT] ←Mem[[base] + offset] | ||||||
跳转 | BNE RS,RT,offset |
| PC←([RS] != [RT]) ? [sign_extend(offset) << 2 + NPC] : NPC | |||||
J target |
| PC←(NPC[31:28]) ## (instr_index << 2) |
关于汇编指令的说明:
rs意味着source register,rd意味着destination register;
rt有时(如运算指令)意味着第二个source register,有时(如访存指令)意味着target (source/destination) register;
我们使用 [rs] 表示寄存器 rs的内容;
另外,所有算数运算指令都执行有符号运算。
序号 | 指令 | 取指令周期(IF) | 指令译码/读寄存器周期(ID) | 执行/有效地址计算周期(EX) | 存储器访问/分支完成周期(MEM) | 写回周期(WB) |
1 | ADD RD,RS,RT | IR←IMem[PC] PC←PC+1 | raddr1←IR[25:21]; raddr2←IR[20:16]; r_waddr←IR[15:11]; | A←rdata1 B←rdata2 Card=`ADD |
| r_wdata←F; we←1’b1; |
2 | SUB RD,RS,RT | IR←IMem[PC] PC←PC+1 | raddr1←IR[25:21]; raddr2←IR[20:16]; r_waddr←IR[15:11]; | A←rdata1 B←rdata2 Card=`SUB |
| r_wdata←F; we←1’b1; |
3 | AND RD,RS,RT | IR←IMem[PC] PC←PC+1 | raddr1←IR[25:21]; raddr2←IR[20:16]; r_waddr←IR[15:11]; | A←rdata1 B←rdata2 Card=`AND |
| r_wdata←F; we←1’b1; |
4 | OR RD,RS,RT | IR←IMem[PC] PC←PC+1 | raddr1←IR[25:21]; raddr2←IR[20:16]; r_waddr←IR[15:11]; | A←rdata1 B←rdata2 Card=`OR |
| r_wdata←F; we←1’b1; |
5 | XOR RD,RS,RT | IR←IMem[PC] PC←PC+1 | raddr1←IR[25:21]; raddr2←IR[20:16]; r_waddr←IR[15:11]; | A←rdata1 B←rdata2 Card=`XOR |
| r_wdata←F; we←1’b1; |
6 | SLT RD,RS,RT | IR←IMem[PC] PC←PC+1 | raddr1←IR[25:21]; raddr2←IR[20:16]; r_waddr←IR[15:11]; | A←rdata1 B←rdata2 Card=`SLT |
| r_wdata←F; we←1’b1; |
7 | MOVZ RD,RS,RT | IR←IMem[PC] PC←PC+1 | raddr1←IR[25:21]; raddr2←IR[20:16]; r_waddr←IR[15:11]; | A←rdata1 B←rdata2 Card=`MOVZ |
| r_wdata←F; we←1’b1; |
8 | SLL RD,RT,sa | IR←IMem[PC] PC←PC+1 | raddr1←IR[25:21]; raddr2←IR[20:16]; r_waddr←IR[15:11]; Imm←IR[10:6]; | A←Imm B←rdata2 Card=`SLL (F=B<<Imm) |
| r_wdata←F; we←1’b1; |
9 | SW RT,offset(base) | IR←IMem[PC] PC←PC+1 | raddr1←IR[25:21]; raddr2←IR[20:16]; Imm←IR[15:0]; | A←rdata1 B←Imm Card=`ADD | ram_addr←F; ram_wdata←rdata2 ram_wen←1’b1; |
|
10 | LW RT,offset(base) | IR←IMem[PC] PC←PC+1 | raddr1←IR[25:21]; raddr2←5’b0; Imm←IR[15:0]; r_waddr←IR[20:16]; | A←rdata1 B←Imm Card=`ADD | ram_addr←F;
| r_wdata=ram_rdata; we=1’b1;
|
11 | BNE RS,RT,offset | IR←IMem[PC] PC←PC+1 | raddr1←IR[25:21]; raddr2←IR[20:16]; Imm←IR[15:0]; | A←rdata1; B←rdata2; Card=`SUB | if(!Zero) A←Imm<<2 B←PC Card=`ADD | if(!Zero) PC←F
|
12 | J target | IR←IMem[PC] PC←PC+1 | Imm←IR[25:0]; |
|
| PC←{PC[31:26],Imm<<2} |
(2)处理器结构设计框图及功能描述
该CPU为非流水简单CPU。指令执行分为5个周期完成,分别为取指、译码、执行、访存、写回。给定时钟信号和复位信号,处理器可自动执行指令系统规定的12种指令编写的程序,当复位信号为零时,CPU进行初始化。在取指周期,PC送至instr_mem并读出当前指令内容,之后PC加4送NPC;译码阶段,根据当前指令进行译码,得到立即数值送Imm,得到存操作数的通用寄存器号r_addr1和r_addr2,得到目的寄存器的寄存器号。在执行阶段,分别将对应的操作数赋给ALU的A和B,并给出对应的Card选择ALU的操作。在访存阶段,给ram_addr、ram_wen和ram_wdata赋值,其中完成跳转指令的NPC计算(有条件跳转根据执行周期生成的Zero条件码进行计算)。在写回阶段,为r_wdata和we赋值,并更新PC。
(3)各模块输入输出接口信号定义
模块名称及功能:
ALU
完成算数和逻辑运算
信号名 | 位数 | 方向 | 来源/去向 | 意义 |
A | 32 | IN | Rdata1 | 操作数1 |
B | 32 | IN | Rdata2 | 操作数2 |
Cin | 1 | IN | 赋0 | 低位进位 |
Card | 5 | IN | control_unit | 操作选择 |
F | 32 | OUT | register | 结果 |
Cout | 1 | OUT | state | 运算产生的进位 |
Zero | 1 | OUT | state | 零标志位 |
模块名称及功能:
Register通用寄存器组
存储常用的操作数
信号名 | 位数 | 方向 | 来源/去向 | 意义 |
clk | 1 | IN | IN | 时钟信号 |
raddr1 | 5 | IN | control_unit | 寄存器堆读地址1 |
raddr2 | 5 | IN | control_unit | 寄存器堆读地址2 |
we | 1 | IN | control_unit | 寄存器堆写使能 |
waddr | 5 | IN | control_unit | 寄存器堆写地址 |
wdata | 32 | IN | control_unit | 寄存器堆写数据 |
rdata1 | 32 | OUT | ALU | 寄存器堆读返回数据1 |
rdata2 | 32 | OUT | ALU | 寄存器堆读返回数据2 |
模块名称及功能:
指令存储器instr_mem
存储程序的指令,只读,不可写
信号名 | 位数 | 方向 | 来源/去向 | 意义 |
ram_addr | 32 | IN | PC | 当前指令的地址 |
ram_rdata | 32 | OUT | IR | 读取当前指令 |
模块名称及功能:
数据存储器data_mem
存储数据,可读可写,同步读异步写
信号名 | 位数 | 方向 | 来源/去向 | 意义 |
clk | 1 | IN | IN | 时钟信号 |
ram_wen | 1 | IN | control_unit | 同步 RAM 写使能,置位时写入 |
ram_addr | 32 | IN | control_unit | 同步 RAM 地址信号,表示读/写地址 |
ram_wdata | 32 | IN | control_unit | 同步 RAM 写数据信号,表示写入数据 |
ram_rdata | 32 | OUT | Register | 同步 RAM 读数据信号,表示读出数据 |
以上表格不够可加页
四、实验设计
1. 各模块的详细设计
(1)ALU
完成算逻运算,含数据通路,为组合逻辑单元
`define ADD 5'b00001
`define ADDS 5'b00010
`define SUB 5'b00011
`define SUBS 5'b00100
`define SUB_A 5'b00101
`define SUBS_A 5'b00110
`define SAME_A 5'b00111
`define SAME_B 5'b01000
`define NOT_A 5'b01001
`define NOT_B 5'b01010
`define OR 5'b01011
`define AND 5'b01100
`define XNOR 5'b01101
`define XOR 5'b01110
`define NAND 5'b01111
`define ZERO 5'b00000
`define SLT 5'b10000
`define MOVZ 5'b10001
`define SLL 5'b10010
module alu(
input [31:0] A,
input [31:0] B,
input Cin,
input [4:0] Card,
output [31:0] F,
output Cout,
output Zero
);
wire [32:0] add_result;
wire [32:0] adds_result;
wire [32:0] sub_result;
wire [32:0] subs_result;
wire [32:0] sub_a_result;
wire [32:0] subs_a_result;
wire [32:0] same_a_result;
wire [32:0] same_b_result;
wire [32:0] not_a_result;
wire [32:0] not_b_result;
wire [32:0] or_result;
wire [32:0] and_result;
wire [32:0] xnor_result;
wire [32:0] xor_result;
wire [32:0] nand_result;
wire [32:0] zero_result;
wire [32:0] slt_result;
wire [32:0] movz_result;
wire [32:0] sll_result;
assign add_result=A+B;
assign adds_result=A+B+Cin;
assign sub_result=A-B;
assign subs_result=A-B-Cin;
assign sub_a_result=B-A;
assign subs_a_result=B-A-Cin;
assign same_a_result=A;
assign same_b_result=B;
assign not_a_result=~A;
assign not_b_result=~B;
assign or_result=A|B;
assign and_result=A&B;
assign xnor_result=~(A^B);
assign xor_result=A^B;
assign nand_result=~(A&B);
assign zero_result=0;
assign slt_result=(A<B)?32'h1:32'h0;
assign movz_result=(B == 32'h0)?A:B;
assign sll_result=B << A[4:0]; // 左移B的位数由A的低5位指定;
assign F = ({32{Card == `ADD}} & add_result) |
({32{Card == `SUB}} & sub_result) |
({32{Card == `ADDS}} & adds_result) |
({32{Card == `SUBS}} & subs_result) |
({32{Card == `SUB_A}} & sub_a_result) |
({32{Card == `SUBS_A}} & subs_a_result) |
({32{Card == `SAME_A}} & same_a_result) |
({32{Card == `SAME_B}} & same_b_result) |
({32{Card == `NOT_A}} & not_a_result) |
({32{Card == `NOT_B}} & not_b_result) |
({32{Card == `OR}} & or_result) |
({32{Card == `AND}} & and_result) |
({32{Card == `XNOR}} & xnor_result) |
({32{Card == `XOR}} & xor_result) |
({32{Card == `NAND}} & nand_result) |
({32{Card == `ZERO}} & zero_result)|
({32{Card == `SLT}} & slt_result) |
({32{Card == `MOVZ}} & movz_result) |
({32{Card == `SLL}} & sll_result);
assign Cout = (Card == `ADD) ? add_result[32] :
(Card == `ADDS) ? adds_result[32] :
(Card == `SUB) ? sub_result[32] :
(Card == `SUBS) ? subs_result[32] :
(Card == `SUB_A) ? sub_a_result[32] :
(Card == `SUBS_A) ? subs_a_result[32] :
1'b0;
assign Zero = (F == 32'h0);
endmodule
(2)寄存器堆
存取常用操作数
module register(
input clk,
input [4:0] raddr1,
output [31:0] rdata1,
input [4:0] raddr2,
output [31:0] rdata2,
input we,
input [4:0] waddr,
input [31:0] wdata
);
//采用寄存器数组的形式进行描述
reg [31:0] regts[0:31];
//初始化
initial begin
$readmemh("reg_data.txt",regts);
end
//写操作
always @(negedge clk ) begin
if(we) begin
regts[waddr] <= wdata;
end
end
//读操作
assign rdata1 = regts[raddr1];
assign rdata2 = regts[raddr2];
endmodule
(3)指令存储器
存指令程序
module instr_mem(
input [31:0] addr,
output [31:0] data
);
reg [31:0] instr [255:0];
initial begin
$readmemh("inst_data.txt",instr);
end
assign data=instr[addr/4];
endmodule
(4)数据存储器
module data_mem(
input clk,
input we,
input [31:0] addr,
input [31:0] w_data,
output [31:0] data
);
reg [31:0] dmem [255:0];
initial begin
$readmemh("data_data.txt",dmem);
end
assign data=dmem[addr/4];
always @(posedge clk)begin
if(we) dmem[addr/4]<=w_data;
end
endmodule
2. 系统的详细设计
CPU指令执行分五个阶段:取指IF、译码ID、执行EX、访存MEM、写回WB。采用更新当前状态进行控制,根据不同的状态标记采取不同的操作。
`define Add 6'b100000
`define Sub 6'b100010
`define And 6'b100100
`define Or 6'b100101
`define Xor 6'b100110
`define Slt 6'b101010
`define Movz 6'b001010
`define Sll 5'b000000
`define OP 6'b000000
`define SW 6'b101011
`define LW 6'b100011
`define BNE 6'b000101
`define J 6'b000010
`define IF 3'b000
`define ID 3'b001
`define EX 3'b010
`define MEM 3'b011
`define WB 3'b100
module cpu (
input clk,
input resetn,
output [31:0] debug_wb_pc,
output debug_wb_rf_wen,
output [4:0] debug_wb_rf_addr,
output [31:0] debug_wb_rf_wdata
);
(* MARK_DEBUG="true" *)reg ram_wen, we, opcode_valid;
(* MARK_DEBUG="true" *)reg [2:0] state,next_state;
(* MARK_DEBUG="true" *)reg [4:0] Card, raddr1, raddr2, r_waddr;
//(* MARK_DEBUG="true" *)reg [15:0] ram_addr;
(* MARK_DEBUG="true" *)reg [31:0] r_wdata,ram_addr, ram_wdata, A,B,Imm, PC,NPC;
(* MARK_DEBUG="true" *)wire [31:0] rdata1,rdata2,F,ram_rdata,IR;
(* MARK_DEBUG="true" *)wire Zero;
//通用寄存器组
register register (
.clk(clk),
.raddr1(raddr1),
.rdata1(rdata1),
.raddr2(raddr2),
.rdata2(rdata2),
.we(we),
.waddr(r_waddr),
.wdata(r_wdata)
);
//ALU
alu alu (
.A(A),
.B(B),
.Cin(1'b0),
.Card(Card),
.F(F),
.Cout(Cout),
.Zero(Zero)
);
// // 指令存储器
// block_mem instr_mem (
// .clka (clk),
// .wea (1'b0), // 指令存储器只读
// .addra(PC[15:0]/4),
// .dina (32'h0), // 写入0,因为这是只读存储器
// .douta(IR)
// );
// // 数据存储器
// block_mem1 data_mem (
// .clka (clk),
// .wea (ram_wen),
// .addra(ram_addr),
// .dina (ram_wdata),
// .douta(ram_rdata)
// );
instr_mem instr_mem(
.addr(PC),
.data(IR)
);
data_mem data_mem(
.clk (clk),
.we (ram_wen),
.addr(ram_addr),
.w_data (ram_wdata),
.data(ram_rdata)
);
always @(posedge clk or negedge resetn) begin
if (!resetn) begin
PC<=32'h0;
state <= `IF; // 初始状态为取指阶段
end else begin
state <= next_state; // 使用下一个状态
//if(state==`WB)PC<=NPC;
end
end
always @(*) begin
case (state)
`IF:begin
//if (opcode_valid) begin
NPC=PC+4;
case(IR[31:26])
`OP:begin
raddr1=IR[25:21];
raddr2=IR[20:16];
r_waddr=IR[15:11];
if(IR[5:0]==`Sll)Imm=IR[10:6];
end
`SW,`BNE:begin
raddr1=IR[25:21];
raddr2=IR[20:16];
Imm=IR[15:0];
end
`LW:begin
raddr1=IR[25:21];
raddr2=5'b0;
r_waddr=IR[20:16];
Imm=IR[15:0];
end
`J:begin
Imm=IR[25:0];
end
endcase
next_state = `ID; // 解码
end
`ID:begin
//type
case(IR[31:26])
`OP:begin
A=rdata1;
B=rdata2;
case(IR[5:0])
`Add:begin
Card=`ADD;
end
`Sub:begin
Card=`SUB;
end
`And:begin
Card=`AND;
end
`Or:begin
Card=`OR;
end
`Xor:begin
Card=`XOR;
end
`Slt:begin
Card=`SLT;
end
`Movz:begin
Card=`MOVZ;
end
`Sll:begin
A=Imm;
Card=`SLL;
end
endcase
end
`SW,`LW:begin
A=rdata1;
B=Imm;
Card=`ADD;
end
`BNE:begin
A=rdata1;
B=rdata2;
Card=`SUB;
end
endcase
next_state = `EX;
end
`EX:begin
//type
case(IR[31:26])
`SW:begin
ram_addr=F;
ram_wdata=rdata2;
ram_wen=1'b1;
end
`LW:begin
ram_addr=F;
end
`BNE:begin
if(!Zero)NPC=NPC+(Imm<<2);
end
`J:begin
NPC={NPC[31:26],Imm<<2};
end
endcase
next_state = `MEM;
end
`MEM:begin
case(IR[31:26])
`OP:begin
r_wdata=F;
we=1'b1;
end
`LW:begin
r_wdata=ram_rdata;
we=1'b1;
end
endcase
ram_wen=1'b0;
next_state = `WB;
end
`WB:begin
//type
PC=NPC;
we=1'b0;
next_state = `IF;
end
endcase
end
// 调试信息
assign debug_wb_pc = PC;//32'bX;
assign debug_wb_rf_wen = we;
assign debug_wb_rf_addr = r_waddr;//32'bX;
assign debug_wb_rf_wdata =r_wdata;// 32'bX;
endmodule