ソースコードの17行目は外部のソースコードに記述されている回路を読み込むための記述です。先頭の”ram01”というのが外部のソースコードのmodule文で定義されている回路の名前になります。その後に続く”ram01_0”というのは読み込んだ回路を現在のソースコード上で使用するために付けられる名前です。こちらの名前はmodule文で定義された名前とは関係なく自由に決めてしまって大丈夫です。
“ram01”という名前は私がQuartusのメガファンクションという機能を使ってメモリ回路を生成した時に付けた名前です。このコードをそのまま使用する場合は、後ほど紹介するメガファンクションの生成の時にメモリ回路に付ける名前を“ram01”になるようにしてください。
“ram01_0”の後に続く丸括弧の中には“ram01”の持つ入出力端子名とその端子へ接続する信号名が入ります。ドットで始まる方の名前は“ram01”の持つ入出力端子名を表し、入出力端子が複数存在する場合には端子名の間はコンマで区切られて記述されます。入出力端子名の後ろに続く丸括弧の中にはその端子へ接続する信号の名前が入れられます。例えば17行目の記述の”.wren(mem_w),”の部分が持つ意味は“ram01_0”の持つ4つ目の端子である”wren”に対し、”wrapper_memory”の持つ入力端子である”mem_w”が接続されていることを意味します。
“ram01_0”の持つ1つ目の端子である”address”に対して”wrapper_memory”の持つレジスタである”reg_address[12:0]”が接続されていますが、ここで”reg_address”レジスタの0ビット目から12ビット目までしか”address”端子へ接続されていない理由は、“ram01”の”address”端子のビットサイズが13ビットしかないためです。
“ram01”の”address”端子のビットサイズは、使用するFPGAのメモリ容量によって上限が決められてしまいます。一般的なFPGAが持つメモリ容量でも余裕を持って生成できるように、”address”端子のビットサイズは13ビットにしてあります。このコードをそのまま使用する場合は後ほど紹介するメガファンクションの生成の時に、メモリ回路の”address”端子のビットサイズを13ビットになるようにしてください。
cpu.v
cpu.vはこれまで紹介してきた回路を全てつないでCPUという1つの回路として機能させるためのコードです。CPUの設計図と見比べながらコードを読んでいくと分かりやすいと思います。
module cpu(clk, rst, port_1, port_2, port_3, port_4);
input clk;
input rst;
input [7:0] port_3;
input [7:0] port_4;
output [7:0] port_1;
output [7:0] port_2;
wire clk_2, clk_3;
wire alu_e, wr_e, ir1_e, ir2_e, pc_e, hr_e, mem_e, p1_e, p2_e,
p3_e, p4_e, mem_w, m1_s, m2_s, m3_s, m4_s, m5_s;
wire [3:0] alu_opcode;
wire [7:0] wr;
wire [7:0] ir1;
wire [7:0] ir2;
wire [7:0] hr;
wire [7:0] p3;
wire [7:0] p4;
wire [15:0] pc;
wire [15:0] pc_inc;
wire [7:0] m1;
wire [15:0] m2;
wire [15:0] m3;
wire [7:0] m4;
wire [7:0] m5;
wire [7:0] mem_out;
wire [7:0] alu_out;
wire flag;
wire [15:0] address;
prescaler prescaler_0(.clk(clk), .clk_2(clk_2), .clk_3(clk_3));
control_unit control_unit_0(.clk_3(clk_3), .rst(rst), .flag(flag), .ir1(ir1[4:0]),
.alu_e(alu_e), .wr_e(wr_e), .ir1_e(ir1_e), .ir2_e(ir2_e), .pc_e(pc_e), .hr_e(hr_e),
.mem_e(mem_e), .p1_e(p1_e), .p2_e(p2_e), .p3_e(p3_e), .p4_e(p4_e), .mem_w(mem_w),
.m1_s(m1_s), .m2_s(m2_s), .m3_s(m3_s), .m4_s(m4_s), .m5_s(m5_s),
.alu_opcode(alu_opcode));
register_8 wr_0(.reg_e(wr_e), .rst(rst), .reg_in(m1), .reg_out(wr));
register_8 ir1_0(.reg_e(ir1_e), .rst(rst), .reg_in(mem_out), .reg_out(ir1));
register_8 ir2_0(.reg_e(ir2_e), .rst(rst), .reg_in(mem_out), .reg_out(ir2));
register_8 hr_0(.reg_e(hr_e), .rst(rst), .reg_in(alu_out), .reg_out(hr));
register_8 p1_0(.reg_e(p1_e), .rst(rst), .reg_in(alu_out), .reg_out(port_1));
register_8 p2_0(.reg_e(p2_e), .rst(rst), .reg_in(alu_out), .reg_out(port_2));
register_8 p3_0(.reg_e(p3_e), .rst(rst), .reg_in(port_3), .reg_out(p3));
register_8 p4_0(.reg_e(p4_e), .rst(rst), .reg_in(port_4), .reg_out(p4));
program_counter pc_0(.pc_e(pc_e), .rst(rst), .pc_in(m2), .pc_out(pc),
.pc_inc_out(pc_inc));
multiplexer_8 m1_0(.mux_s(m1_s), .mux_in_a(alu_out), .mux_in_b(ir2), .mux_out(m1));
multiplexer_16 m2_0(.mux_s(m2_s), .mux_in_a(address), .mux_in_b(pc_inc),
.mux_out(m2));
multiplexer_16 m3_0(.mux_s(m3_s), .mux_in_a(address), .mux_in_b(pc), .mux_out(m3));
multiplexer_8 m4_0(.mux_s(m4_s), .mux_in_a(alu_out), .mux_in_b(m5), .mux_out(m4));
multiplexer_8 m5_0(.mux_s(m5_s), .mux_in_a(p3), .mux_in_b(p4), .mux_out(m5));
wrapper_memory memory_0(.clk_2(clk_2), .mem_e(mem_e), .mem_w(mem_w),
.mem_address(m3), .mem_in(m4), .mem_out(mem_out)); alu alu_0 (.alu_e(alu_e),
.rst(rst), .opcode(alu_opcode), .alu_in_a(wr), .alu_in_b(mem_out),
.alu_out(alu_out), .flag(flag));
assign address = {hr, ir2};
endmodule