週刊 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)
0 件のコメント:
コメントを投稿