2013年6月23日日曜日

平成25年度 春期 応用情報技術者試験 結果

AP受けました。受かりました。
だからなんだって話ですけどね。

一応経緯をさらっと述べると,
旧試のFE受かる
→旧試のSW落ちる
→やーめた
→悠久の時の流れ(超えられない壁)
→新試AP合格
みたいな。

んで,結果。

得点
午前75.00点
午後82.00点

午前分野別得点
ストラテジ系15.00点 / 25.00点 (60.0%)
マネジメント系11.25点 / 12.50点 (90.0%)
テクノロジ系48.75点 / 62.50点 (78.0%)

午後の問題選択分野
2(アルゴリズム),
4(システムアーキテクチャ),
5(ネットワーク),
7(エンベデッド),
8(システム開発),
9(セキュリティ)

総括: 午前のテクノロジもっと取りたかった(85%くらい)。

2013年2月15日金曜日

Compiled gcc4.7.2

gcc4.7(.2)の環境つくった忘備録

意外と面倒なgccのコンパイル。
最新版のgccであれこれ楽しもう的な。
環境はCentOS 6。
その忘備録。



用意するもの

pplとcloog(cloog-ppl)以外はそれぞれ最新版のソースをもってくる。
pplとcloog(cloog-ppl)はどうもバージョンの指定があり,依存があるらしい。
詳しくはgccのソースを展開してINSTALLディレクトリのドキュメントを参照すればいい。
というか,gccのインストールに必要なことはだいたいそこに書かれいてる。
  • binutils (2.23.1)
  • gmp (5.1.1)
  • mpfr (3.1.1)
  • mpc (1.0)
  • ppl (0.11)
  • cloog / cloog-ppl (cloog-ppl-0.15.11)
  • gcc (4.7.2)

以下全部スーパーユーザで作業します。

1. binutils

# tar zxvf binutils-2.23.1.tar.gz
# cd binutils-2.23.1
# mkdir build; cd build
# ../configure
# make
# make check
# make install


2. GMP

--enable-cxxを付け忘れるとPPLのmakeで痛い目に遭う。
# tar jxvf gmp-5.1.1.tar.bz2
# cd gmp-5.1.1
# mkdir build; cd build
# ../configure --enable-cxx
# make
# make check
# make install
そんでもって,これを忘れてハマった!
環境変数の設定。
# export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH
# export LD_RUN_PATH=/usr/local/lib:$LD_RUN_PATH


3. MPFR

# tar jxvf mpfr-3.1.1.tar.bz2
# cd mpfr-3.1.1
# mkdir build; cd build
# ../configure --with-gmp=/usr/local
# make
# make check
# make install


4. MPC

# tar zxvf gmp-1.0.tar.gz
# cd gmp-1.0
# mkdir build; cd build
# ../configure --with-gmp=/usr/local --with-mpfr=/usr/local
# make
# make check
# make install


5. PPL

たしか,多重定義エラーでmakeがこけるので,/usr/local/include/gmpxx.hのほうをコメントアウトで解決する。
# tar zxvf ppl-0.11.tar.gz
# cd ppl-0.11
# mkdir build; cd build
# ../configure --with-gmp-prefix=/usr/local
# make
# make check
# make install


6. cloog / cloog-ppl

# tar zxvf cloog-ppl-0.15.11.tar.gz
# cd cloog-ppl-0.15.11
# mkdir build; cd build
# ../configure  --with-gmp=/usr/local --with-ppl=/usr/local
# make
# make check
# make install


7. GCC

# tar zxvf gcc-4.7.2.tar.gz
# cd gcc-4.7.2
# mkdir build; cd build
# ../configure --with-gmp=/usr/local --with-mpfr=/usr/local --with-mpc=/usr/local --with-ppl=/usr/local --with-cloog=/usr/local --program-suffix=-4.7
# make
# make check
# make install


これで
# gcc-4.7 -v
とでもすればうまくいったと確認できる。

2012年9月20日木曜日

週刊 TD4をFPGAで創る 第5号 「命令デコーダを創る」

週刊 TD4をFPGAで創る 第5号 「命令デコーダを創る」

第9章からです。
ついにシミュレーション編完結!!

命令デコーダがどのような経緯でIC2つに収まったかは渡波(2003)をご参照くださいな。

Amazon.co.jp - 渡波 郁 「CPUの創りかた」 毎日コミュニケーションズ (2003)

1.74HC10

まずは3入力NAND3つ入り!

module LOGIC_74HC10(A1, B1, C1, Y1, A2, B2, C2, Y2, A3, B3, C3, Y3);
 input A1, B1, C1, A2, B2, C2, A3, B3, C3;
 output Y1, Y2, Y3;
 
 assign Y1 = ~(A1 & B1 & C1);
 assign Y2 = ~(A2 & B2 & C2);
 assign Y3 = ~(A3 & B3 & C3);
endmodule

テストベンチはいらないよね?

2.74HC32

次に2入力OR4つ入り!

module LOGIC_74HC32(A1, B1, Y1, A2, B2, Y2, A3, B3, Y3, A4, B4, Y4);
 input A1, B1, A2, B2, A3, B3, A4, B4;
 output Y1, Y2, Y3, Y4;
 
 assign Y1 = A1 | B1;
 assign Y2 = A2 | B2;
 assign Y3 = A3 | B3;
 assign Y4 = A4 | B4;
endmodule

これもテストベンチはいらないよね?

3.命令デコーダ

いよいよ命令デコーダづくり!
気合入れていきましょう。

module InstructionDecoder(OPERATION_CODE, C_FLAG_BAR, LOAD_0, LOAD_1, LOAD_2, LOAD_3, SELECT_A, SELECT_B);
 input [3:0] OPERATION_CODE;
 input C_FLAG_BAR;
 output LOAD_0, LOAD_1, LOAD_2, LOAD_3, SELECT_A, SELECT_B;
 
 reg Vcc = 1;
 reg GND = 0;
 
 wire [1:0] w;
 
 assign SELECT_B = OPERATION_CODE[1];
 
 LOGIC_74HC32 logic_74hc32 (
  OPERATION_CODE[2], OPERATION_CODE[3], LOAD_0, 
  w[0], OPERATION_CODE[3], LOAD_1, 
  OPERATION_CODE[0], OPERATION_CODE[3], SELECT_A, 
  OPERATION_CODE[0], C_FLAG_BAR, w[1]
  );
 
 LOGIC_74HC10 logic_74hc10 (
  OPERATION_CODE[2], Vcc, Vcc, w[0], 
  Vcc, w[0], OPERATION_CODE[3], LOAD_2, 
  OPERATION_CODE[2], OPERATION_CODE[3], w[1], LOAD_3
  );
endmodule

はい!出来上がり!

テストベンチはこんな感じ!

module instruction_decoder_test;
 reg  [3:0] OPCODE;
 reg  C_FLAG_BAR;
 wire LOAD_0, LOAD_1, LOAD_2, LOAD_3, SELECT_A, SELECT_B;
 
 InstructionDecoder decoder(OPCODE, C_FLAG_BAR, LOAD_0, LOAD_1, LOAD_2, LOAD_3, SELECT_A, SELECT_B);
 
 initial begin
  $dumpfile("instruction_decoder_test.vcd");
  $dumpvars(0, instruction_decoder_test);
  $monitor ("%t: OPCODE = %b%b%b%b, C_FLAG_BAR = %b, (SELECT_B, A, LOAD_0, 1, 2, 3) = %b %b %b %b %b %b", 
   $time, OPCODE[3], OPCODE[2], OPCODE[1], OPCODE[0], C_FLAG_BAR, 
   SELECT_B, SELECT_A, LOAD_0, LOAD_1, LOAD_2, LOAD_3);

   OPCODE = 4'b0000; C_FLAG_BAR = 1'b0;
  #10 OPCODE = 4'b0001; C_FLAG_BAR = 1'b0;
  #10 OPCODE = 4'b0010; C_FLAG_BAR = 1'b0;
  #10 OPCODE = 4'b0011; C_FLAG_BAR = 1'b0;
  #10 OPCODE = 4'b0100; C_FLAG_BAR = 1'b0;
  #10 OPCODE = 4'b0101; C_FLAG_BAR = 1'b0;
  #10 OPCODE = 4'b0110; C_FLAG_BAR = 1'b0;
  #10 OPCODE = 4'b0111; C_FLAG_BAR = 1'b0;
  #10 OPCODE = 4'b1001; C_FLAG_BAR = 1'b0;
  #10 OPCODE = 4'b1011; C_FLAG_BAR = 1'b0;
  #10 OPCODE = 4'b1110; C_FLAG_BAR = 1'b0;
  #10 OPCODE = 4'b1110; C_FLAG_BAR = 1'b1;
  #10 OPCODE = 4'b1111; C_FLAG_BAR = 1'b0;
  #10 $finish;
 end
endmodule

出力結果をよーく本と見比べてね!

4.そして,完成へ…

長かったCPUづくりもいよいよ一段落です。
すべてのパーツを組み合わせましょう。

module Processor(RESET, CLOCK, INPUT, OUTPUT);
 input RESET, CLOCK;
 input [3:0] INPUT;
 output [3:0] OUTPUT;
 
 reg  Vcc = 1'b1;
 reg  GND = 1'b0;
 wire [5:0] NOT_IN_USE;
 
 wire [3:0] ROM_ADDRESS;
 wire [7:0] ROM_DATA;
 wire [3:0] OPERATION_CODE;
 wire [3:0] IMEEDIATE_DATA;
 
 wire LOAD_0, LOAD_1, LOAD_2, LOAD_3, SELECT_A, SELECT_B;
 
 wire [3:0] REGISTER_IN;
 wire [3:0] REGISTER_A_OUT;
 wire [3:0] REGISTER_B_OUT;
 wire [3:0] REGISTER_C_OUT;
 wire [3:0] REGISTER_D_OUT;
 wire [3:0] ALU_IN_A;
 wire [3:0] ALU_IN_B;
 wire CARRY_OUT, C_FLAG, C_FLAG_BAR;
 
 assign ROM_ADDRESS = REGISTER_D_OUT;
 assign OPERATION_CODE = ROM_DATA[7:4];
 assign IMEEDIATE_DATA = ROM_DATA[3:0];
 assign ALU_IN_B = IMEEDIATE_DATA;
 assign OUTPUT = REGISTER_C_OUT;
 
 ROM_16WORD  ROM(ROM_ADDRESS, ROM_DATA);
 
 InstructionDecoder Instruction_Decoder (OPERATION_CODE, C_FLAG_BAR, 
  LOAD_0, LOAD_1, LOAD_2, LOAD_3, SELECT_A, SELECT_B);
 
 LOGIC_74HC161 Register_A (RESET, CLOCK, 
  REGISTER_IN[0], REGISTER_IN[1], REGISTER_IN[2], REGISTER_IN[3], 
  GND, LOAD_0, GND, 
  REGISTER_A_OUT[0], REGISTER_A_OUT[1], REGISTER_A_OUT[2], REGISTER_A_OUT[3], 
  NOT_IN_USE[0]);
  
 LOGIC_74HC161 Register_B (RESET, CLOCK, 
  REGISTER_IN[0], REGISTER_IN[1], REGISTER_IN[2], REGISTER_IN[3], 
  GND, LOAD_1, GND, 
  REGISTER_B_OUT[0], REGISTER_B_OUT[1], REGISTER_B_OUT[2], REGISTER_B_OUT[3], 
  NOT_IN_USE[1]);
  
 LOGIC_74HC161 Register_C (RESET, CLOCK, 
  REGISTER_IN[0], REGISTER_IN[1], REGISTER_IN[2], REGISTER_IN[3], 
  GND, LOAD_2, GND, 
  REGISTER_C_OUT[0], REGISTER_C_OUT[1], REGISTER_C_OUT[2], REGISTER_C_OUT[3], 
  NOT_IN_USE[2]);
  
 LOGIC_74HC161 Register_D (RESET, CLOCK, 
  REGISTER_IN[0], REGISTER_IN[1], REGISTER_IN[2], REGISTER_IN[3], 
  Vcc, LOAD_3, Vcc, 
  REGISTER_D_OUT[0], REGISTER_D_OUT[1], REGISTER_D_OUT[2], REGISTER_D_OUT[3], 
  NOT_IN_USE[3]);
 
 LOGIC_74HC153 Register_Selector_0 (SELECT_A, SELECT_B, GND, GND, 
  REGISTER_A_OUT[0], REGISTER_B_OUT[0], REGISTER_C_OUT[0], GND, 
  REGISTER_A_OUT[1], REGISTER_B_OUT[1], REGISTER_C_OUT[1], GND,
  ALU_IN_A[0], ALU_IN_A[1]);
  
 LOGIC_74HC153 Register_Selector_1 (SELECT_A, SELECT_B, GND, GND, 
  REGISTER_A_OUT[2], REGISTER_B_OUT[2], REGISTER_C_OUT[2], GND, 
  REGISTER_A_OUT[3], REGISTER_B_OUT[3], REGISTER_C_OUT[3], GND, 
  ALU_IN_A[2], ALU_IN_A[3]);
 
 LOGIC_74HC283 ALU (GND, 
  ALU_IN_A[0], ALU_IN_A[1], ALU_IN_A[2], ALU_IN_A[3], 
  ALU_IN_B[0], ALU_IN_B[1], ALU_IN_B[2], ALU_IN_B[3], 
  REGISTER_IN[0], REGISTER_IN[1], REGISTER_IN[2], REGISTER_IN[3], 
  CARRY_OUT);
 
 LOGIC_74HC74 C_Flag (RESET, CARRY_OUT, CLOCK, Vcc, C_FLAG, C_FLAG_BAR, 
  GND, GND, GND, GND, NOT_IN_USE[4], NOT_IN_USE[5]);
 
endmodule

完成!!!!!!!!!

実際に動かしてみよう!
テストベンチは次の通り。

module processor_test;
 reg  RESET, CLOCK;
 reg  [3:0] INPUT;
 wire [3:0] OUTPUT;
 
 Processor processor(RESET, CLOCK, INPUT, OUTPUT);
 
 initial begin
  $dumpfile("processor_test.vcd");
  $dumpvars(0, processor_test);
  $monitor ("%t: CLOCK = %b, RESET = %b, INPUT = %b%b%b%b, OUTPUT = %b%b%b%b", 
   $time, CLOCK, RESET, 
   INPUT[3], INPUT[2], INPUT[1], INPUT[0], 
   OUTPUT[3], OUTPUT[2], OUTPUT[1], OUTPUT[0]);
  
  CLOCK = 0;
  RESET = 1;
  INPUT = 4'b0000;
  #400 $finish;
 end
 
 always #1
  CLOCK = ~CLOCK;
endmodule

LEDチカチカとラーメンタイマーそれぞれ動いたでしょうか?
これにて一段落。

次回予告

次回は実際にFPGAに実装してみたいと思います。(多分)

Amazon.co.jp - 渡波 郁 「CPUの創りかた」 毎日コミュニケーションズ (2003)

2012年9月13日木曜日

週刊 TD4をFPGAで創る 第4号 「ALUを創る」

週刊 TD4をFPGAで創る 第4号 「ALUを創る」

第8章からです。
頑張って記事を書くぞ!

1.74HC283

というわけで4bit Full-Adder。
P信号,G信号を使ってCarry-LookaheadなAdderにするって奴はテストによく出るよ!

module LOGIC_74HC283(CIN, A1, A2, A3, A4, B1, B2, B3, B4, S1, S2, S3, S4, COUT);
 input CIN, A1, A2, A3, A4, B1, B2, B3, B4;
 output S1, S2, S3, S4, COUT;
 
 wire [3:0] G;
 wire [3:0] P;
 wire [3:0] C;
 
 assign G[0] = ~(A1 & B1);
 assign G[1] = ~(A2 & B2);
 assign G[2] = ~(A3 & B3);
 assign G[3] = ~(A4 & B4);
 
 assign P[0] = ~(A1 | B1);
 assign P[1] = ~(A2 | B2);
 assign P[2] = ~(A3 | B3);
 assign P[3] = ~(A4 | B4);
 
 assign C[0] = CIN;
 assign C[1] = ~((~CIN & G[0]) | P[0]);
 assign C[2] = ~((~CIN & G[0] & G[1]) | (G[1] & P[0]) | P[1]);
 assign C[3] = ~((~CIN & G[0] & G[1] & G[2]) | (G[1] & G[2] & P[0]) | (G[2] & P[1]) | P[2]);
 assign COUT = ~((~CIN & G[0] & G[1] & G[2] & G[3]) | (G[1] & G[2] & G[3] & P[0]) | (G[2] & G[3] & P[1]) | (G[3] & P[2]) | P[3]);
 
 assign S1 = (C[0] ^ (~P[0] & G[0]));
 assign S2 = (C[1] ^ (~P[1] & G[1]));
 assign S3 = (C[2] ^ (~P[2] & G[2]));
 assign S4 = (C[3] ^ (~P[3] & G[3]));
endmodule

テストベンチはこんな感じ?

module logic_74hc283_test;
 reg  CIN;
 reg  [3:0] A;
 reg  [3:0] B;
 wire [3:0] S;
 wire COUT;
 
 LOGIC_74HC283 logic_74hc283(CIN, 
  A[0], A[1], A[2], A[3], 
  B[0], B[1], B[2], B[3], 
  S[0], S[1], S[2], S[3], 
  COUT);
 
 initial begin
  $dumpfile("logic_74hc283_test.vcd");
  $dumpvars(0, logic_74hc283_test);
  $monitor ("%t: A = %d, B = %d, CIN = %b, S = %d, COUT = %b", 
   $time, A, B, CIN, S, COUT);
   
   CIN = 0;
   A = 0; B = 0;
  #10 A = 1; B = 1;
  #10 A = 1; B = 2;
  #10 A = 2; B = 3;
  #10 A = 4; B = 2;
  #10 A = 4; B = 3;
  #10 A = 4; B = 5;
  #10 A = 8; B = 10;
  #10 A = 6; B = 7;
  #10 A = 12; B = 9;
  #10 $finish;
 end
endmodule

番外編

2.74HC181

物理的になくても,Verilogで書くことならできちゃうんです。簡単にね!

回路図はこんな感じです。


まったく,わけがわからないよ。
でも,なんとなーく,左右にわかれてますよね?よね?



色をつけるとわかりやすい!
それじゃあ元気よく実装しましょう!(半泣)

module LOGIC_74HC181(CIN, S0, S1, S2, S3, M, A0, A1, A2, A3, B0, B1, B2, B3, F0, F1, F2, F3, COUT, COMP, G, P);
 input CIN, S0, S1, S2, S3, M, A0, A1, A2, A3, B0, B1, B2, B3;
 output F0, F1, F2, F3, COUT, COMP, G, P;
 
 wire [3:0] D;
 wire [3:0] E;
 wire [3:0] F;
 
 assign D[0] = ~((~B0 & S1) | (B0 & S0) | A0);
 assign D[1] = ~((~B1 & S1) | (B1 & S0) | A1);
 assign D[2] = ~((~B2 & S1) | (B2 & S0) | A2);
 assign D[3] = ~((~B3 & S1) | (B3 & S0) | A3);
 assign E[0] = ~((B0 & S3 & A0) | (A0 & S2 & ~B0));
 assign E[1] = ~((B1 & S3 & A1) | (A1 & S2 & ~B1));
 assign E[2] = ~((B2 & S3 & A2) | (A2 & S2 & ~B2));
 assign E[3] = ~((B3 & S3 & A3) | (A3 & S2 & ~B3));
 
 assign F0 = ((D[0] ^ E[0]) ^ ~(CIN & ~M));
 assign F1 = ((D[1] ^ E[1]) ^ ~((CIN & E[0] & ~M) | (D[0] & ~M)));
 assign F2 = ((D[2] ^ E[2]) ^ ~((CIN & E[0] & E[1] & ~M) | (E[1] & D[0] & ~M) | (D[1] & ~M)));
 assign F3 = ((D[3] ^ E[3]) ^ ~((CIN & E[0] & E[1] & E[2] & ~M) | (E[1] & E[2] & D[0] & ~M) | (E[2] & D[1] & ~M) | (D[2] & ~M)));
 
 assign P = ~(E[0] & E[1] & E[2] & E[3]);
 assign G = ~(D[3] | (E[3] & D[2]) | (E[3] & E[2] & D[1]) | (E[3] & E[2] & E[1] & D[0]));
 assign COMP = F0 & F1 & F2 & F3;
 assign COUT = ~G | (E[3] & E[2] & E[1] & E[0] & CIN);
endmodule

網羅テストを実行するのはさすがに無理だと思うので,適当にテストベンチ書いてテストしてみるといいよ!
あと,このICはActive-LowとActive-Highで挙動が違うから注意してね!
詳しいことはデータシート読め!

番外編終わり

3.74HC74

フラグレジスタ用のフリップフロップ回路です。
奥さん!二個入りニコニコ大特価だよ!

module LOGIC_74HC74(CLR1, D1, CK1, PR1, Q1, Qb1, CLR2, D2, CK2, PR2, Q2, Qb2);
 input CLR1, D1, CK1, PR1, CLR2, D2, CK2, PR2;
 output Q1, Qb1, Q2, Qb2;
 reg  Q1, Q2;
 
 assign Qb1 = ~Q1;
 assign Qb2 = ~Q2;
 
 initial begin
  Q1 <= 1'b0;
  Q2 <= 1'b0;
 end
 
 always @(CLR1, CK1, PR1, CLR2, CK2, PR2) begin
  if(~CLR1) begin
   Q1 <= 1'b0;
  end else if(~PR1) begin
   Q1 <= 1'b1;
  end else if(CK1) begin
   Q1 <= D1;
  end
  
  if(~CLR2) begin
   Q2 <= 1'b0;
  end else if(~PR2) begin
   Q2 <= 1'b1;
  end else if(CK2) begin
   Q2 <= D2;
  end
 end
endmodule

テストベンチはこんな感じ?

module logic_74hc74_test;
 reg  CLR1, D1, CK1, PR1, CLR2, D2, CK2, PR2;
 wire Q1, Qb1, Q2, Qb2;
 
 LOGIC_74HC74 logic_74hc74(CLR1, D1, CK1, PR1, Q1, Qb1, CLR2, D2, CK2, PR2, Q2, Qb2);
 
 initial begin
  $dumpfile("logic_74hc74_test.vcd");
  $dumpvars(0, logic_74hc74_test);
  $monitor ("%t: CK1 = %b, (CLR1, PR1) = (%b, %b), D1 = %b, Q1 = %b | CK2 = %b, (CLR2, PR2) = (%b, %b), D2 = %b, Q2 = %b",
   $time, CK1, CLR1, PR1, D1, Q1, CK2, CLR2, PR2, D2, Q2);
  
  CK1 = 0; CK2 = 0;
  CLR1 = 1; CLR2 = 1;
  PR1 = 1; PR2 = 1;
  D1 = 0;  D2 = 0;
  
  #3 D1 = 1; D2 = 1;
  #1 D1 = 0; D2 = 0;
  #30 $finish;
 end
 
 always #3 CK1 = ~CK1;
 always #5 CK2 = ~CK2;
endmodule

4.8.2節までの回路

というわけで,8.2節までの回路(つまり,I/Oポートなし)を書いてみます。
module CHAPTER_8_2(CLOCK, RESET, SELECT_A, SELECT_B, LOAD_0, LOAD_1, LOAD_2, LOAD_3, ROM_DATA, ROM_ADDRESS);
 input CLOCK, RESET;
 input SELECT_A, SELECT_B, LOAD_0, LOAD_1, LOAD_2, LOAD_3;
 input [7:0] ROM_DATA;
 output [3:0] ROM_ADDRESS;
 
 reg Vcc = 1'b1;
 reg GND = 1'b0;
 wire [6:0] NOT_IN_USE;
 
 wire [3:0] REGISTER_IN;
 
 wire [3:0] REGISTER_A_OUT;
 wire [3:0] REGISTER_B_OUT;
 wire [3:0] REGISTER_C_OUT;
 wire [3:0] REGISTER_D_OUT;
 
 wire [3:0] ALU_IN_A;
 wire [3:0] ALU_IN_B;
 wire CARRY_OUT, C_FLAG;
 
 wire [3:0] OPERATION_CODE;
 wire [3:0] IMEEDIATE_DATA;
 
 assign ROM_ADDRESS = REGISTER_D_OUT;
 assign OPERATION_CODE = ROM_DATA[7:4];
 assign IMEEDIATE_DATA = ROM_DATA[3:0];
 assign ALU_IN_B = IMEEDIATE_DATA;
 
 LOGIC_74HC161 Register_A (RESET, CLOCK, 
  REGISTER_IN[0], REGISTER_IN[1], REGISTER_IN[2], REGISTER_IN[3], 
  GND, LOAD_0, GND, 
  REGISTER_A_OUT[0], REGISTER_A_OUT[1], REGISTER_A_OUT[2], REGISTER_A_OUT[3], 
  NOT_IN_USE[0]);
 
 LOGIC_74HC161 Register_B (RESET, CLOCK, 
  REGISTER_IN[0], REGISTER_IN[1], REGISTER_IN[2], REGISTER_IN[3], 
  GND, LOAD_1, GND, 
  REGISTER_B_OUT[0], REGISTER_B_OUT[1], REGISTER_B_OUT[2], REGISTER_B_OUT[3], 
  NOT_IN_USE[1]);
 
 LOGIC_74HC161 Register_C (RESET, CLOCK, 
  REGISTER_IN[0], REGISTER_IN[1], REGISTER_IN[2], REGISTER_IN[3], 
  GND, LOAD_2, GND, 
  REGISTER_C_OUT[0], REGISTER_C_OUT[1], REGISTER_C_OUT[2], REGISTER_C_OUT[3], 
  NOT_IN_USE[2]);
 
 LOGIC_74HC161 Register_D (RESET, CLOCK, 
  REGISTER_IN[0], REGISTER_IN[1], REGISTER_IN[2], REGISTER_IN[3], 
  Vcc, LOAD_3, Vcc, 
  REGISTER_D_OUT[0], REGISTER_D_OUT[1], REGISTER_D_OUT[2], REGISTER_D_OUT[3], 
  NOT_IN_USE[3]);
 
 LOGIC_74HC153 Register_Selector_0 (SELECT_A, SELECT_B, GND, GND, 
  REGISTER_A_OUT[0], REGISTER_B_OUT[0], REGISTER_C_OUT[0], GND, 
  REGISTER_A_OUT[1], REGISTER_B_OUT[1], REGISTER_C_OUT[1], GND,
  ALU_IN_A[0], ALU_IN_A[1]);
 
 LOGIC_74HC153 Register_Selector_1 (SELECT_A, SELECT_B, GND, GND, 
  REGISTER_A_OUT[2], REGISTER_B_OUT[2], REGISTER_C_OUT[2], GND, 
  REGISTER_A_OUT[3], REGISTER_B_OUT[3], REGISTER_C_OUT[3], GND, 
  ALU_IN_A[2], ALU_IN_A[3]);
 
 LOGIC_74HC283 ALU (GND, 
  ALU_IN_A[0], ALU_IN_A[1], ALU_IN_A[2], ALU_IN_A[3], 
  ALU_IN_B[0], ALU_IN_B[1], ALU_IN_B[2], ALU_IN_B[3], 
  REGISTER_IN[0], REGISTER_IN[1], REGISTER_IN[2], REGISTER_IN[3], 
  CARRY_OUT);
 
 LOGIC_74HC74 C_Flag (RESET, CARRY_OUT, CLOCK, Vcc, C_FLAG, NOT_IN_USE[4], 
  GND, GND, GND, GND, NOT_IN_USE[5], NOT_IN_USE[6]);
endmodule

だいぶCPUっぽくなってきましたね!

4.8.3節までの回路

どんどんいってみましょう!
8.3節までの回路(つまり,I/Oポートつき)を書いてみます。

module CHAPTER_8_3(CLOCK, RESET, SELECT_A, SELECT_B, LOAD_0, LOAD_1, LOAD_2, LOAD_3, ROM_DATA, ROM_ADDRESS);
 input CLOCK, RESET;
 input SELECT_A, SELECT_B, LOAD_0, LOAD_1, LOAD_2, LOAD_3;
 input [7:0] ROM_DATA;
 output [3:0] ROM_ADDRESS;
 
 reg Vcc = 1'b1;
 reg GND = 1'b0;
 wire [6:0] NOT_IN_USE;
 
 wire [3:0] REGISTER_IN;
 
 wire [3:0] REGISTER_A_OUT;
 wire [3:0] REGISTER_B_OUT;
 wire [3:0] REGISTER_C_OUT;
 wire [3:0] REGISTER_D_OUT;
 
 wire [3:0] ALU_IN_A;
 wire [3:0] ALU_IN_B;
 wire CARRY_OUT, C_FLAG;
 
 wire [3:0] OPERATION_CODE;
 wire [3:0] IMEEDIATE_DATA;
 
 assign ROM_ADDRESS = REGISTER_D_OUT;
 assign OPERATION_CODE = ROM_DATA[7:4];
 assign IMEEDIATE_DATA = ROM_DATA[3:0];
 assign ALU_IN_B = IMEEDIATE_DATA;
 assign OUTPUT = REGISTER_C_OUT;
 
 LOGIC_74HC161 Register_A (RESET, CLOCK, 
  REGISTER_IN[0], REGISTER_IN[1], REGISTER_IN[2], REGISTER_IN[3], 
  GND, LOAD_0, GND, 
  REGISTER_A_OUT[0], REGISTER_A_OUT[1], REGISTER_A_OUT[2], REGISTER_A_OUT[3], 
  NOT_IN_USE[0]);
  
 LOGIC_74HC161 Register_B (RESET, CLOCK, 
  REGISTER_IN[0], REGISTER_IN[1], REGISTER_IN[2], REGISTER_IN[3], 
  GND, LOAD_1, GND, 
  REGISTER_B_OUT[0], REGISTER_B_OUT[1], REGISTER_B_OUT[2], REGISTER_B_OUT[3], 
  NOT_IN_USE[1]);
  
 LOGIC_74HC161 Register_C (RESET, CLOCK, 
  REGISTER_IN[0], REGISTER_IN[1], REGISTER_IN[2], REGISTER_IN[3], 
  GND, LOAD_2, GND, 
  REGISTER_C_OUT[0], REGISTER_C_OUT[1], REGISTER_C_OUT[2], REGISTER_C_OUT[3], 
  NOT_IN_USE[2]);
  
 LOGIC_74HC161 Register_D (RESET, CLOCK, 
  REGISTER_IN[0], REGISTER_IN[1], REGISTER_IN[2], REGISTER_IN[3], 
  Vcc, LOAD_3, Vcc, 
  REGISTER_D_OUT[0], REGISTER_D_OUT[1], REGISTER_D_OUT[2], REGISTER_D_OUT[3], 
  NOT_IN_USE[3]);
 
 LOGIC_74HC153 Register_Selector_0 (SELECT_A, SELECT_B, GND, GND, 
  REGISTER_A_OUT[0], REGISTER_B_OUT[0], REGISTER_C_OUT[0], GND, 
  REGISTER_A_OUT[1], REGISTER_B_OUT[1], REGISTER_C_OUT[1], GND,
  ALU_IN_A[0], ALU_IN_A[1]);
  
 LOGIC_74HC153 Register_Selector_1 (SELECT_A, SELECT_B, GND, GND, 
  REGISTER_A_OUT[2], REGISTER_B_OUT[2], REGISTER_C_OUT[2], GND, 
  REGISTER_A_OUT[3], REGISTER_B_OUT[3], REGISTER_C_OUT[3], GND, 
  ALU_IN_A[2], ALU_IN_A[3]);
 
 LOGIC_74HC283 ALU (GND, 
  ALU_IN_A[0], ALU_IN_A[1], ALU_IN_A[2], ALU_IN_A[3], 
  ALU_IN_B[0], ALU_IN_B[1], ALU_IN_B[2], ALU_IN_B[3], 
  REGISTER_IN[0], REGISTER_IN[1], REGISTER_IN[2], REGISTER_IN[3], 
  CARRY_OUT);
 
 LOGIC_74HC74 C_Flag (RESET, CARRY_OUT, CLOCK, Vcc, C_FLAG, NOT_IN_USE[4], 
  GND, GND, GND, GND, NOT_IN_USE[5], NOT_IN_USE[6]);
endmodule

次回予告

ついにシミュレーション編最終回!
命令デコーダを完成させます!
そして,全てを結合させCPU全体の完成です!

乞うご期待!!!

Amazon.co.jp - 渡波 郁 「CPUの創りかた」 毎日コミュニケーションズ (2003)

2012年9月6日木曜日

週刊 TD4をFPGAで創る 第3号 「レジスタを創る」

週刊 TD4をFPGAで創る 第3号 「レジスタを創る」

第7章からです。
え,第6章? ちゃんと読んでおいてね!

1.74HC153

4チャネルのデータセレクタですね。
真理表はデータシートでも参照してくださいな。

module LOGIC_74HC153(A, B, G1, G2, C10, C11, C12, C13, C20, C21, C22, C23, Y1, Y2);
 input A, B, G1, G2, C10, C11, C12, C13, C20, C21, C22, C23;
 output Y1, Y2;
 
 wire [3:0] temp [0:1];
 
 assign temp[0][0] = C10 & (~B) & (~A) & (~G1);
 assign temp[0][1] = C11 & (~B) & A & (~G1);
 assign temp[0][2] = C12 & B & (~A) & (~G1);
 assign temp[0][3] = C13 & B & A & (~G1);
 
 assign temp[1][0] = C20 & (~B) & (~A) & (~G2);
 assign temp[1][1] = C21 & (~B) & A & (~G2);
 assign temp[1][2] = C22 & B & (~A) & (~G2);
 assign temp[1][3] = C23 & B & A & (~G2);
 
 assign Y1 = temp[0][0] | temp[0][1] | temp[0][2] | temp[0][3];
 assign Y2 = temp[1][0] | temp[1][1] | temp[1][2] | temp[1][3];
endmodule

テストベンチはこんな感じ?

module logic_74hc153_test;
 reg  A, B;
 reg  [1:0] G;
 reg  [3:0] C0;
 reg  [3:0] C1;
 wire [1:0] Y;
 
 LOGIC_74HC153 logic_74hc153(A, B, G[0], G[1], 
  C0[0], C0[1], C0[2], C0[3], C1[0], C1[1], C1[2], C1[3], Y[0], Y[1]);
 
 initial begin
  $dumpfile("logic_74hc153_test.vcd");
  $dumpvars(0, logic_74hc153_test);
  $monitor ("%t: (B, A) = (%b, %b), G = (%b, %b), C0 = %b%b%b%b, C1 = %b%b%b%b, Y = (%b, %b)",
   $time, B, A, G[0], G[1], C0[0], C0[1], C0[2], C0[3], C1[0], C1[1], C1[2], C1[3], Y[0], Y[1]);
   
   G = 3;
   B = 0; A = 0;
   C0 = 4'b1100;
   C1 = 4'b0101;
  #10 B = 0; A = 0;
  #10 B = 0; A = 1;
  #10 B = 1; A = 0;
  #10 B = 1; A = 1;
  #10 $finish;
 end
endmodule

2.74HC161

4ビットカウンタです。
こいつをレジスタとして使います。

module LOGIC_74HC161(CLR, CK, A, B, C, D, ENP, LOAD, ENT, QA, QB, QC, QD, CO);
 input CLR, CK, A, B, C, D, ENP, LOAD, ENT;
 output QA, QB, QC, QD, CO;
 
 wire [3:0] DATA = {D, C, B, A};
 reg  [3:0] FLIPFLOP;
 
 assign QA = FLIPFLOP[0];
 assign QB = FLIPFLOP[1];
 assign QC = FLIPFLOP[2];
 assign QD = FLIPFLOP[3];
 assign CO = ENT & QA & QB & QC & QD;
 
 initial begin
  FLIPFLOP <= 4'b0000;
 end
 
 always @(CLR or posedge CK) begin
  if(~CLR) begin
   FLIPFLOP <= 4'b0000;
  end
  else if(CK) begin
   if(~LOAD) begin
    FLIPFLOP <= DATA;
   end else if(ENP & ENT) begin
    if(FLIPFLOP == 4'b1111) begin
     FLIPFLOP <= 4'b0000;
    end else begin
     FLIPFLOP <= FLIPFLOP + 1;
    end
   end
  end
 end
endmodule

テストベンチはこんな感じ?

module logic_74hc161_test;
 reg  CLR, CK, ENP, LOAD, ENT;
 reg  [3:0] DATA;
 wire A, B, C, D, QA, QB, QC, QD, CO;
 wire [3:0] Q;
 
 assign A = DATA[0];
 assign B = DATA[1];
 assign C = DATA[2];
 assign D = DATA[3];
 assign Q = {QD, QC, QB, QA};
 
 LOGIC_74HC161 logic_74hc161(CLR, CK, A, B, C, D, ENP, LOAD, ENT, QA, QB, QC, QD, CO);
 
 initial begin
  $dumpfile("a.vcd");
  $dumpvars(0, logic_74hc161_test);
  $monitor ("%t: CK = %b, (CLR, LOAD, ENP, ENT) = (%b %b %b %b), DATA = %d(%b%b%b%b), Q = %d(%b%b%b%b), CO = %b",
   $time, CK, CLR, LOAD, ENP, ENT, DATA, D, C, B, A, Q, QD, QC, QB, QA, CO);
  
   CK = 0;
   CLR = 1; ENP = 1; LOAD = 1; ENT = 1;
   DATA = 0;
  #60 
  #10  CLR = 0;
  #10  CLR = 1;
  #60  DATA = 0;
  #10  DATA = 7; LOAD = 0;
  #10  DATA = 0; LOAD = 1;
  #10  DATA = 0;
  #40  ENP = 0;
  #30  ENP = 1;
  #210
  #10  $finish;
 end
 
 always #10 CK = ~CK;
endmodule

3.第7章の章末の回路

第7章の章末の回路を実装してみましょう!

module CHAPTER_7(CLOCK, RESET, SELECT_A, SELECT_B, LOAD_0, LOAD_1, LOAD_2, LOAD_3);
 input CLOCK, RESET;
 input SELECT_A, SELECT_B, LOAD_0, LOAD_1, LOAD_2, LOAD_3;
 
 reg GND = 1'b0;
 
 wire [3:0] REGISTER_IN;
 
 wire [3:0] REGISTER_A_OUT;
 wire [3:0] REGISTER_B_OUT;
 wire [3:0] REGISTER_C_OUT;
 wire [3:0] REGISTER_D_OUT;
 
 wire [3:0] NOT_IN_USE;
 
 LOGIC_74HC161 Register_A (RESET, CLOCK, 
  REGISTER_IN[0], REGISTER_IN[1], REGISTER_IN[2], REGISTER_IN[3], 
  GND, LOAD_0, GND, 
  REGISTER_A_OUT[0], REGISTER_A_OUT[1], REGISTER_A_OUT[2], REGISTER_A_OUT[3], 
  NOT_IN_USE[0]);
 
 LOGIC_74HC161 Register_B (RESET, CLOCK, 
  REGISTER_IN[0], REGISTER_IN[1], REGISTER_IN[2], REGISTER_IN[3], 
  GND, LOAD_0, GND, 
  REGISTER_B_OUT[0], REGISTER_B_OUT[1], REGISTER_B_OUT[2], REGISTER_B_OUT[3], 
  NOT_IN_USE[1]);
 
 LOGIC_74HC161 Register_C (RESET, CLOCK, 
  REGISTER_IN[0], REGISTER_IN[1], REGISTER_IN[2], REGISTER_IN[3], 
  GND, LOAD_0, GND, 
  REGISTER_C_OUT[0], REGISTER_C_OUT[1], REGISTER_C_OUT[2], REGISTER_C_OUT[3], 
  NOT_IN_USE[2]);
 
 LOGIC_74HC161 Register_D (RESET, CLOCK, 
  REGISTER_IN[0], REGISTER_IN[1], REGISTER_IN[2], REGISTER_IN[3], 
  GND, LOAD_0, GND, 
  REGISTER_D_OUT[0], REGISTER_D_OUT[1], REGISTER_D_OUT[2], REGISTER_D_OUT[3], 
  NOT_IN_USE[3]);
 
 LOGIC_74HC153 Register_Selector_0 (SELECT_A, SELECT_B, GND, GND, 
  REGISTER_A_OUT[0], REGISTER_B_OUT[0], REGISTER_C_OUT[0], REGISTER_D_OUT[0], 
  REGISTER_A_OUT[1], REGISTER_B_OUT[1], REGISTER_C_OUT[1], REGISTER_D_OUT[1],
  REGISTER_IN[0], REGISTER_IN[1]);
 
 LOGIC_74HC153 Register_Selector_1 (SELECT_A, SELECT_B, GND, GND, 
  REGISTER_A_OUT[2], REGISTER_B_OUT[2], REGISTER_C_OUT[2], REGISTER_D_OUT[2], 
  REGISTER_A_OUT[3], REGISTER_B_OUT[3], REGISTER_C_OUT[3], REGISTER_D_OUT[3], 
  REGISTER_IN[2], REGISTER_IN[3]);
endmodule

こいつは,outputがないのでテストのしようがないですねぇ。。。
まぁ,REGISTER_A_OUTとかを無理やり出力に引っ張ればいいんですけど。
面倒なんで,テストしたい人はやって見るといいと思います。

次回予告

次はいよいよALUだよ!
演算回路だよ!
CPUっぽいよ!

Amazon.co.jp - 渡波 郁 「CPUの創りかた」 毎日コミュニケーションズ (2003)

2012年8月30日木曜日

週刊 TD4をFPGAで創る 第2号 「ROMを創る」

週刊 TD4をFPGAで創る 第2号 「ROMを創る」

さぁ,実装するでございます。

第5章からです。
え,ROMって作れないんじゃなかったのって気がしますが,
実はこの時点では機械スイッチを使ってることをすっかり忘れていてまして。
74HC540と74HC154作っちゃたので載せます。

下の方にある「3.ROM」の部分までは読み飛ばしてOKですよ?

1.74HC540

バスバッファ8個入り!
Gの値によってはハイ・インピーダンスになるのですが,その場合は「1'hz」と書きます。

module LOGIC_74HC540(G1, G2, A1, A2, A3, A4, A5, A6, A7, A8, Y1, Y2, Y3, Y4, Y5, Y6, Y7, Y8);
	input	G1, G2;
	input	A1, A2, A3, A4, A5, A6, A7, A8;
	output	Y1, Y2, Y3, Y4, Y5, Y6, Y7, Y8;
	
	wire	G = G1 | G2;
	
	assign	Y1 = (G == 1'b0) ? ~A1 : 1'hz;
	assign	Y2 = (G == 1'b0) ? ~A2 : 1'hz;
	assign	Y3 = (G == 1'b0) ? ~A3 : 1'hz;
	assign	Y4 = (G == 1'b0) ? ~A4 : 1'hz;
	assign	Y5 = (G == 1'b0) ? ~A5 : 1'hz;
	assign	Y6 = (G == 1'b0) ? ~A6 : 1'hz;
	assign	Y7 = (G == 1'b0) ? ~A7 : 1'hz;
	assign	Y8 = (G == 1'b0) ? ~A8 : 1'hz;
endmodule

テストベンチはこんな感じ?

module logic_74hc540_test;
	reg	[1:0] G;
	reg	[7:0] A;
	wire	[7:0] Y;
	
	LOGIC_74HC540	logic_74hc540(G[0], G[1], 
		A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], 
		Y[0], Y[1], Y[2], Y[3], Y[4], Y[5], Y[6], Y[7]);
	
	initial begin
		$dumpfile("logic_74hc540_test.vcd");
		$dumpvars(0, logic_74hc540_test);
		$monitor ("%t: (G[1], G[0]) = (%b, %b), A = %b%b%b%b%b%b%b%b, Y = %b%b%b%b%b%b%b%b",
			$time, G[0], G[1], 
			A[7], A[6], A[5], A[4], A[3], A[2], A[1], A[0], 
			Y[7], Y[6], Y[5], Y[4], Y[3], Y[2], Y[1], Y[0]);
			

			A = 8'b00000000;	G = 0;
		#10	A = 8'b10101010;
		#10	A = 8'b11001100;
		#10	A = 8'b11110000;
		#10	A = 8'b00111100;
		#10	A = 8'b00000000;	G = 1;
		#10	A = 8'b10101010;	
		#10	A = 8'b11001100;
		#10	A = 8'b11110000;
		#10	A = 8'b00111100;
		#10	A = 8'b00000000;	G = 2;
		#10	A = 8'b10101010;	
		#10	A = 8'b11001100;
		#10	A = 8'b11110000;
		#10	A = 8'b00111100;
		#10	A = 8'b00000000;	G = 3;
		#10	A = 8'b10101010;	
		#10	A = 8'b11001100;
		#10	A = 8'b11110000;
		#10	A = 8'b00111100;
		#10	$finish;
	end
endmodule

2.74HC154

4ビットの2進数を16ビットの信号線にバラします。
ギョーカイヨーゴでは4-16デコーダって言います。

module LOGIC_74HC154(G1, G2, A, B, C, D, Y0, Y1, Y2, Y3, Y4, Y5, Y6, Y7, Y8, Y9, Y10, Y11, Y12, Y13, Y14, Y15);
	input	G1, G2, A, B, C, D;
	output	Y0, Y1, Y2, Y3, Y4, Y5, Y6, Y7, Y8, Y9, Y10, Y11, Y12, Y13, Y14, Y15;
	wire	G = (~G1) & (~G2);
	
	assign	Y0  = ~(G & ~A & ~B & ~C & ~D);
	assign	Y1  = ~(G &  A & ~B & ~C & ~D);
	assign	Y2  = ~(G & ~A &  B & ~C & ~D);
	assign	Y3  = ~(G &  A &  B & ~C & ~D);
	assign	Y4  = ~(G & ~A & ~B &  C & ~D);
	assign	Y5  = ~(G &  A & ~B &  C & ~D);
	assign	Y6  = ~(G & ~A &  B &  C & ~D);
	assign	Y7  = ~(G &  A &  B &  C & ~D);
	assign	Y8  = ~(G & ~A & ~B & ~C &  D);
	assign	Y9  = ~(G &  A & ~B & ~C &  D);
	assign	Y10 = ~(G & ~A &  B & ~C &  D);
	assign	Y11 = ~(G &  A &  B & ~C &  D);
	assign	Y12 = ~(G & ~A & ~B &  C &  D);
	assign	Y13 = ~(G &  A & ~B &  C &  D);
	assign	Y14 = ~(G & ~A &  B &  C &  D);
	assign	Y15 = ~(G &  A &  B &  C &  D);
endmodule

テストベンチはこんな感じ?

module logic_74hc154_test;
	reg		[1:0] G;
	reg		[3:0] A;
	wire	[15:0] Y;
	
	LOGIC_74HC154	logic_74hc154(G[0], G[1], A[0], A[1], A[2], A[3], 
		Y[0], Y[1], Y[2], Y[3], Y[4], Y[5], Y[6], Y[7], 
		Y[8], Y[9], Y[10], Y[11], Y[12], Y[13], Y[14], Y[15]);
	
	initial begin
		$dumpfile("logic_74hc154_test.vcd");
		$dumpvars(0, logic_74hc154_test);
		$monitor ("%t: G = %b%b, A = %b%b%b%b, Y = %b%b%b%b%b%b%b%b%b%b%b%b%b%b%b%b",
			$time, G[1], G[0], A[3], A[2], A[1], A[0], 
			Y[15], Y[14], Y[13], Y[12], Y[11], Y[10], Y[9], Y[8], 
			Y[7], Y[6], Y[5], Y[4], Y[3], Y[2], Y[1], Y[0]);
			
			A = 4'b0000;	G = 0;
		#10	A = 4'b0001;
		#10	A = 4'b0011;
		#10	A = 4'b0100;
		#10	A = 4'b0101;
		#10	A = 4'b0110;
		#10	A = 4'b0111;
		#10	A = 4'b1000;
		#10	A = 4'b1001;
		#10	A = 4'b1011;
		#10	A = 4'b1100;
		#10	A = 4'b1101;
		#10	A = 4'b1110;
		#10	A = 4'b1111;
		#10	A = 4'b0000;	G = 1;
		#10	A = 4'b0001;
		#10	A = 4'b0011;
		#10	A = 4'b0100;
		#10	A = 4'b0101;
		#10	A = 4'b0110;
		#10	A = 4'b0111;
		#10	A = 4'b1000;
		#10	A = 4'b1001;
		#10	A = 4'b1011;
		#10	A = 4'b1100;
		#10	A = 4'b1101;
		#10	A = 4'b1110;
		#10	A = 4'b1111;
		#10	A = 4'b0000;	G = 2;
		#10	A = 4'b0001;
		#10	A = 4'b0011;
		#10	A = 4'b0100;
		#10	A = 4'b0101;
		#10	A = 4'b0110;
		#10	A = 4'b0111;
		#10	A = 4'b1000;
		#10	A = 4'b1001;
		#10	A = 4'b1011;
		#10	A = 4'b1100;
		#10	A = 4'b1101;
		#10	A = 4'b1110;
		#10	A = 4'b1111;
		#10	A = 4'b0000;	G = 3;
		#10	A = 4'b0001;
		#10	A = 4'b0011;
		#10	A = 4'b0100;
		#10	A = 4'b0101;
		#10	A = 4'b0110;
		#10	A = 4'b0111;
		#10	A = 4'b1000;
		#10	A = 4'b1001;
		#10	A = 4'b1011;
		#10	A = 4'b1100;
		#10	A = 4'b1101;
		#10	A = 4'b1110;
		#10	A = 4'b1111;
		#10	$finish;
	end
ここからは本題です。

3.ROM

さて,ここでROMモジュールを作ろうとして頓挫したわけです。

で,結局Verilog様の偉大なる力に頼ることにします。
今だけはVerilogのことを偉大なる指導者と読んでもバチは当たらない!

こんな感じになりました。
実際に本に乗っているコードをのっけてあります。
コメントアウトしたりしながら楽しんでね!

module ROM_16WORD(ROM_ADDRESS, ROM_DATA);
	input	[3:0] ROM_ADDRESS;
	output	[7:0] ROM_DATA;
	
	reg	[7:0] ROM [0:15];
	
	assign	ROM_DATA = ROM[ROM_ADDRESS];
	
	initial begin
		// BLANK
		/*
		ROM[0]  <= 8'b00000000;	// NOP
		ROM[1]  <= 8'b00000000;	// NOP
		ROM[2]  <= 8'b00000000;	// NOP
		ROM[3]  <= 8'b00000000;	// NOP
		ROM[4]  <= 8'b00000000;	// NOP
		ROM[5]  <= 8'b00000000;	// NOP
		ROM[6]  <= 8'b00000000;	// NOP
		ROM[7]  <= 8'b00000000;	// NOP
		ROM[8]  <= 8'b00000000;	// NOP
		ROM[9]  <= 8'b00000000;	// NOP
		ROM[10] <= 8'b00000000;	// NOP
		ROM[11] <= 8'b00000000;	// NOP
		ROM[12] <= 8'b00000000;	// NOP
		ROM[13] <= 8'b00000000;	// NOP
		ROM[14] <= 8'b00000000;	// NOP
		ROM[15] <= 8'b00000000;	// NOP
		*/
		
		// LED NIGHT RIDER
		/*
		ROM[0]  <= 8'b10110011;	// OUT 0011
		ROM[1]  <= 8'b10110110;	// OUT 0110
		ROM[2]  <= 8'b10111100;	// OUT 1100
		ROM[3]  <= 8'b10111000;	// OUT 1000
		ROM[4]  <= 8'b10111000;	// OUT 1000
		ROM[5]  <= 8'b10111100;	// OUT 1100
		ROM[6]  <= 8'b10110110;	// OUT 0110
		ROM[7]  <= 8'b10110011;	// OUT 0011
		ROM[8]  <= 8'b10110001;	// OUT 0001
		ROM[9]  <= 8'b11110000;	// JMP 0000
		ROM[10] <= 8'b00000000;	// NOP
		ROM[11] <= 8'b00000000;	// NOP
		ROM[12] <= 8'b00000000;	// NOP
		ROM[13] <= 8'b00000000;	// NOP
		ROM[14] <= 8'b00000000;	// NOP
		ROM[15] <= 8'b00000000;	// NOP
		*/
		
		// RAMEN TIMER (For 1Hz CLOCK)
		ROM[0]  <= 8'b10110111;	// OUT 0111
		ROM[1]  <= 8'b00000001;	// ADD A, 0001
		ROM[2]  <= 8'b11100001;	// JNC 0001
		ROM[3]  <= 8'b00000001;	// ADD A, 0001
		ROM[4]  <= 8'b11100011;	// JNC 0011
		ROM[5]  <= 8'b10110110;	// OUT 0110
		ROM[6]  <= 8'b00000001;	// ADD A, 0001
		ROM[7]  <= 8'b11100110;	// JNC 0110
		ROM[8]  <= 8'b00000001;	// ADD A, 0001
		ROM[9]  <= 8'b11101000;	// JNC 1000
		ROM[10] <= 8'b10110000;	// OUT 0000
		ROM[11] <= 8'b10110100;	// OUT 0100
		ROM[12] <= 8'b00000001;	// ADD A, 0001
		ROM[13] <= 8'b11101010;	// JNC 1010
		ROM[14] <= 8'b10111000;	// OUT 1000
		ROM[15] <= 8'b11111111;	// JMP 1111
	end
endmodule

コメントで命令をNOPって書いてますけど,実際には「8'b00000000」は「ADD A, 0」だったりします。
まぁ,要するにNOPなんですけどね。

テストベンチはこんな感じ?

module test_rom;
	reg	[3:0] ROM_ADDRESS;
	wire	[7:0] ROM_DATA;
	
	ROM_16WORD	ROM(ROM_ADDRESS, ROM_DATA);
	
	initial begin
		$dumpfile("test_rom.vcd");
		$dumpvars(0, test_rom);
		$monitor ("%t: ROM_ADDRESS = %b%b%b%b, ROM_DATA = %b%b%b%b%b%b%b%b", $time,
			ROM_ADDRESS[3], ROM_ADDRESS[2], ROM_ADDRESS[1], ROM_ADDRESS[0],
			ROM_DATA[7], ROM_DATA[6], ROM_DATA[5], ROM_DATA[4], 
			ROM_DATA[3], ROM_DATA[2], ROM_DATA[1], ROM_DATA[0]
		);
		
			ROM_ADDRESS = 4'b0000;
		#10	ROM_ADDRESS = 4'b0001;
		#10	ROM_ADDRESS = 4'b0010;
		#10	ROM_ADDRESS = 4'b0011;
		#10	ROM_ADDRESS = 4'b0100;
		#10	ROM_ADDRESS = 4'b0101;
		#10	ROM_ADDRESS = 4'b0110;
		#10	ROM_ADDRESS = 4'b0111;
		#10	ROM_ADDRESS = 4'b1000;
		#10	ROM_ADDRESS = 4'b1001;
		#10	ROM_ADDRESS = 4'b1010;
		#10	ROM_ADDRESS = 4'b1011;
		#10	ROM_ADDRESS = 4'b1100;
		#10	ROM_ADDRESS = 4'b1101;
		#10	ROM_ADDRESS = 4'b1110;
		#10	ROM_ADDRESS = 4'b1111;
		#10	$finish;
	end
endmodule


次回予告

次は何だっけ?

えーと,レジスタファイルの話っぽいよ!

Amazon.co.jp - 渡波 郁 「CPUの創りかた」 毎日コミュニケーションズ (2003)

2012年8月23日木曜日

週刊 TD4をFPGAで創る 創刊号

週刊 TD4をFPGAで創る 創刊号

創刊号は特に何にもつかずに0円。
というかこれからもずっと0円の予定。

1.TD4

TD4って知ってますか?

この世の中には日本語に限定しても数多の電子工作本が出版されているのですが,
その中でも異彩を放っているのが「CPUの創りかた」っていう本でございます。

Amazon.co.jp - 渡波 郁 「CPUの創りかた」 毎日コミュニケーションズ (2003)

この本が市井でどんな評価を受けているかは上のAmazonレビューなんかをご参照してくださいな。
実際,書店で現物を見られると「感動モノ」だと思いますよ?

TD4っていうのは渡波(2003)の中で実際に制作されている4bit CPUでありまして,
なんと10個のLogic ICで構成されているという驚きのプロセッサでございます。

ICといっても別にマイコン持ってくるとかそんなトンチのきいた話をしているわけではなく,
74 Logicシリーズ(Hi-speed CMOS)だけで構成されちゃってたりします。

いわゆるTTLで5V動作するのでハンダゴテをニギニギしながら作業しても作れちゃいますし,
実際に渡波(2003)の中で制作されています。

というか,実装部分の話もかなり載っていて,電子工作初心者に向けたいくらいです。

ちなみに,TD4の名前の意味は……。本を読んでみるとわかります(笑)

そんでもって,次のようなISA(命令セットアーキテクチャ)を持っています。
MOV A, Im
MOV B, Im
MOV A, B
MOV B, A
ADD A, Im
ADD B, Im
IN A
IN B
OUT Im
OUT B
JMP Im
JNC Im

2.FPGAで作る

いやね,はじめはディスクリートで作ろうと思ったんですよ?
でもね,さすがに大変じゃないですか。
本にも書いてありますが,配線量が半端じゃ無いんですよ。とくにROM。

その点HDLって!!
便利だし!
拡張も簡単だし!

実際に物理的に作ろうと思えばFPGAに実装しちゃえばいいわけですしね!

といわけで,まずはVerilog HDLで書いてシミュレーションします。
んで,うまく行ったらネットリスト書いてFPGA上に論理合成の結果を書き込んで完成です!

3.必要なもの

1.本
買いましょう!
絶対に買いましょう!
大事なことなので二度言いました。

2.Verilog HDLの開発環境
Icarus Verilogとか使えばいいんじゃね?
gtkwaveがあれば見やすいかもしれないけど,個人的にはずっとコンソールからvvpしてます。
詳細はググレカス。

3.FPGAボード&開発環境
実際にあれば現物が見れます。
必須ってわけではないけどね。

個人的には研究室に転がってるお借りしたXilinx ML501を使う予定です。

え,なんで予定かって?
この記事書いてる時点じゃまだ実装してないんですよ。

4.元気!ヤル気!シャカリキ!
これ大事!

4.お約束

あのー。
Verilogとかちょっち齧ったことある人は知ってると思うんですけど,別に中で74Logicを再現する必要はないんですよね。

でも,今回はできるだけ再現します。
しかも,assignとか使いまくって再現します。
本来はお行儀が悪いから,ちゃんとRTLで再現するんですけどね。

ただし,ROMとクロックジェネレータは再現できないので,Verilog様の偉大なる力をお借りしちゃいます。
(ROMって再現できないんですかね?メカニカルスイッチはだめかなぁ?)

以上お約束でした。
(意味がわからなかった人は,読み飛ばしちゃえ!)

次回予告

いよいよ実装するよ!