FPGAでTD4を作成する1(ROM作成)

「CPUの創りかた」という本に載っている4bitCPU「TD4」をFPGAで作成します。
使用するFPGAボードはXilinxのBasys2で、言語はVHDLです。
各パーツごとに作成して最後に全体を統合します。今回はROMを作成します。 ====

TD4の作成について

 

【開発環境】
使用ボード:Basys2 (Xilinx)
ツール:ISE Project Navigator 14.7
シミュレーション:Isim
言語:VHDL

TD4の全体構成をブロック図で表したのが下図です。
今回はFPGAで作りますが、構成は「CPUの創りかた」に合わせていきます。
ちなみに矢印の色が青とオレンジの2色ありますが、色の違いに特に意味はなく、単に見やすくしただけです。


f:id:hirokun1735:20190103213506j:plain

 

ROMの機能

TD4のROMは8bit×16で16byteあります。
「CPUの創りかた」では16個のスライドスイッチを使っています。
これを全て配線するのはかなり骨が折れますが、FPGAならコードを書くだけで実現できます。


TD4で用いるプログラムは各8bitです。
ROMは16byteなので全部で16ステップのプログラムを格納できます。
プログラムカウンタからプログラムが格納されているアドレスを指定する4bitの信号が送られ、対応するプログラム8bitを出力します。


8bitのプログラムのうち上位4bitは命令の機能である「オペレーションコード」であり、デコーダに出力されます。
下位4bitは命令に組み込まれたデータであり、「イミディエイトデータ」と呼ばれます。こちらはALUに出力されます。

ROMのコード

以下はVHDLで書いたROMのコードです。
TD4のプログラムは以下のコードに直接書き込みます。
"0000"から"1111"の16byteありますが、プログラムコードを"0000"から順番に書き込みます。


ちなみに以下に載せたコードは「CPUの創りかた」の295ページにあるサンプルプログラム1「LEDちかちか」のコードを書き込んでいます。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity rom_16byte is
    Port ( ADDRESS : in  STD_LOGIC_VECTOR(3 downto 0);
           ROM_DATA : out  STD_LOGIC_VECTOR(3 downto 0);
			  OP_CODE : out  STD_LOGIC_VECTOR(3 downto 0));
end rom_16byte;

architecture RTL of rom_16byte is

	signal data : STD_LOGIC_VECTOR(7 downto 0);

begin

	ROM_DATA <= data(3 downto 0);
	OP_CODE <= data(7 downto 4);
	
	process (ADDRESS) begin
		case ADDRESS is
		
			when "0000" => data <= "10110011";
			when "0001" => data <= "10110110";
			when "0010" => data <= "10111100";
			when "0011" => data <= "10111000";
			when "0100" => data <= "10111000";
			when "0101" => data <= "10111100";
			when "0110" => data <= "10110110";
			when "0111" => data <= "10110011";
			when "1000" => data <= "10110001";
			when "1001" => data <= "11110000";
			when "1010" => data <= "00000000";
			when "1011" => data <= "00000000";
			when "1100" => data <= "00000000";
			when "1101" => data <= "00000000";
			when "1110" => data <= "00000000";
			when "1111" => data <= "00000000";
			when others => data <= "00000000";
		
		end case;
	end process;
	
end RTL;

ROMのシミュレーション

上で書いたROMのコードをシミュレーションするためのテストベンチのコードが以下です。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
 
ENTITY rom_16byte_tb IS
END rom_16byte_tb;
 
ARCHITECTURE behavior OF rom_16byte_tb IS 
 
    -- Component Declaration for the Unit Under Test (UUT)
 
    COMPONENT rom_16byte
    PORT ( ADDRESS : in  STD_LOGIC_VECTOR(3 downto 0);
           ROM_DATA : out  STD_LOGIC_VECTOR(3 downto 0);
			  OP_CODE : out  STD_LOGIC_VECTOR(3 downto 0)
        );
    END COMPONENT;
    
   --Inputs
   signal ADDRESS : std_logic_vector(3 downto 0);

 	--Outputs
   signal ROM_DATA : std_logic_vector(3 downto 0);
	signal OP_CODE : std_logic_vector(3 downto 0);
 
BEGIN
 
	-- Instantiate the Unit Under Test (UUT)
   uut: rom_16byte PORT MAP (
          ADDRESS => ADDRESS,
          ROM_DATA => ROM_DATA,
			 OP_CODE => OP_CODE
        );

   -- Clock process definitions
   process begin
		Address <= "0000";
		wait for 100 ns;
		Address <= "0001";
		wait for 100 ns;
		Address <= "0010";
		wait for 100 ns;
		Address <= "0011";
		wait for 100 ns;
		Address <= "0100";
		wait for 100 ns;
		Address <= "0101";
		wait for 100 ns;
		Address <= "0110";
		wait for 100 ns;
		Address <= "0111";
		wait for 100 ns;
		Address <= "1000";
		wait for 100 ns;
		Address <= "1001";
		wait for 100 ns;
		Address <= "1010";
		wait for 100 ns;
		Address <= "1011";
		wait for 100 ns;
		Address <= "1100";
		wait for 100 ns;
		Address <= "1101";
		wait for 100 ns;
		Address <= "1110";
		wait for 100 ns;
		Address <= "1111";
		wait for 100 ns;
		
		wait;
		
   end process;

END;


アドレスを指定する入力に"0000"から"1111"を順番に入れています。
シミュレーション結果は以下のようになりました。


f:id:hirokun1735:20190103124207j:plain


addressの4bitを順番に変えていくと、そのアドレスに応じた8bitのdataが出力されます。

まとめ

4bitCPU「TD4」のROMを作成しました。
プログラムカウンタからアドレスを表す4bitのコードが入力され、対応するアドレスに格納されている8bitのデータを出力します。


次の記事はこちらです。

 

www.hiro-hard.info