断罪之眼的最终乐章

[请为一切不真实之物感到骄傲,因为我们高于这个世界!因为,吾等金碧辉煌的王国,是狭小又禁忌的乐土]

介绍

经过了这么多章的学习,我们终于把所有cpu的功能模块全部做完了,那么就让我们拼接在一起吧

拼接顺序

首先 ram与pc计数器是整个cpu的发动者,有了他们,cpu才能发动。
接着pc寄存器的擦写模式由功能解码器控制并且擦写数值由reg3给出。
接着将立即数模块的输出连接到reg0上,reg0的save开启条件也接受功能解码器控制,
接着将判决器的输入与reg3的输出相连,判决器的输出与pc计数器相连
最后再将alu的输入与reg1与reg2的输出相连,alu的输出与总线相连

代码实现

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
module bus(
input reg [7:0] data_in, //外界输入
input reg clk,
input reg rst,
input reg ram_we,
input reg [7:0] ram_data_in,
input reg pc_recount,

output wire [7:0] data_out//输出
);

wire [7:0] data_save_en;
wire [7:0] data_load_en;
wire [7:0] bus_line_w;
wire [3:0] function_sel_w;
wire [7:0] reg_0_always_out_w;
wire [7:0] reg_1_always_out_w;
wire [7:0] reg_2_always_out_w;
wire [7:0] reg_3_always_out_w;

reg en =1'b1;
reg [7:0] code_in=8'b00000000;
reg [7:0] bus_line = 8'b00000000;
reg [7:0] data_load_en_r=8'b00000000;
reg [7:0] data_save_en_r=8'b00000000;
reg [3:0] function_sel=2'b00;
reg reg_3_en=1'b0;
reg reg_0_en=1'b0;
reg [7:0] reg_0_always_out;
reg [7:0] reg_3_always_out;

//最高两位为具体功能 第六位位数据位或地址位
always @(data_save_en or data_load_en or bus_line_w) begin
data_save_en_r<=data_save_en;
data_load_en_r<=data_load_en;
function_sel<=function_sel_w;
bus_line<=bus_line_w;

reg_0_always_out<=reg_0_always_out_w;
reg_3_always_out<=reg_3_always_out_w;
end
//判决器的特殊寄存器
always @(data_save_en_r[3] or function_sel[3])begin
if(data_save_en_r[3]==1'b1 || function_sel[3]==1'b1)
reg_3_en=1'b1;
else
reg_3_en=1'b0;
end

//立即数的特殊寄存器
always @(data_save_en_r[0] or function_sel[0])begin
if(data_save_en_r[0]==1'b1 || function_sel[0]==1'b1)
reg_0_en=1'b1;
else
reg_0_en=1'b0;
end

//功能解码位
decoder_2to4 decoder_2to4_sel(
.in (code_in[7:6]) ,
.en (en),
.out (function_sel_w)
);

//寄存器解码
decoder_3to8 decoder_3to8_save(
.in (code_in[2:0]) ,
.en (function_sel_w[2]) ,

.out (data_save_en)
);

decoder_3to8 decoder_3to8_load(
.in (code_in[5:3]) ,
.en (function_sel_w[2]),

.out (data_load_en)
);

//计算单元alu
alu alu_my(
.alu_sel (function_sel_w[1]),
.alu_order (code_in[2:0]),
.reg_1 (reg_1_always_out_w),
.reg_2 (reg_2_always_out_w),

.alu_out(bus_line_w)
);

//立即数模块
immediate immediate_my(
.count_in(code_in[5:0]),
.count_sel(function_sel_w[0]),

.count_out(bus_line_w)

);

// 判决器模块
arbiter arbiter_my(
.reg_0 (reg_0_always_out),
.reg_3 (reg_3_always_out),
.arbiter_order(code_in[2:0]),
.arbiter_sel(function_sel_w[3]),

.pc_sel (pc_sel),
.arbiter_out (code_addr_out)

);

//寄存器挂载
register_pluse register_pluser_0(
.save_en (reg_0_en),
.load_en (data_load_en_r[0]),
.data_in (bus_line) ,

.data_out (bus_line_w) ,
.data_out_always (reg_0_always_out_w)
);

register_pluse register_pluser_1(
.save_en (data_save_en_r[1]),
.load_en (data_load_en_r[1]),
.data_in (bus_line) ,

.data_out (bus_line_w) ,
.data_out_always (reg_1_always_out_w)
);

register_pluse register_pluser_2(
.save_en (data_save_en_r[2]),
.load_en (data_load_en_r[2]),
.data_in (bus_line) ,
.data_out (bus_line_w) ,
.data_out_always (reg_2_always_out_w)
);

register_pluse register_pluser_3(
.save_en (reg_3_en),
.load_en (data_load_en_r[3]),
.data_in (bus_line) ,
.data_out (bus_line_w) ,
.data_out_always (reg_3_always_out_w)
);

register_pluse register_pluser_4(
.save_en (data_save_en_r[4]),
.load_en (data_load_en_r[4]),
.data_in (bus_line) ,
.data_out (bus_line_w) ,
.data_out_always ()
);

register_pluse register_pluser_5(
.save_en (data_save_en_r[5]),
.load_en (data_load_en_r[5]),
.data_in (bus_line) ,
.data_out (bus_line_w) ,
.data_out_always ()
);

register_pluse register_pluser_6(
.save_en (data_save_en_r[6]),
.load_en (data_load_en_r[6]),
.data_in (bus_line) ,
.data_out (bus_line_w) ,
.data_out_always ()
);


//输入口
register_pluse register_pluser_in(
.save_en (en),
.load_en (data_load_en_r[7]),
.data_in (data_in) ,
.data_out (bus_line_w) ,
.data_out_always ()
);

//输出口
register_pluse register_pluser_out(
.save_en (data_save_en_r[7]),
.load_en (en),
.data_in (bus_line) ,

.data_out (data_out) ,
.data_out_always ()
);


reg pc_sel_r;
reg [7:0] code_addr_out_r;
reg [7:0] pc_addr_r;
wire [7:0] ram_data_out;
wire [7:0] pc_addr;

always @(*) begin
code_addr_out_r<=code_addr_out;
pc_sel_r<=pc_sel;
code_in<=ram_data_out;
pc_addr_r<=pc_addr;
end

//pc计数器
pc_counter pc_counter_my(
.clk (clk),
.reset (rst),
.model_sel (pc_sel_r),
.pc_recount (pc_recount),
.load_value (code_addr_out_r),

.pc_w (pc_addr)
);
//ram
ram_8bit ram_8bit_my(
.clk (clk),
.rst (rst),
.we (ram_we),
.data_in (ram_data_in),
.addr (pc_addr),

.data_out (ram_data_out)
);
endmodule

测试代码

如果上面的cpu模块没错的话,测试代码中cpu将不断循环

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

`timescale 1ns/1ns

module bus_tb;

reg data_in=8'b0;
reg clk=1'b0;
reg rst=1'b0;
reg ram_we=1'bz;
reg [7:0] ram_data_in=8'b 00000000;
reg pc_recount=1'b0;




wire [7:0] data_out;


initial begin
//从ram输入指令 写操作

#1 rst=1'b1;
#1 rst=1'b0;
ram_we=1'b1;

#10 ram_data_in=8'b 00_111_000; // 从输入赋予寄存器0 ram地址0
#10 ram_data_in=8'b10_000_001; // 复制寄存器0的值到寄存器1 ram地址1
#10 ram_data_in=8'b 11_000_011; // 复制寄存器0的值到寄存器3 ram地址2
#10 ram_data_in=8'b 00_000_000; // 从输入赋予寄存器0 ram地址3
#10 ram_data_in=8'b 11_000_100; // 跳转回ram地址处0

//从ram读取指令 读操作
#10 ram_we=1'b0;
pc_recount=1'b1;
#10 pc_recount=1'b0;



end

always #5 clk=~clk;


bus bus_my(
.data_in (data_in), //外界输入
.clk (clk),
.rst (rst),
.ram_we (ram_we),
.ram_data_in (ram_data_in),
.pc_recount (pc_recount),

.data_out (data_out)//输出

);

endmodule

结语

经过十章的学习我们终于将完整的cpu搭建出来了,当我第一次接触cpu这个概念的时候觉得非常的高大上,网上的资料中关于cpu的架构和指令集都十分复杂,都是使用现代的主流架构搭建cpu,如:arm,risv等。使我在一段时间内对于cpu望而却步,但是当我接触了图灵完备的游戏后我理解了再复杂的架构也是由简单的门级电路封装起来的。若你玩过图灵完备这款游戏,你会知道用verilog搭建出cpu比游戏中用一个个门级电路简单很多。我写这篇文章的目的是为了填补国内的cpu入门教程,从最简单的cpu架构开始做起。

整点二次元

img1