-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcpu.v
More file actions
140 lines (123 loc) · 3.81 KB
/
cpu.v
File metadata and controls
140 lines (123 loc) · 3.81 KB
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
//--------------------------------
// 4bitCPU 「TD4」
//
// $ git clone git@gist.github.com:ed0575c2871070ecc89d99bd7e357f5d.git my_td4
// $ cd my_td4
// $ brew install icarus-verilog
// $ iverilog -o cpu cpu.v && ./cpu
//--------------------------------
module cpu(
input clk,
input n_reset,
output [3:0] address,
input [7:0] instr,
input [3:0] in,
output [3:0] out);
//------------------------
// (デバッグ用)モニタの設定
//------------------------
initial begin
// $monitor("%t: pc = %b, a = %b, b = %b, instr = %b, op = %b, im = %b, select_a = %b, select_b = %b, load0 = %b, load1 = %b, load2 = %b", $time, pc_reg, a_reg, b_reg, instr, op, im, select_a, select_b, load0, load1, load2);
end
//------------------------
// ワイヤ・レジスタの宣言
//------------------------
wire [3:0] op;
wire [3:0] im;
wire select_a, select_b;
wire load0, load1, load2, load3;
wire [3:0] selector_out;
wire [3:0] alu_out;
wire c; // Carry out
reg [3:0] pc_reg; // Program counter
reg [3:0] a_reg, b_reg; // A, B register
reg [3:0] out_reg; // Out port register
reg co_reg; // Carry out register
//------------------------
// 外部モジュールとの接続
//------------------------
// データセレクタ
data_selector ds (a_reg, b_reg, in, 4'b0000, select_a, select_b, selector_out);
//------------------------
// レジスタ
//------------------------
always @(posedge clk or negedge n_reset) begin
if (!n_reset) begin
a_reg <= 0;
b_reg <= 0;
// out_reg <= 0;
end
else begin
a_reg <= load0 ? alu_out : a_reg;
b_reg <= load1 ? alu_out : b_reg;
// out_reg <= load2 ? alu_out : out_reg;
end
end
//------------------------
// 出力ポート
//------------------------
assign out = out_reg;
always @(posedge clk or negedge n_reset) begin
if (!n_reset) out_reg <= 0;
else out_reg <= load2 ? alu_out : out_reg;
end
//------------------------
// プログラムカウンタ
//------------------------
assign address = pc_reg;
always @(posedge clk or negedge n_reset) begin
if (!n_reset) pc_reg <= 0;
else pc_reg <= load3 ? im : pc_reg + 1;
end
//------------------------
// ALU と carry レジスタ
//------------------------
assign {c, alu_out} = selector_out + im;
always @(posedge clk or negedge n_reset) begin
if (!n_reset) co_reg <= 0;
else co_reg <= c;
end
//------------------------
// 命令のデコード
//------------------------
// 命令を「オペレーションコード」と「イミディエイトデータ」へ分割
assign op = instr[7:4]; // オペレーションコード
assign im = instr[3:0]; // イミディエイトデータ
// データセレクタ制御フラグ
assign select_a = op[0] | op[3];
assign select_b = op[1];
// ロードレジスタ制御フラグ
assign load0 = !(op[2] | op[3]); // Aレジスタへロード
assign load1 = !(!op[2] | op[3]); // Bレジスタへロード
assign load2 = !op[2] & op[3]; // 出力ポートへロード
assign load3 = (!co_reg | op[0]) & op[2] & op[3]; // PCへロード
endmodule
//------------------------
// データセレクタ
//
// select_a、select_bの信号に応じてc0〜c3の信号を出力する
//
// * (select_a = L, select_b = L) => c0を出力
// * (select_a = H, select_b = L) => c1を出力
// * (select_a = L, select_b = H) => c2を出力
// * (select_a = H, select_b = H) => c3を出力
//------------------------
module data_selector(
input [3:0] c0,
input [3:0] c1,
input [3:0] c2,
input [3:0] c3,
input select_a, select_b,
output reg [3:0] y
);
always @(*) begin
if (select_a & select_b)
y = c3;
else if (!select_a & select_b)
y = c2;
else if (select_a & !select_b)
y = c1;
else
y = c0;
end
endmodule