TECH 으로 돌아가기
TECH HACKER NEWS 오늘 7분 읽기 24 READS

8087 부동소수점 칩의 마이크로코드: FSCALE 명령어 해부

8087 부동소수점 칩의 마이크로코드: FSCALE 명령어 해부
SOURCE IMAGE · HACKER NEWS

오늘날 거의 모든 컴퓨터가 따르는 부동소수점 표준의 뿌리는 1980년 인텔이 내놓은 8087 코프로세서에 있다. 1970년대만 해도 부동소수점 연산은 제조사마다 서로 호환되지 않는 십여 가지 방식이 난립했고, 수학적 엄밀함보다 하드웨어 구현의 단순함을 앞세운 탓에 수치 안정성 문제가 잦았다. 8087은 코너 케이스에서도 최대한 정확하도록 설계되었고, IBM PC에 장착되면서 스프레드시트부터 CAD까지 부동소수점 연산을 최대 100배 빠르게 처리했다. 성능 못지않게 중요한 것은, 이 칩이 이후 산업 표준의 원형이 되었다는 점이다.

켄 시리프(Ken Shirriff)가 참여하는 리버스 엔지니어링 그룹 '옵코드 컬렉티브(Opcode Collective)'는 8087 내부를 제어하는 마이크로코드를 해독하는 작업을 이어가고 있다. 이번 분석의 대상은 FSCALE 명령어다. 부동소수점 수를 2의 거듭제곱만큼 스케일링하는 이 명령은 곱셈보다 훨씬 빠른데, 원리 자체는 '지수에 정수를 더한다'는 한 줄로 요약된다. 겉보기엔 사소한 명령이지만 실제 마이크로코드는 140개가 넘는 마이크로 명령과 3단계 서브루틴 호출로 이뤄져 있다. 그 복잡함의 정체가 이 글의 핵심이다.

칩 내부의 구조

분석은 칩을 열어 현미경으로 고해상도 이미지를 찍는 물리적 작업에서 출발한다. 칩 중앙에는 1,648개의 마이크로 명령을 담은 마이크로코드 ROM이 있고, 왼쪽의 마이크로코드 엔진이 점프와 서브루틴 호출을 처리하며 코드를 순차 실행한다. 아래쪽 절반은 실제 연산을 수행하는 '데이터패스'로, 지수를 다루는 16비트 경로와 가수(significand)를 다루는 64비트 경로로 나뉜다. 여기에는 값을 임의의 비트 수만큼 좌우로 옮기는 시프터, 곱셈·나눗셈·제곱근에서 반복적으로 쓰이는 가산기, 지수의 특수값을 검출하고 형식을 변환하는 지수 변환기가 배치돼 있다.

8087은 값을 여덟 개의 스택 레지스터에 80비트 부동소수점 형태로 저장하며, 각 값에는 유효(valid)·특수(special)·영(zero)·비어 있음(empty)을 구분하는 '태그'가 붙는다. 무한대, NaN, 비정규화 값은 특수로 분류된다. 내부적으로는 정수든 BCD든 모두 '임시 실수(temporary real)'라 불리는 80비트 형식으로 통일해 처리한다. 이 형식은 부호 1비트, 15비트 지수, 64비트 가수로 구성되며, 지수에는 16383의 바이어스가 더해져 항상 양수로 저장된다. 이 바이어스 값은 뒤에서 다시 등장한다.

왜 단순한 명령이 복잡해지는가

8087은 잘못된 연산(0/0, ∞-∞), 오버플로, 언더플로, 0 나눗셈, 비정규화 피연산자, 그리고 정밀도까지 여섯 종류의 예외를 구분해 처리한다. 각 예외는 제어 레지스터의 비트로 마스킹 여부를 제어하는데, 마스킹을 해제하면 8086에 인터럽트를 걸어 소프트웨어가 개입하고, 마스킹하면 칩이 최선의 결과로 연산을 이어간다. 예컨대 잘못된 결과는 NaN으로, 오버플로나 0 나눗셈은 무한대로 치환된다. 이런 유연성은 정확성을 높이지만, 특수값들의 조합을 일일이 처리해야 하므로 마이크로코드를 크게 부풀리는 원인이 된다.

각 마이크로 명령은 16비트다. 앞 3비트가 명령 유형을 지정하고 나머지 비트의 의미를 결정한다. 유형에는 레지스터 간 데이터 전송, 배럴 시프터를 이용한 시프트, 덧셈과 뺄셈을 담당하는 가산기 제어, 스택 포인터·태그·예외를 다루는 기타 명령, 그리고 원거리 점프·호출과 근거리 상대 점프가 있다. 조건 필드로 분기를 제어하고 마지막 비트로 조건을 반전시킬 수 있다. 명령이 시작되면 디코더가 해당 마이크로코드의 시작 주소를 계산하는데, FSCALE는 10진수 748번지에서 시작한다.

FSCALE가 밟는 실제 단계

FSCALE 루틴은 먼저 스택 최상단 st(0)의 첫 인자를 임시 레지스터 tmpA로 옮긴다. 이 값이 0이면 즉시 반환하므로, 0을 무엇으로 스케일링하든—심지어 NaN으로도—결과는 0이다. 이어 두 번째 인자를 tmpB로 옮기고, 이 값이 0이면 역시 반환해 원래 값을 그대로 둔다. 정상적인 경우에는 특수 처리 서브루틴을 건너뛰고 763번지로 점프한다.

763번지부터는 두 번째 인자를 부동소수점에서 정수로 변환한다. 예를 들어 9는 부동소수점으로 1.001×2³이며, 왼쪽 정렬된 가수 비트를 정수로 만들려면 오른쪽으로 밀어야 한다. 지수가 n일 때 가수는 63-n비트만큼 오른쪽으로 시프트해야 하는데, 지수에 16383 바이어스가 걸려 있으므로 실제로는 0x403e에서 지수를 뺀 값만큼 밀어야 한다. 앞서 상수 0x403e가 준비된 이유가 여기 있다. 마이크로코드는 지수를 가산기 입력인 B 레지스터로 옮기고, 지수 변환기로 오버플로를 검사한 뒤, 0x403e를 tmpC에 넣고 뺄셈을 수행한다. 그 결과는 합 레지스터를 거쳐 시프트 카운트 레지스터로 복사되어 시프터를 구동하고, 시프트된 값이 다시 B 레지스터로 들어간다. 개념적으로 한 줄인 연산이 레지스터 이동과 상수 선택, 시프트 활성화와 결과 읽기라는 별개의 마이크로 명령들로 촘촘히 쪼개져 있음을 보여주는 대목이다.

실무자에게 이 분석의 의미는 두 가지다. 하나는 오늘날 우리가 당연하게 여기는 IEEE 계열 부동소수점의 정확성이, 특수값과 예외를 빠짐없이 처리하려는 이런 마이크로코드 수준의 노력 위에 서 있다는 사실이다. 다른 하나는 추상화 아래의 실제 구현이 상위 명령의 단순함과 얼마나 다를 수 있는가라는 점이다. 다만 이 글은 완전히 해독된 명령 하나를 다룰 뿐, 1,648개 마이크로 명령 전체의 해석이 끝난 것은 아니며 여기 소개된 동작도 특정 정상 경로에 한정된 서술이라는 한계는 분명히 짚어둘 필요가 있다.

SOURCE · HACKER NEWS
원문 전체 보기 → https://www.righto.com/2026/09/8087-microcode-reverse-engine...
SHARE
NEXT · CHOOSE

변화를 읽었다면,
내가 만들 수익 구조를 고릅니다.

정보를 더 모으는 데서 멈추지 않고, 광고·외주·판매·중개·구독 중 내 상황에 맞는 출발점을 정해보세요.

21가지 수익 구조 살펴보기
처리 중...