VHDL 시뮬레이션 툴\을 활용한 RC8100 에 대한 VHDL 코드 작성/검증 자료출처 : 유니텔 MicroProcessor의 구조를 간략화한 RISC 형태의 RC8001의 전반적인 시스템 구성과 사양에 대하여 설명하였다. 이어서는 RC8001 디자인에 대해 설명할 예정이다. 또한 각 블럭에 대한 VHDL 소스 및 이를 검증할 수 있도록 스티 뮬러스(Stimulus)와 시뮬레이션 결과에 대해 알아보도록 하겠다. 컴퓨터 아키텍쳐(Computer Architecture)에 대한 지식이 있는 사용자의 경우 는 전체적인 시스템의 구조와 흐름은 파악하였을 것이라고 판단되며, 아직 전체적인 윤곽을 확인하지 못한 사용자라 할지라도 지금부터 설명하는 각각 의 블럭들의 설명을 읽고나면 RC8001의 구조와 처리 내용을 이해할 수 있을 것이다. 1. RC8001 VHDL 소스의 설계 레지스터(Register) 전송 레벨을 구성하는 블럭들을 조합논리 회로 요소와 순서논리 회로로 분류하면 표 1과 같다. 표 1. 하드웨어 블럭에 대한 분류 조합 논리 회로 요소 1. 입력이 5 Bit인 2×1 Multiplexer 2. 입력이 8 Bit인 2×1 Multiplexer 3. 5 Bit의 입력 데이터에 대하여 1을 증가하는 회로 4. 5가지의 기능을 갖는 8Bit ALU 5. Address가 5 Bit이고, Data Bus가 8 Bit인 ROM 6. Address가 5 Bit이고, Data Bus가 8 Bit인 RAM 순서 논리 회로 요소 a. Enable 신호 및 초기화를 갖는 1 Bit AF b. Enable 신호 및 초기화 신호를 갖는 5 Bit Register c. Enable 신호와 초기화 신호를 갖는 8 Bit Register d. 출력이 5 Bit인 파형 발생기 e. 여러 가지 제어신호를 명령어와 수행 5 단계에 따라 생성하는 FSM 레지스터 전송 레벨의 구성을 설명한 그림 1과 같이 12가지 요소를 Behavioral Modeling 방법에 의하여 각각 표현하고, 이들의 연결 관계를 주의하면서 Structural Modeling 방법에 의하여 표현하면 VHDL 설계를 마치게 된다. (1) VHDL 모델링 기법 들어가기에 앞서 VHDL 모델링(Source Code Description) 기법에 대하여 간단히 설명하겠다. VHDL 모델링 방법에는 아래와 같이 4가지 방법이 있으며, 꼭 특정한 한가지 방법만으로 VHDL을 기술해야 하는 것이 아니라 이해하기 쉽고 익숙한 방법 을 사용하며, 때로는 여러 가지 기술방법을 혼용하여 사용하는 것이 일반적 이다. 1) 동작적 기술(Behavioral Description) . 기능적 또는 알고리즘적 표현을 주로 사용한다 . 고급언어를 사용한 프로그램 작성과 유사하다 . 문서화를 위해서 가장 우수한 기술방법이다. . VHDL의 순차문을 사용한다. 2) 자료처리 흐름 기술(Dataflow Description) . 동작적보다 한 단계 낮은 수준의 기술방법이다. . 부울함수, RTL, 또는 연산자(AND, OR) 등의 표현을 이용한다. . VHDL의 병행문을 사용한다(회로의 각 구성요소의 작동 표현). 3) 구조적 기술(Structural Description) . 가장 하드웨어적 표현에 가깝다 . 구성요소 및 연결상태를 가장 잘 표현한다 . 계층적 구조의 디자인에 이용된다. 4) 혼합적 기술(Mixed Description) . 앞의 세 가지 기술을 혼합적으로 사용한다. 다음은 위에서 설명한 VHDL Modeling 기법을 이용 전가산기를 디자인한 예이다. VHDL 코드 작성에 앞서 복습한다는 생각으로 다음의 예제를 검토하 기 바란다(지난 호에서도 언급했지만 본 글은 VHDL을 활용하는 방법을 설명하는 글로 VHDL에 대한 기본지식이 있다는 전제에서 VHDL 구조 및 기본 문법 등의 설명은 생략한다). (2) 반가산기의 엔티티 entity Half_Adder is port ( A, B : in bit; Sum, Carry : out bit); end Half_Adder; (3) 반가산기의 동작적 기술 architecture Beh_Des of Half_A.... begin process ( A, B ) begin if ( A = B ) then sum <= '1' after 2 ns; else sum <= '1' after 2 ns; end if; if ( A = '1') and ( B = '1') then carry <= '1' after 2 ns; else carry <= '1' after 2 ns; end if; end process; end Beh_Des; (4) 반가산기의 자료흐름 기술 architecture Dataflow_Des .... begin sum <= A xor B after 2 ns; Carry <= A and B after 2 ns; end Dataflow_Des; (5) 전가산기의 엔티티 entity Full_Adder is port (X, Y, C_in : in bit; S_out, C_out : out bit ); end Full_Adder; (6) 전가산기의 구조적 기술 -. 이미 디자인된 OR2와 Half_Adder를 Component로 지정하여 사용한다. architecture Structural_Des of Full_Adder is signal t_s, t_c1, t_c2 : bit; -- declaration of internal signals component OR2 -- declaration of local components port (I1, I2 : in bit; O : out bit); end component; component Half_Adder port (A, B : in bit; Sum, Carry : out bit); end component; begin -- component instantiation statements HA1 : Half_Adder port map (X, Y, t_s, t_c1); HA2 : Half_Adder port map (t_s, C_in, S_out, t_c2); ORG : OR2 port map (t_c1, t_c2, C_out); end Structural_Des; 앞에서 보는 바와 같이 디지털 회로설계에 대한 기본 지식이 있다면 자료 흐름 기술을 보는 것이 전체를 파악하는데 편리할 것이다. 그렇지만 사전 지식이 없는 사용자나 전혀 회로에 대한 지식이 없다면 동작적 기술이 처리 내용을 이해하는데 편리할 것이다. 이제 RC8001로 돌아와 기본적인 블럭에 대하여 코딩해보자. 먼저 가장 간단하고 많이 이용되는 입력자료가 5 Bit인 2×1 Multiplexer의 설계를 해보도록 하자. 2. Multiplexer RC8001에서 Multiplexer의 역할은 PC 레지스터의 값을 1 증가할 것인가 또는 Jump의 경우와 같이 IR에서 지정하는 값으로 할 것인가를 선택하기 위하여 사용되는 블럭이다. 요약하면 Select Signal에 따라 입력된 값 중에서 하나를 선택하여 출력해주는 디자인이다. 설계사양은 입력 Port가 addr_m, r_addr_m, mux5_sel이고 출력 Port가 addr_me이다. 입력값이 Bus Type이므로 Data Type은 STD_LOGIC_VECTOR를 이용하며 Size는 (4 downto 0)로 선언한다. 입력 Signal이 '1'이면 INC에 서 제공된 값(addr_m)을 이용하고 입력 Signal이 '0'이면 IR Reg에서 제공된 값(r_addr_m)을 출력 Port addr_me로 출력한다. 만일 앞의 두 가지 경우 이외의 사건이 발생하면 출력값은 '00000'으로 한다. < 5Bit 2×1 Multiplexer > --*************************************************************** ENTITY mux5 IS PORT ( addr_m : IN STD_LOGIC_VECTOR(4 DOWNTO 0); r_addr_m : IN STD_LOGIC_VECTOR(4 DOWNTO 0); mux5_sel : IN STD_LOGIC; addr_me : OUT STD_LOGIC_VECTOR(4 DOWNTO 0)); END mux5; --*************************************************************** ARCHITECTURE mux5_a OF mux5 IS BEGIN PROCESS(addr_m, r_addr_m, mux5_sel) BEGIN IF mux5_sel = '1' THEN addr_me <= addr_m; ELSIF mux5_sel = '0' THEN addr_me <= r_addr_m; ELSE addr_me <= "00000"; END IF; END PROCESS; ----------------------------------------------------------------- END mux5_a; --*************************************************************** < 5Bit 2×1 Multiplexer Source > addev[ addr_m ]{["00001" @ 10 ns],["00010" @ 20 ns], ["00011" @ 30 ns], ["00100" @ 40 ns],["00101" @ 50 ns], ["00110" @ 60 ns], ["00111" @ 70 ns],["01000" @ 80 ns], ["01001" @ 90 ns], ["01010" @100 ns] }; addev[r_addr_m]{["11110" @10 ns ], ["11101" @ 20 ns], ["11100" @ 30 ns], ["11011" @40 ns ], ["11010" @ 50 ns], ["11001" @ 60 ns], ["11000" @70 ns ], ["10111" @ 80 ns], ["10110" @ 90 ns], ["10101" @100 ns] }; addpat [mux5_sel]{[ 0 @ 15 ns ], [ 1 @ 20 ns ] }; view addr_m, r_addr_m, mux5_sel, addr_me; 입력이 8 비트인 2×1 Multiplexer는 MEM 레지스터의 값을 ALU 레지스터의 출력으로 할 것인가 또는 RAM에서 읽은 값으로 할 것인가를 선택하기 위하 여 요구되는 블럭이다. 따라서 앞에서 기술한 코드를 이용, 입력과 출력 데이터에 대한 비트수만 을 8 비트로 변경하면 된다. 기본적인 구조는 5 비트 Multiplexer와 동일 하므로 이와 관련된 소스는 생략한다. 3. Adder 입력을 1 증가하는 INC 회로는 프로그램 메모리의 위치를 가리키는 PC 레지 스터의 값을 명령어에 대한 Fetch 동작 후 1의 증가가 요구되도록 하기 위한 블럭이다. 1을 증가시키는 알고리즘은 다음에서 보는 바와 같이 산술 적으로 처리하지 않고 논리연산에 의한 방법을 이용한다. 연산의 예> 입 력(PC_ADDR) : "00010101" = 21 Carry : "00000011" 출 력(INC_ADDR) : "00010110" = 22 < INC Source> --************************************************************* ENTITY inc IS PORT ( pc_addr : IN STD_LOGIC_VECTOR(4 DOWNTO 0); inc_addr : OUT STD_LOGIC_VECTOR(4 DOWNTO 0)); END inc; --************************************************************* ARCHITECTURE inc_a OF inc IS SIGNAL carry : STD_LOGIC_VECTOR (4 DOWNTO 0); BEGIN carry (0) <= '1'; carry (1) <= pc_addr (0) AND carry (0); carry (2) <= pc_addr (1) AND carry (1); carry (3) <= pc_addr (2) AND carry (2); carry (4) <= pc_addr (3) AND carry (3); inc_addr <= pc_addr XOR carry; END inc_a; --************************************************************* < INC Stimulus > addev[pc_addr] {["00001" @ 10 ns],["00010" @ 20 ns],["00011"@30 ns], ["01000" @ 40 ns],["01110" @ 50 ns],["11111"@60 ns], ["11011" @ 70 ns] }; view pc_addr, inc_addr; 8 비트 Adder는 CPU의 ALU에서의 연산을 처리하는데 이용된다. 여기서는 일반적인 산술연산을 이용하지 않고 INC 블럭에서 설명한 각각의 비트를 논리연산하여 그 결과를 추출하는 방법을 취하였다. < 8Bit Adder Source > --******************************************************************* ENTITY add8 IS PORT ( in1 : IN STD_LOGIC_VECTOR (7 DOWNTO 0); in2 : IN STD_LOGIC_VECTOR (7 DOWNTO 0); out1 : OUT STD_LOGIC_VECTOR (7 DOWNTO 0)); END add8; --******************************************************************* ARCHITECTURE add8_a OF add8 IS --------------------------------------------------------------------- SIGNAL carry : STD_LOGIC_VECTOR (7 DOWNTO 0); --------------------------------------------------------------------- BEGIN carry(0) <= '0'; carry(1)<=(in1(0)and in2(0))or(in1(0)and carry(0))or(in2(0)and carry(0)); carry(2)<=(in1(1)and in2(1))or(in1(1)and carry(1))or(in2(1)and carry(1)); carry(3)<=(in1(2)and in2(2))or(in1(2)and carry(2))or(in2(2)and carry(2)); carry(4)<=(in1(3)and in2(3))or(in1(3)and carry(3))or(in2(3)and carry(3)); carry(5)<=(in1(4)and in2(4))or(in1(4)and carry(4))or(in2(4)and carry(4)); carry(6)<=(in1(5)and in2(5))or(in1(5)and carry(5))or(in2(5)and carry(5)); carry(7)<=(in1(6)and in2(6))or(in1(6)and carry(6))or(in2(6)and carry(6)); out1 <= in1 xor in2 xor carry; END add8_a; --******************************************************************* < 8 Bit Adder Stimulus > addpat [ in1 ] { [ "00000000" @ 15 ns ], [ "00001000" @ 20 ns ], [ "00001111" @ 30 ns ], [ "00110011" @ 40 ns ] }; addpat [ in2 ] { [ "00001010" @ 25 ns ], [ "00000101" @ 25 ns ], [ "01010101" @ 25 ns ], [ "00011000" @ 25 ns ] }; view in1, in2, out1; 4. ALU 5가지 기능을 수행하는 8 비트 ALU는 EXE 단계에서 요구되는 ALU의 기능 중 Add 연산의 경우는 ALU 레지스터에 저장되는 값이 0인가의 여부를 조사하여 0이면 '1'을, 그렇지 않으면 '0'을 출력하는 ZERO_FLAG 출력을 생성한다. < 8 Bit ALU Source > --****************************************************************** ENTITY alu IS PORT ( opcode : IN STD_LOGIC_VECTOR (2 DOWNTO 0); op_1 : IN STD_LOGIC_VECTOR (7 DOWNTO 0); op_2 : IN STD_LOGIC_VECTOR (7 DOWNTO 0); zero_a : OUT STD_LOGIC; alu_o : OUT STD_LOGIC_VECTOR (7 DOWNTO 0)); END alu; --****************************************************************** ARCHITECTURE alu_a OF alu IS -------------------------------------------------------------------- COMPONENT add8 PORT ( in1 : IN STD_LOGIC_VECTOR (7 DOWNTO 0); in2 : IN STD_LOGIC_VECTOR (7 DOWNTO 0); out1 : OUT STD_LOGIC_VECTOR (7 DOWNTO 0)); END COMPONENT; -------------------------------------------------------------------- SIGNAL temp_alu : STD_LOGIC_VECTOR (7 DOWNTO 0); SIGNAL add_result : STD_LOGIC_VECTOR (7 DOWNTO 0); -------------------------------------------------------------------- BEGIN -------------------------------------------------------------------- PROCESS(temp_alu) BEGIN IF temp_alu = "00000000" THEN zero_a <= '1'; ELSE zero_a <= '0'; END IF; END PROCESS; -------------------------------------------------------------------- ADD0 : ADD8 port map (op_1, op_2, add_result); -------------------------------------------------------------------- PROCESS(opcode,op_2,op_1) BEGIN CASE opcode IS WHEN "010" => temp_alu <= add_result; -- add WHEN "011" => temp_alu <= op_2 AND op_1; -- and WHEN "100" => temp_alu <= op_2 XOR op_1; -- xor WHEN "101" => temp_alu <= op_2; -- bypass for load WHEN "110" => temp_alu <= op_1; -- bypass for store WHEN OTHERS => temp_alu <= "00000000"; END CASE; END PROCESS; -------------------------------------------------------------------- alu_o <= temp_alu; -------------------------------------------------------------------- END alu_a; --******************************************************************* OP 코드에 따라 5종류의 연산 중 하나를 선택하여 처리하다. 여기서는 8 비트 Adder를 컴퓨넌트로 선언하여 이용하며 출력결과가 '00000000'인 경우 는 Zero_a의 값을 '1'로 한다. 표 2. Op Code Table Instruction half if not zero skip if zero add and xor load store jump Op Code 000 001 010 011 100 101 110 111 각 OP 코드의 기능과 처리내용은 2회 강좌의 표 3을 참조하기 바란다. < 8Bit ALU Stimulus > addpat [op_1] { [ "00000000" @ 15 ns ], [ "00010001" @ 15 ns ], [ "00001111" @ 15 ns ], [ "01010101" @ 15 ns ] }; addpat [op_2] { [ "11100011" @ 20 ns ], [ "00001110" @ 30 ns ], [ "01010101" @ 40 ns ] }; addpat [opcode] { [ "000" @ 100 ns], [ "001" @ 200 ns], [ "010" @ 150 ns], [ "011" @ 100 ns], [ "100" @ 100 ns], [ "101" @ 100 ns], [ "110" @ 100 ns], [ "111" @ 100 ns] }; view opcode, op_1, op_2, zero_a, alu_o; 시뮬레이션 결과를 검증할 때는 윈도의 Zoomin 명령을 사용하면 특정 부분 을 확대하여 분석할 수 있으며, Std_Logic_Vector의 경우는 바이너리 (Binary) 형태로 표시되므로 바이너리가 익숙하지않은 사용자는 Verify에서 Change Bus Radix를 이용하여 원하는 형태의 수식으로 변경하여 확인하는 것이 좋다. 5. 레지스터(Register) ALU의 수행에 따라 생성되는 ZERO_FLAG에 대한 정보를 저장하기 위하여 Enable 신호 및 초기화 신호를 갖는 1 비트 FF에 대한 설계가 요구된다. < 1 Bit Register Source > --******************************************************************** ENTITY reg1 IS PORT ( clk, rst, d, en : IN STD_LOGIC; q : OUT STD_LOGIC); END reg1; --******************************************************************** ARCHITECTURE reg1_a OF reg1 IS BEGIN PROCESS(clk, rst, d, en) BEGIN IF rst = '0' THEN q <= '0'; ELSIF en = '1' THEN IF clk = '0' AND clk'EVENT THEN q <= d; END IF; END IF; END PROCESS; END reg1_a; --******************************************************************** < 1 Bit Register Stimulus > addev [ pc_addr ] { [ "00001" @ 10 ns ], [ "00010" @ 20 ns ], [ "00011" @ 30 ns ], [ "01000" @ 40 ns ], [ "01110" @ 50 ns ], [ "11111" @ 60 ns ], [ "11011" @ 70 ns ] }; view pc_addr, inc_addr; 프로그램 메모리의 위치를 가리키는 PC 레지스터의 크기가 5 비트이므로 이를 위한 5 비트 레지스터의 설계 또한 필요하다. 5 비트 레지스터의 경우 는 이미 디자인한 1 비트 FF인 REG1을 이용하여 구조적으로 기술을 하면 편리하다. < 5Bit Register Source > --*************************************************************** ENTITY reg5 IS PORT ( ena : IN STD_LOGIC; rst_r : IN STD_LOGIC; clk_r : IN STD_LOGIC; dat_r : IN STD_LOGIC_VECTOR(4 DOWNTO 0); qr : OUT STD_LOGIC_VECTOR(4 DOWNTO 0)); END reg5; --*************************************************************** ARCHITECTURE reg5_a OF reg5 IS ----------------------------------------------------------------- COMPONENT reg1 PORT ( clk : IN STD_LOGIC; rst : IN STD_LOGIC; d : IN STD_LOGIC; en : IN STD_LOGIC; q : OUT STD_LOGIC); END COMPONENT; ----------------------------------------------------------------- BEGIN ----------------------------------------------------------------- u0 : reg1 port map (clk_r,rst_r,dat_r(0),ena,qr(0)); u1 : reg1 port map (clk_r,rst_r,dat_r(1),ena,qr(1)); u2 : reg1 port map (clk_r,rst_r,dat_r(2),ena,qr(2)); u3 : reg1 port map (clk_r,rst_r,dat_r(3),ena,qr(3)); u4 : reg1 port map (clk_r,rst_r,dat_r(4),ena,qr(4)); ----------------------------------------------------------------- END reg5_a; --*************************************************************** < 5 Bit Register Stimulus > addev [ena ] {[ 0 @ 10 ns ],[ 1 @ 20 ns ],[0 @ 70 ns],[1@150ns] }; addev [rst_r ]{ [ 0 @ 15 ns ],[ 1 @ 30 ns ] }; addpat[clk_r ]{ [ 1 @ 10 ns ],[ 0 @ 10 ns ] }; addpat[dat_r ]{ [ "00001" @ 40 ns ],[ "01010" @ 30 ns ] }; view ena, rst_r, clk_r, dat_r, qr; 8 비트 레지스터는 프로그램 메모리에서 읽은 명령어를 기억하는 IR 레지 스터, ALU의 연산 결과를 일시적으로 저장하는 ALU 레지스터, 데이터 메모리의 내용을 일시적으로 저장하는 MEM 레지스터 그리고 ACC 레지스터 의 설계를 위하여 8 Bit 레지스터의 설계가 요구된다. 마치며 이번에는 Multiplexer, Adder, Increase, ALU, F/F, 레지스터에 대한 VHDL 소스를 설명하였다. VHDL을 이용한 코드는 일반적인 개발 언어에 비하여 간단하고 단순하다. 아마 C나 Pascal등을 사용해 본 독자라면 눈으로 한번 촉는 정도로 이해할 수 있을 것이다. 그러나 VHDL이 다른 프로그래밍 언어와 다른 점은 하드웨어 설계를 목적 으로 디자인된 언어라는 점이다. 우리는 C나 Pascal을 가지고 원하는 하드 웨어의 기능을 시뮬레이션할 수는 있을 것이다. 그러나 그 소스 코드를 이용하여 하드웨어를 만들 수는 없다. 그러므로 VHDL을 실제 하드웨어로 구현할 수 있는 기반을 제공한다는 점에서 다른 언어와의 차이를 두어야 할 것이다. 다음에는 나머지 블럭에 대하여 Source와 시뮬레이션을 위한 자료를 설명토록 하겠다. 참고 1 MyVHDL Station의 시뮬레이션 파일 작성요령 시뮬레이션을 수행하기 위해 입력 Port에 할당할 Signal의 리스트를 작성 해야하는데, 이를 스티뮬러스(Stimulus) 또는 테스트 벡터(Test Vector)라 부른다. MyVHDL에서는 스티뮬러스를 외부에서 파일로 작성하여 입력받을 수 있게 되어 있으며, 시뮬레이션 결과 확인 과정에서 출력할 시그널(Signa) l의 리스트도 이 파일에서 정의하므로 커맨드 파일(Command File)이라고 한다. 기본 문법 구조 . ADDEV : Add Event 시뮬레이션의 시작에서 지정된 시간만큼 지난 시점에서의 시그널(Signal) 값을 설정한다. 시그날 값을 변경하기 전까지는 이전의 값이 유지된다. addev [signal name] { [ 'value' @ time (time resolution)], [...], ...}; . ADDPAT : Add Pattern 시뮬레이션 시작에서부터 끝날 때까지 지정된 패턴을 반복한다. addpat [signal name] { [ 'value' @ time (time resolution)], [...], ...}; . VIEW : Signal List for Result Display 시뮬레이션 결과를 Vwaver로 디스플레이할 때 표시될 시그널을 지정한다. view signal_name1, signal_name2, ....... 참고 2. 테스트 벤치(Test Bench)의 사용 일반적으로 VHDL 툴에서는 시뮬레이션을 수행하기 위해서 테스트 벤치를 사용한다. 물론 MyVHDL Station에서도 테스트 벤치를 사용할 수 있다. 그러나 현재의 베타 버전에서는 시뮬레이션 파일 사용을 기본으로 설정하 였기에 앞에서 설명한 스티뮬러스 파일을 배워야하는 것이고 정식 버전 에서는 스티뮬러스에 의한 방법뿐만 아니라 현재의 커맨드 파일 방식의 시뮬레이션을 모두 사용할 수 있다.
Make your own free website on Tripod.com