计组实验2_后四次

Uncategorized
5.2k words

第二次实验 单周期CPU

单周期CPU(I型指令)

题目
在单周期CPU(R型指令)设计的基础上增加下列I型指令: addi,addiu,andi,ori,lui。
分析
alt text
My test image
数据通路图
My test image
指令格式: I型指令和R型指令的格式不同;
指令功能:指令执行流程相同,取指→ 立即数扩展(读源操作数)→运算→写回运算结果。
复用:取指,读GPR,ALU,写GPR。
增加:立即数扩展功能;ALU增加lui指令的功能;
增加立即数为ALU的操作数2 ;增加rt为GPR的写寄存器。
当一个端口有多个输入时,需要在其前面增加多路选择器。
多路选择器根据控制信号确定具体情况时端口接哪个输入。
补充:ctrl模块

1
2
3
4
module ctrl(output reg_write  ,
output[3:0] aluop,
input [5:0] op ,
input [5:0] funct );

dm模块和MEM型指令

数据通路图
My test image
1.DM模块设计
alt text
My test image

  • lw指令读DM→ 一个读端口
  • sw指令写DM→ 一个写端口

读端口是组合逻辑,在指令执行的clock周期保持不变。
写端口是时序逻辑,在指令执行的clock周期结束时把结果写入。
读端口和写端口不会同时使用,而且地址计算方法相同,所以可以共用地址线。
不是每种指令都写DM ,所以写端口需要写使能信号控制。

信号名 方向 描述
data_out[31:0] O 读出的数据
clock I 时钟信号,上升沿有效
mem_write I 写使能信号 1:有效;0:无效。
address[31:0] I 读写地址
data_in[31:0] I 要写入的数据
功能名称 功能描述
读存储器 data_out = 数据存储器[address]。
写存储器 mem_write信号有效时,在clock的上升沿,数据存储器[address] = data_in。

mem型指令
DM
My test image
alt text
My test image
结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
`include "alu.v"
`include "pc.v"
`include "gpr.v"
`include "im.v"
`include "ctrl.v"
`include "mux.v"
`include "ext.v"
`include "dm.v"

module s_cycle_cpu(
input clock,
input reset);

wire [31:0] pc_out;// 程序计数器输出
reg [31:0] npc;// 下一条指令地址

wire [31:0] im_out;// 指令存储器输出

reg [5:0] opcode;
reg [4:0] rs;
reg [4:0] rt;
reg [4:0] rd;
reg [5:0] funct;
reg [15:0] imm;// 立即数

wire reg_write;
wire [3:0] alu_if;// ALU操作码
wire s_num_write;// 写寄存器号
wire [1:0] s_ext;// 扩展方式
wire s_b;// 选择B
wire s_data_write;// 写数据
wire mem_write;// 写内存

wire [31:0] alu_out;// ALU输出
wire [31:0] a;// 寄存器A
wire [31:0] b;// 寄存器B
wire [4:0] num_write;// 写寄存器号
wire [31:0] data_write;// 写数据
wire [31:0] alu_b;// ALU输入B
wire [31:0] ext_out;// 扩展输出

wire [31:0] dm_out;// 数据存储器输出

// 以下为模块实例化
pc PC(
.pc(pc_out),
.clock(clock),
.reset(reset),
.npc(npc)
);
im IM(
.instruction(im_out),
.pc(pc_out)
);

// 从指令中提取操作码、寄存器号、立即数等
always @(*)
begin
opcode <= im_out[31:26];
rs <= im_out[25:21];
rt <= im_out[20:16];
rd <= im_out[15:11];
funct <= im_out[5:0];
npc <= pc_out + 4;

imm[15:0] <= im_out[15:0];// 立即数
end
assign reg_write = 1;// 对于addu指令,寄存器写使能信号总是1
// 以下为模块实例化
ctrl CTRL(
.reg_write(reg_write),
.aluif(alu_if),
.s_num_write(s_num_write),
.s_ext(s_ext),
.s_b(s_b),
.s_data_write(s_data_write),
.mem_write(mem_write),
.op(opcode),
.funct(funct)
);

mux #(.WIDTH(5)) MUX1(
.y(num_write),
.a(rt),
.b(rd),
.sel(s_num_write)
);// 写寄存器号

gpr GPR(
.a(a),
.b(b),
.clock(clock),
.reg_write(1), //此处作用为初始化为1
.num_write(num_write),
.rs(rs),
.rt(rt),
.data_write(data_write)
);// 通用寄存器

mux #(.WIDTH(32)) MUX2(
.y(alu_b),
.a(b),
.b(ext_out),
.sel(s_b)
);// 选择B

alu ALU (
.c(alu_out),
.a(a),
.b(alu_b),
.alu_if(alu_if)
);// 算术逻辑单元

ext EXT(
.ext_out(ext_out),
.imm(imm),
.extop(s_ext)
);// 扩展单元

mux #(.WIDTH(32)) MUX3(
.y(data_write),
.a(alu_out),
.b(dm_out),
.sel(s_data_write)
);// 写数据

dm DM(
.data_out(dm_out),
.clock(clock),
.mem_write(mem_write),
.address(alu_out),
.data_in(b)
);// 数据存储器()

endmodule

DM模块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
module dm (

output [31:0] data_out, // 输出数据
input clock,
input mem_write, // 写使能
input [31:0] address, // 地址
input [31:0] data_in // 输入数据
);
reg [31:0] data_memory[1023:0]; // 4k数据存储器
assign data_out = data_memory[address[11:2]];// 读数据

always @(posedge clock)// 时序逻辑
if(mem_write)
data_memory[address[11:2]] <= data_in;// 写数据
endmodule

mux(二选一选择器)

1
2
3
4
5
6
7
8
9
module mux #(parameter WIDTH = 32) (
output [WIDTH-1:0] y,// 输出
input [WIDTH-1:0] a,// 输入1
input [WIDTH-1:0] b,// 输入2
input sel);// 选择信号

assign y = (sel == 1) ? b : a;

endmodule

ctrl模块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
module ctrl(
output reg reg_write,// 写使能
output reg [3:0] aluif,// ALU操作码
output reg s_num_write,// 写寄存器号
output reg [1:0] s_ext,// 扩展方式
output reg s_b,// 选择B
output reg s_data_write,// 写数据
output reg mem_write,// 写内存
input [5:0] op,// 操作码
input [5:0] funct// 功能码
);

always @(*)
case(op)
6'b100011://LW
begin
reg_write <= 1;
aluif <= 6'b0001;//addu
s_num_write <= 0;
s_ext <= 2'b10;// 扩展方式:符号扩展
s_b <= 1;
s_data_write <= 1;
mem_write <= 0;
end
6'b101011://SW
begin
reg_write <= 0;
aluif <= 6'b0001;//addu
s_num_write <= 0;
s_ext <= 2'b10;// 扩展方式:符号扩展
s_b <= 1;
s_data_write <= 0;
mem_write <= 1;
end
6'b001000://ADDI
begin
reg_write <= 1;
aluif <= 6'b0001;//addu
s_num_write <= 0;
s_ext <= 2'b10;// 扩展方式:符号扩展
s_b <= 1;
s_data_write <= 0;
mem_write <= 0;
end
6'b001001://ADDIU
begin
reg_write <= 1;
aluif <= 6'b0001;//addu
s_num_write <= 0;
s_ext <= 2'b10;// 扩展方式:符号扩展
s_b <= 1;
s_data_write <= 0;
mem_write <= 0;
end
6'b001100://ANDI
begin
reg_write <= 1;
aluif <= 6'b0100;//and
s_num_write <= 0;
s_ext <= 2'b01;// 扩展方式:零扩展
s_b <= 1;
s_data_write <= 0;
mem_write <= 0;
end
6'b001101://ORI
begin
reg_write <= 1;
aluif <= 6'b0101;//or
s_num_write <= 0;
s_ext <= 2'b01;// 扩展方式:零扩展
s_b <= 1;
s_data_write <= 0;
mem_write <= 0;
end
6'b001111://LUI
begin
reg_write <= 1;
aluif <= 6'b0001;//addu
s_num_write <= 0;
s_ext <= 2'b11;// 扩展方式:L
s_b <= 1;
s_data_write <= 0;
mem_write <= 0;
end

6'b000000://R-type
begin
reg_write <= 1;
aluif <= funct[3:0];
s_num_write <= 1;
s_ext <= 2'b00;// 扩展方式:默认
s_b <= 0;
s_data_write <= 0;
mem_write <= 0;
end
default:
begin
reg_write <= 1;
end

endcase

endmodule

后记:实验报告终于干完了,就不写了,附上报告祸害造福后人。
实验报告-单周期CPU
提取码:UNms

Comments