#Project 3-순차회로를 이용해 2차 방정식의 해를 계산하는 계산기 만들기(멀티사이클 구조)
마지막으로 순차회로를 이용해 2차 방정식의 해를 구하는 모듈을 설계해 보자. 2차 방정식의 해를 구하는 방법에는 여러 가지 방법이 존재하지만 그중에서도 가장 대표적인 방법은 근의 공식을 활용하는 방법이다.
중등과정에서 배우는 근의공식은 수학에서 가장 기본이 되는 공식이며, 아마 첫 번째로 외우는 식일 것이다. 근의 형태에는 서로 다른 두 실근, 하나의 중근, 서로 다른 복소근이 존재한다. 중근과 복소근은 실제적으로 구현하는 데에 한계가 있기 때문에 서로 다른 두실근의 경우만 이번모듈에서 다루겠다.
#모듈의 입출력
요구되는모듈의 입출력은 다음과 같다. 입력은 a, b, c각각 4비트, 3비트, 3비트 2 의보수로 입력을 받고 출력은 Q(5.3)의 출력을 따르며 2개의 segment display로 출력한다. a, b, c 통틀어서 10비트 입력을 스위치로 입력받고 출력은 앞서 루트계산기의 출력과 같은 형태로 출력하면 될 것이다. 얼핏 보기에는 루트 안 계산값만 인스턴스 해서 단순히 계산하면 될 것 같지만 분수의 형태로 되어있기 때문에 나눗셈 계산이 필수적이다. 소수가 포함되어 있는 나눗셈을 어떻게 구현해야 하는지가 이번모듈설계의 핵심이라고 볼 수 있을 것이다. 그리고 출력되어야 하는 근이 총 2개이므로 토글(버튼)을 눌렀을 때 다른 근이 디스플레이에 표시되어야 하는 것도 모듈의 요구사항이다. 따라서 입력에는 토글버튼도 포함되어야 한다.(+,-총 2개의 근이존재)
#설계의 과정
근의공식의 최종값을 구하는 것을 모듈의 설계목적으로 설정하자. 그러면 결국 핵심적인 연산은 근의 공식 분자 부분을 2a로 나누는 과정이 핵심적인 부분일 것이다. 왜냐하면 분자 부분이 일반적인 부분이 아닌 소수+정수 부분이므로 소수가 포함된 나눗셈을 멀티사이클을 통해서 구현해야 하기 때문이다. 이 과정에서 앞서 설명한 부동소수점의 개념이 이용된다. 입력된 a, b, c가 모두 2의 보수이므로 보수화된 수를 연산의 편리함을 위해서 양수로 바꾸어서 연산한 뒤에 부호판단을 해서 마지막에 다시 보수화를 통해서 최종적인 결과를 출력하는 방법으로 설계를 진행했다.
1. 입력값의 역 보수화
입력값이 모두 보수이기때문에 연산과정에서 비트수가 맞지 않아서 오류가 자주 발생할 수 있을 것이다. 따라서 보수화된 입력값을 역보수화하는 과정을 통해서 모두 양수로 만드는 과정이 필수적이다.
위와 같이 3중 연산자를 이용해서 간단하게 구현할 수 있다. 각각의 입력값의 MSB가 1인경우는 입력값이 음수라는 의미이므로 a의모든 비트를 bitwise not연산을 한 뒤에 +1을 해준다. 하지만 0인경우에는 입력값이 양수라는 의미이므로 그냥 입력값 그대로 할당된다. 이때 연산과정에서 000을 뒤에 붙인 이유는 소수 부분을 만들어서 비트수를 맞추기 위함이다. 가령 3과 3.0은 같은 것처럼 뒤에 임의로 소수를 붙여서 비트수를 맞추기 위한 작업이라고 볼 수 있겠다.
2. 루트값의 계산
먼저 근의 공식에 존재하는 루트값의 계산이 첫 번째로 계산되어야 한다. b^2-4ac의 값이 먼저 계산되고 계산된 값이 인스턴스 한 모듈의 입력값으로 입력되어 계산결과가 출력되는 방법이 가장 간단하다고 판단되어서 이러한 방법으로 설계하였다. a, b, c의 값이 모두 정수이고 b^2-4ac의 값이 양수이므로 앞서 조합회로로 구현했던 루트계산기를 인스턴스 해서 사용해도 설계상의 오류가 생기지 않다고 판단해서 그대로 인스턴스해서 사용하였다.
ㅍ
위의 코드와 같이 각각의 상수들을 계산하고 모듈을 인스턴스해서 결괏값을 할당할 수 있을 것이다. 변수를 모두 새롭게 지정한 이유는 비트수를 맞추어서 연산과정에서 오류가 없도록 하기 위함이다.
3. 분자값의 계산
분자에는 +,-총 2개의 계산결과가 존재한다. 앞서 구한 루트값 계산결과를 이용해 b와 계산하면 되는데 마찬가지로 부호판단과 비트수가 맞아야 한다는 것이 관건이다. 이때 b는 정수이므로 루트값과 연산 시에는 정수는 정수끼리 연산을 해도 연산과정에서 문제가 없을 것이다. 설명하자면 정수+(정수+소수)의 형태에서 (정수+정수)+소수로 간단하게 정수끼리 계산한 뒤에 계산결과에 루트값의 소수 부분을 붙이는 것이 간단할 것이다. 특히 토글값에 따라서 분자값이 달라지기 때문에 토글을 고려한 조건문을 이용해 분자를 결정한다.
위와 같이 토글의 조건(값)에 따라서 다르게 연산이 이루어질 것이다. 앞서 설명한 것과 같이 정수 부분이 핵심적인 계산이므로 정수부분만이 계산과정에 사용된다는 것을 확인할 수 있다.
4. 나눗셈의 구현
마지막으로 가장 중요한 나눗셈의 구현이다. 마찬가지로 멀티사이클을 이용해서 나눗셈을 구현해야 한다. 지금 직면한 문제가 소수 부분이 포함된 나눗셈을 어떻게 멀티사이클로 설계를 해야 되느냐가 가장 핵심적인 계산인데 먼저 소수가 없는 정수끼리의 나눗셈을 생각해 보자. 예를 들어 10/3을 구하고 싶을 때는 모듈로연산과 몫연산을 사용해서 가장 간단하게 나타낼 수 있지만 이 방법은 소수에서는 적용이 되지 않을뿐더러 멀티사이클 연산이 아니다. 따라서 우리는 뺼셈으로 나눗셈을 구현할 수 있을 것이다. 10에서 3을 매 클럭마다 빼는 것이다. 10-3=7, 7-3=4, 4-3=1, 왕같이 더 이상 3으로 뺄 수 없을 때까지 뺼셈을 진행한다. 따라서 총 3번 연산을 진행하였으므로 몫은 3이고 나머지는 마지막연산의 결과인 1이 된다. 따라서 10/3=3... 1 임을 알 수 있다. 이러한 원리를 소수가 포함된 나눗셈에 적용시켜 보자. 마찬가지로 소수점에 대한 작업이 필요하다.
위 식에서 소수점을 정규화시키기 위해 양변에 2^3=8을 곱한다. 따라서
이렇게 소수가 없는 형태로 만들어졌다. 우리는 이제 8x의 값을 찾는 것이므로 분자에서 분모의 값을 하나씩 뺴나가는 과정이 필요하다.
위와 같은 코드로 나눗셈을 구현할 수 있다. 음수가 될 때까지 빼는 것이 조건이므로 if조건문을 사용해서 매 클럭마다 카운팅 한다.
5. 근삿값의 결정
위 과정을 통해서 8x의 값을 구한 뒤에 우리는 8로 다시 나누어주는 역정규화 과정이 필요하다. 따라서 8을 나눈다는 개념은 소수점은 다시 생기게 하는것이므로 xxxxxxxx 에서 xxxxx.xxx으로 다시 만들면 된다. 8로 나눈다는개념 자체는 따로 연산과정 없이 그냥 설계자가 하위비트 3개를 소수 부분으로 해석하는 것이 8로 나눈다는 개념인 것이다. 하지만 몫은 구했지만 어떤 몫에 더 가까운지에 대한 연산이 필요하다. 예를 들어 10/3=3.3333이므로 4보다 3에 더 가까운 수이다. 따라서 10-3=7, 7-3=4, 4-3=1, 1-3=-2에서 어떤몫에 더 가까운지 판단하기위해서는 뺄셈의 연산결과로 쉽게 예측할수있다. 마지막 연산 두개 4-3=1, 1-3=-2 에서 1 <|-2| 이므로 마지막에서 2번째 연산결괏값이 더 작다. 따라서 몫은 3에 더 가까운 것을 알 수 있을 것이다. 이때 마지막연산결과는 항상 음수이므로 절댓값을 취해서 비교해야 한다는 것을 잊지 말자. 따라서 이를 코드상으로 구현하면 다음과 같다.
if비교문을 통해서 어떤 값을 근삿값으로 할당할지 결정한다. 따라서 appxi가 최종적인 근사값으로 출력된다.
'Project > DSD project' 카테고리의 다른 글
[Project] Verilog Term Project-루트계산기(3) (0) | 2023.01.13 |
---|---|
[Project] Verilog Term Project-루트계산기(2) (0) | 2023.01.11 |
[Project] Verilog Term Project-루트계산기(1) (0) | 2023.01.08 |