extension decode: 같은 0x33을 덧셈으로만 읽으면 생기는 오류
decoder에 덧셈을 인식하는 규칙을 추가하고 나니 곱셈 명령도 그 규칙에 걸렸다. 비트열의 큰 opcode가 같기 때문이다. extension decode에서는 어떤 연산처럼 보이는지를 찾는 것만으로 충분하지 않다. 정확한 encoding이 무엇이며, 현재 구성에서 그 명령을 실행할 수 있는지까지 함께 판단해야 한다.
같은 0x33 안에 서로 다른 명령이 있다
RV32의 register-register 연산 세 개를 같은 입력·목적지로 비교해 보자. rd=x1, rs1=x2, rs2=x3이며 아래 값은 각 32비트 명령어다.
| 명령 | 명령어 값 | funct7 | funct3 | opcode |
|---|---|---|---|---|
| ADD | 0x003100B3 | 0000000 | 000 | 0110011 |
| SUB | 0x403100B3 | 0100000 | 000 | 0110011 |
| MUL | 0x023100B3 | 0000001 | 000 | 0110011 |
opcode와 funct3만 검사하면 세 명령이 같아 보인다. 그런데 x2=7, x3=3이라면 결과는 ADD에서 10, SUB에서 4, MUL에서 21이다. MUL 비트열을 먼저 일치한 넓은 ADD 규칙으로 처리하면 정상적인 명령 하나를 전혀 다른 연산으로 바꾼다.
이 표는 명령어의 각 필드 위치에 값을 넣어 만든 예다. lowRISC Ibex의 원 decoder는 register-register opcode 안에서 {instr[31:25], instr[14:12]}, 즉 funct7과 funct3를 함께 비교하고, 기본 ALU 연산과 M 확장 연산을 구별한다. Ibex, ibex_decoder.sv의 OPCODE_OP 처리
“기본 명령을 먼저 처리하고 남으면 확장으로 넘긴다”는 순서 자체가 해법은 아니다. 기본 규칙이 확장에 배정된 비트까지 넓게 먹으면 뒤의 정확한 규칙은 기회를 얻지 못한다. 규칙의 일치 범위와 명령 집합의 비트 배분이 맞아야 한다.
인식한 명령과 허용된 명령을 나눈다
MUL encoding을 정확히 인식하더라도, 하드웨어가 곱셈 기능을 지원하지 않는 구성이라면 실행 허용 여부는 별도다. Ibex의 해당 분기는 MUL의 연산 종류를 구별한 뒤 RV32M이 RV32MNone인지 검사해 illegal 상태를 정한다. 이는 opcode가 있다는 사실과 확장이 제공된다는 사실을 분리하는 구체 사례다.
예를 들어 x2=7, x3=3에서 M을 지원하는 구성은 MUL 결과 21을 제공한다. 같은 비트열을 M이 없는 Ibex 구성에 넣었을 때는 정상적인 ADD 결과 10으로 대체해서는 안 된다. 하드웨어의 illegal 판정 경로로 넘어가야 한다. 실행 환경이 trap을 받아 명령을 에뮬레이션한다면 프로그램이 결과를 얻는 또 다른 단계가 있을 수 있지만, 그것은 decoder가 임의의 다른 연산으로 해석했다는 뜻이 아니다. RISC-V, Software Execution Environments and Harts
지원 여부에는 고정된 구현 옵션뿐 아니라 현재 실행 상태가 관련될 수도 있다. 그렇다고 모든 명령의 최종 허용 조건이 하나의 조합 decoder 안에서 끝난다고 생각하면 안 된다. Ibex 원문 코드도 CSR 권한과 RV32E에서 사용할 수 없는 레지스터 등 일부 illegal 조건은 다른 곳에서 검사한다고 주석으로 구분한다.
오류 표시는 정상 동작을 막는 제어와 연결되어야 한다
illegal 신호만 켜고 목적지 쓰기 신호가 그대로 남으면 어떤 일이 생길까. trap 처리를 요청하면서도 잘못 해석한 ADD 결과 10을 x1에 쓰는 모순이 생길 수 있다. 정상 실행의 제어를 차단하는 일도 판정의 일부다.
Ibex decoder는 자체적으로 illegal이라고 판정한 경우 레지스터 쓰기, 데이터 요청과 쓰기, 점프·분기와 CSR 접근 등의 제어를 낮춘다. 최종 예외 처리까지 이 코드 하나가 전부라는 뜻은 아니지만, 잘못된 명령이 정상 부작용을 시작하지 못하게 연결한 구조를 볼 수 있다. Ibex, illegal_insn에 따른 제어 차단
검증 예도 이 연결을 따라야 한다. 위 세 encoding을 올바른 연산으로 나누는 검사에 더해, M을 껐을 때 MUL이 illegal인지와 정상 목적지 쓰기가 억제되는지를 확인한다. funct7의 몇 비트만 우연히 맞은 미지원 비트열이 넓은 규칙에 걸리지 않는지도 별도의 반례가 된다.
지원하지 않는 비트열을 모두 같은 종류로 볼 수는 없다
새 규칙을 추가할 때는 reserved encoding과 명시적으로 정의된 HINT, custom 영역을 구분해야 한다. 의미 있는 연산이 아닌 비트열이라고 모두 같은 예외 정책을 가진다고 단정하면 명령 집합이 허용한 동작을 바꿀 수 있다. 어떤 비트를 반드시 검사하고 어떤 비트가 변형을 나타내는지는 각 명령의 원 규정을 따라야 한다.
extension decode의 정확성은 지원하는 명령 개수보다 경계를 얼마나 정확히 나누는지에 달렸다. ADD와 MUL을 가르는 funct7을 보존하고, 인식한 MUL을 구성 조건과 연결하며, illegal 판정을 정상 제어 차단으로 이어야 한다. 이 세 경계가 맞으면 확장이 늘어나도 새 명령이 기존 명령으로 몰래 실행되는 일을 막을 수 있다.