VHDL로 작성한 계산기의 소스 파일 입니다.
*준*
다운로드
장바구니
소개글
VHDL로 작성한 계산기 소스파일입니다. 4칙연산(더하기,빼기,곱하기,나누기)를 수행하여 4개의 7 segment에 출력하도록 합니다.어떤 분이 구매하시고 동작하지 않는다고 하시는데 ㅡ,ㅡ 정확히 동작합니다.
encoder.vhd 파일을 보시면 LSB에 숫자1이 할당되고 바로 상위에 숫자2가 할당됩니다.현재 입력 2,0,8,0 , 4,0,8,0 이런식으로 들어가는것을 확인할 수 있는데
이것이 연산 모듈에 엔코딩 되어 넘어가는 수는 각각 24 , 34 가 됩니다. 연산자8은 곱하기를 의미하죠. 따라서 24*34 =816으로 정확히 출력이 됩니다. 연산에 의한 결과값확인은 alu 모듈 내의 result 시그널을 확인하시면 알 수 있습니다.
최종 출력인 display_h , diplay_m ,display_i 는 각각 100의 단위 세그먼트 ,10의 단위 세그먼트 , 1의 단위 세그먼트 값을 의미하며 127,18,111로 출력되고 있는데 이값은 816을 뜻하는 세그먼트 값입니다.
다시 한번 확인해주시길 바랍니다.
----------------------------------------------------------------------------------------
vhdl의 경우 c 와는 달리 다른 사람의 코드를 보고 이해하는 것이 쉽지 않습니다.
저 또한 작성한지 좀 된 코드라 생각이 가물가물할수도 있구요.
아무튼 구매하신분이 잘 이해가 안된다고 하시기에 좀더 부가적으로 설명을 작성합니다.
calculator_machine.vhd
파일이 가장 탑 모듈입니다.
전체 입력은 버튼 입력 10비트, 연산입력 5비트, 리셋, 클럭으로 구성이 되어 있으며
전체 출력은 7-세그먼트 3자리로 결과를 출력하도록 되어 있습니다.
입력이 10비트인 이유는 0~9까지 숫자가 10개라서 그런거구요.
연산입력은 + , - , * , / , = 까지 5비트가 됩니다. 각 비트에 대한 할당값은 encoder.vhd , func_encoder.vhd파일을 참조하세요
구성 모듈은 전체 시스템을 총괄하는 state 머신과 메모리 unit , 연산 유닛 마지막으로 출력을 맡게되는 display 유닛으로 구현되어 있습니다.
스테이트 머신은 메모리 유닛에 입력받은 숫자를 저장하게 되고 저장이 완료된후 그 데이터를 연산 유닛으로 보내
결과를 display하도록 컨트롤 시그널을 출력하는 역할을 합니다.
스테이트 머신은 밀리 머신의 형태로 구현이 되어 있으며 스테이트는 8개로 구현되어 있습니다.
처음 init 스테이트
인풋 1을 기다리는 스테이트
인풋 2를 기다리는 스테이트
연산입력을 기다리는 스테이트
인풋 3을 기다리는 스테이트
인풋 4를 기다리는 스테이트
=을 기다리는 스테이트
최종적으로 모든 수가 입력되면 연산을 수행하는 스테이트
자세한 컨트롤 시그널의 출력은 스테이트 머신 코드를 참조하시길 바랍니다.
현재 압축되어 있는 파일의 모두가 필요합니다. 계층적 구조로 코드가 작성되어 있기 때문에 하나라도 빠지게 되면 동작하지 않습니다.
테스트 밴치 파일의 경우 cal_test_tb.vhd 파일로 작성이 되어 있으며 4칙 연산이 수행되는걸 확인하실수 있을것입니다.
바꿔가면서 태스트 해보시길 바래요.
전체 모듈의 인터페이스는 맨위에 설명한대로 생각하시면되구요. 정확한건 encoder.vhd 파일과 func_encoder.vhd파일을 확인하시면 결과를 보실수 있습니다.
그리고 연산의 결과값은 alu 모듈내부의 result 시그널을 보시면 확인하실수 있습니다.
--------------------------------------------------------------------------------
이제 막 vhdl 시작했는데 어떻게 계산기 과제가 나와서 이렇게 구입했습니다. 문제는 제가 잘 못한다는 거지요. 우선 ALU.vhd 파일에 logic 셀이 너무 많다고 에러가 나구요. 11개 파일을 모두 컴파일 했을시에 그래픽 에디터로 컴파일한 소스의 그림 11개를 연결해야 되는거 아닌가요?? 근데 연결을 할 줄도 모릅니다 어떻게 메일 주소라도 알려주시면 안될까요 죄송하지만...내일 4시까지 해야되기 때문에 걱정이 많이 되네요 도움 주시는건 감사드리구요
----------------------------------------------------------------------------------
답변.
1.alu의 로직셀이 많다고 나온다.
이 코드는 시뮬레이션을 위해서 작성된 vhdl 코드 입니다. alu 모듈을 보시면 for문을 사용해서 곱셈과 나눗셈을 한 사이클에 수행되도록 만들어져 있습니다. 실제로 곱셈과 나눗셈을 한 사이클에 계산한다는 것은 그 만큼 오버해드가 커져 로직량이 많이 필요해지게 됩니다. 아마도 그러한 에러 메세지가 출력된 것은 님이 사용하실 타겟 fpga의 로직량이 이 코드를 담기에 부족한 것이라 여겨집니다. 다시 말씀드리지만 이 코드는 시뮬레이션을 위해 작성된 코드이기 때문에 실제 구현에는 적합하지 않습니다.
2. 그래픽 에디터로 컴파일한 소스...
저는 그래픽 에디터가 무엇인지 잘 모르겠습니다.
제 추측이 맞다면 아마도 현재 vhdl 코드를 기반으로해서 심볼을 생성하고 그 심볼들을 버스로 연결해주는 작업을 말씀하시는거 같은데요. 심볼로 만들어서 붙일수도 있습니다만 그럴게 할려고 한다면 vhdl코드중에서 port map 되는 부분을 잘 참조하시길 바랍니다. signal의 비트수도 잘 확인하셔야 합니다. 계층적 구조로 이루어져 있기 때문에 그 구조 또한 잘 살피셔야합니다. 예를 들어서 controller 모듈 안에는 숫자 엔코더(encoder.vhd) , 연산 엔코더(func_encode.vhd) , 멀티플렉서(multiplexier.vhd) 모듈과 더불어 state 머신이 구현되어 있습니다.
그리고 마지막으로 segment_driver 파일을 열어보시면 제가 세그먼트를 정의한 것이 보입니다.
그것과 fpga 핀을 정확히 일치 시켜서 작성하셔야합니다. 그렇지 않을 경우 숫자가 이상하게 출력되겠죠.
핀 매핑은 쓰시는 툴(ISE, 쿼터스 etc)에따라서 그리고 타겟으로 쓰는 fpga에 따라서 다르게 되어 있으니 보드 메뉴얼을 참조하시면 어떠한 핀으 어떻게 세그먼트에 연결이 되어 있는지 알수 있고 active high 인지 active low 인지 확인하신 후에 그 핀으로 원하는 비트 값을 출력하면 됩니다.
님께서 하시는 프로젝이 정확히 어떠한 보드에서 어떠한 fpga를 타겟으로 얼마만큼의 로직량을 사용해서 구현해야하는지 제가 알 길이 없네요. 그래서 도움이 될지는 잘 모르겠습니다
-------------------------------------------------------------------------------------
역시 최종 보드 구현이 프로젝이군요.
그럼 더더욱이 이 코드로는 되지 않습니다. 왜냐하면 이 코드는 위에서도 밝혔듯이 시뮬레이션용이구요. 실제 버튼입력을 사용했을때 버튼이 눌러지는것을 감지한후 다시 때어지는것도 감지해야하는데요. 실제 버튼 입력의 경우는 이렇게 하나의 입력에 대해서 2개의 스테이트를 할당해야하는데(무어머신의 경우) 현재 코드는 단 한사이클의 입력이 들어온다는 가정하에 작성된 것임으로 실제로 이 코드를 구현해서 사용하게 되면 님이 버튼 하나를 누른 순간 같은 숫자 입력이 연속적으로 들어가게됨니다. 그러니까 1을 1번 눌렀다고 누르지만 스테이트 머신의 동작 속도가 최소한 메가단위이기 때문에 1이 연속적으로 계속 들어가게 됩니다. 위와 같이 손이 때어지는 부분에 대한 스테이트가 존재하지 않기때문에 발생하는 문제입니다.
한백 보드라면 아마 쿼터스 툴에 알테라 fpga를 사용하시겠군요. 음. 이건 좀 야매인데요 ㅡ,ㅡ
ise 의 coregen과 같이 쿼터스에서도 지원하는 곱셈기와 나눗셈기가 있을 것입니다.
그것들은 보통 하드와이어로 fpga내부에 구현되어 있을 확률이 높은데요 걔네를 이용하는건 어떠한지요? 걔네는 이미 구현되어 fpga에 내장되어 있는 애들이기때문에 추가적으로 많은 로직을 사용하지 않을 것입니다. 그리고 연산 사이클도 정할 수 잇구요. alu 모듈내부에 곱셈기와 나눗셈기만 그것들로 교체하면 다운로드하는게 가능할거 같기도 하군요. 다만 위에서 말씀드린 스테이트 머신 문제는...글쎄요 ㅡㅡ 입력을 겁내 빨리 눌렀다가 때면 될지도.
아!! 아니면 입력 받는 모듈 앞에 버튼의 입력을 받았으때 처음 누른 값만 한 사이클동안 계산기 모듈에 넘겨주는 작은 스테이트 머신을 삽입하셔도 가능합니다. 그러고 보니 현재 계산기 모듈에 변화 없이 문제 해결이 가능하군요. 다만 하드와이어 곱셈기 나눗셈기를 사용한 흔적을 레포트에는 올리면 안될거 같다는 ㅡ,ㅡ ㅎ
아래의 코드를 프로젝트에 삽입하시면 위에서 말한 버튼 입력에 대해서 발생하는 문제를 해결할 수 있습니다. 테스트 해보진 않았습니다만 돌아갈것이라 생각합니다. 기존 프로젝트에 상위 모듈을 하나 더 만들어서 중간에 입력을 감지하는 스테이트 머신을 추가했습니다.
그렇게 만든 스테이트 머신을 입력두곳 즉 버튼 입력부와 연산자 입력사이에 끼워넣었습니다.
---------------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity total_top_calculator is
port
(
clk :in std_logic;
reset :in std_logic;
Num :in std_logic_vector(9 downto 0);
Func :in std_logic_vector(4 downto 0);
Display_h: out std_logic_vector(6 downto 0);
Display_m: out std_logic_vector(6 downto 0);
Display_l: out std_logic_vector(6 downto 0)
);
end total_top_calculator;
architecture Behavioral of total_top_calculator is
component calculator_machine
port
(
clk :in std_logic;
reset :in std_logic;
Num :in std_logic_vector(9 downto 0);
Func :in std_logic_vector(4 downto 0);
Display_h: out std_logic_vector(6 downto 0);
Display_m: out std_logic_vector(6 downto 0);
Display_l: out std_logic_vector(6 downto 0)
);
end component;
component input_detect
port
(
clk :in std_logic;
reset :in std_logic;
input_v :in std_logic;
output_v:out std_logic
);
end component;
signal num_v : std_logic;
signal op_v : std_logic;
signal num_v_out : std_logic;
signal op_v_out : std_logic;
signal num_final_in : std_logic_vector(9 downto 0);
signal op_final_in : std_logic_vector(4 downto 0);
begin
num_v <= Num(9) or
Num(8) or
Num(7) or
Num(6) or
Num(5) or
Num(4) or
Num(3) or
Num(2) or
Num(1) or
Num(0) ;
op_v <= Func(4) or
Func(3) or
Func(2) or
Func(1) or
Func(0) ;
CALCULATOR:
calculator_machine
port map
(
clk =>clk ,
reset =>reset
Num =>num_final_in,
Func =>op_final_in
Display_h=>Display_h,
Display_m=>Display_m,
Display_l=>Display_l
);
NUM_INPUT:
input_detect
port map
(
clk =>clk ,
reset =>reset ,
input_v =>num_v,
output_v=>num_v_out
);
OP_INPUT:
input_detect
port map
(
clk =>clk ,
reset =>reset,
input_v =>op_v,
output_v=>op_v_out
);
process(num_v_out , num)
begin
if (num_v_out = '1' ) then
num_final_in <=num;
else
num_final_in <="0000000000";
end if;
end process;
process(op_v_out , func)
begin
if (op_v_out = '1' ) then
op_final_in <=num;
else
op_final_in <="00000";
end if;
end process;
end ;
--------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity input_detect is
port
(
clk :in std_logic;
reset :in std_logic;
input_v :in std_logic;
output_v:out std_logic
);
end input_detect;
architecture Behavioral of input_detect is
signal pre_state : std_logic_vector(2 downto 0);
signal next_state : std_logic_vector(2 downto 0);
constant init : std_logic_vector(2 downto 0):="00";
constant wait_inputhigh : std_logic_vector(2 downto 0):="01";
constant out_valid : std_logic_Vector(2 downto 0):="11";
constant wait_inputlow : std_logic_vector(2 downto 0):="10";
begin
process(pre_state , clk , input_v)
begin
case pre_state is
when init =>
next_state <=wait_inputhigh;
output_v <='0';
when wait_inputhigh =>
if input_v = '1' then
next_State <=out_valid;
else
next_state <=wait_inputhigh;
end if;
output_v <='0';
when out_valid =>
next_state <=wait_inputlow;
out_valid <='1';
when wait_inputlow =>
if input_v = '1' then
next_State <=init;
else
next_state <=wait_inputlow;
end if;
output_v <='0';
when others =>
next_state <=init;
output_v <='0';
end case;
end process;
-- State Register
process(reset, clk , next_State)
begin
if rising_edge(clk) then
if reset= '1' then
pre_state <=init;
else
pre_state <=next_state;
end if;
end if;
end process;
-----------------------------------
컴파일 실행환경
Modelsim압축파일 내 파일목록
calculator_modelsim.zip
calculator.hwp
calculator.hwp
참고 자료
VHDL 강의 및 교재프로그램소스 연관자료
이 자료와 함께 구매한 자료
[디지털공학] VHDL을 이용한 계산기 설계 51페이지
VHDL를 이용한 계산기설계 23페이지
[정보이론] gf 곱셈기 나눗셈기 vhdl 설계 12페이지
[vhdl] VHDL 계산기2 5페이지
논리회로 설계 실험 계산기 설계 21페이지