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)

0 件のコメント:

コメントを投稿