문제

나는 읽고 있었다 인텔 사용 설명서 그리고 메인 CPU에서 아무 작업도 하지 않는 'NOP' 명령어와 FPU에서 아무 작업도 하지 않는 'FNOP' 명령어가 있음을 확인했습니다.아무것도 하지 말라는 두 가지 별도의 지시사항이 있는 이유는 무엇입니까?

내가 본 유일한 차이점은 서로 다른 예외를 발생시킨다는 것입니다. 따라서 FNOP에서 예외를 관찰하여 사용 가능한 FPU가 있는지 감지할 수 있습니다.하지만 이를 감지하는 CPUID와 같은 다른 메커니즘이 없나요?두 개의 별도 NOP 명령어를 사용하는 실제적인 이유는 무엇입니까?

도움이 되었습니까?

해결책

Raymond Chen과 Hans Passant의 의견을 확장하면 두 가지 별도의 지침이 있고 동일한 효과가 없는 역사적 이유가 있습니다.

두 가지 지침 중 어느 것도 NOP 그리고 FNOP, 는 원래 명시적인 작업 없음 명령으로 설계되었습니다.그만큼 NOP 명령어는 실제로 명령어의 별칭일 뿐입니다. XCHG AX,AX.(또는 32비트 모드에서는 XCHG EAX, EAX.) 초기 Intel 프로세서에서는 실제로 아무것도 수행하지 않았습니다.외부적으로는 눈에 보이는 효과는 없었지만 내부적으로는 다음과 같이 실행되었습니다. XCHG 명령을 실행하는 데 많은 사이클이 소요됩니다.'486은 이를 특별하게 처리한 최초의 Intel CPU였습니다. NOP 1사이클에 다른 레지스터-레지스터를 실행하는 데 3사이클이 걸렸습니다. XCHG 지침.

치료 XCHG AX,AX 특히 현대 Intel 프로세서에서는 명령이 매우 중요해졌습니다.실제로 동일한 레지스터를 자신과 교환하고 있는 경우 근처 명령어도 해당 레지스터를 사용하면 파이프라인 지연이 발생할 수 있습니다. AX 등록하다.그것을 특별하게 취급함으로써 CPU는 결국 다음과 같은 생각을 하지 않게 됩니다. NOP 다음을 설정하는 이전 명령을 기다려야 합니다. AX 또는 다음 명령이 NOP.

이는 아무 작업도 수행하지 않는 다양한 명령이 많이 있다는 사실을 나타냅니다. XCHG AX,AX 단일 바이트인 유일한 것입니다(특수한 경우로 누산기와 레지스터 교환 단일 바이트 XCHG 인코딩).종종 이러한 명령어는 연속 명령어 대신 단일 명령어로 사용됩니다. NOP 성능상의 이유로 루프 시작을 정렬하는 경우와 같은 지침입니다.예를 들어 6바이트 NOP를 원한다면 다음을 사용할 수 있습니다. LEA EAX,[EAX + 00000000].Intel은 결국 명시적인 다중 바이트 NOP 명령을 추가했습니다.(글쎄, Pentium Pro 이후로 존재했던 명령을 공식적으로 문서화한 만큼 많이 추가되지는 않았습니다.) 그러나 단일 바이트 형식만 특별하게 처리됩니다.인근 명령어가 동일한 레지스터를 사용하는 경우 다중 바이트 NOP는 지연을 생성합니다.

AMD가 CPU에 64비트 지원을 추가했을 때 그들은 더욱 발전했습니다. NOP 더 이상 동등하지 않습니다 XCHG EAX,EAX 64비트 모드에서.Intel 명령어 세트의 문제점 중 하나는 레지스터의 일부만 수정하는 명령어가 많다는 것입니다.예를 들어 MOV BX,AX 하위 16비트만 수정합니다. EBX 상위 16비트는 수정되지 않은 채로 둡니다.이러한 부분 수정으로 인해 CPU가 정지되는 것을 방지하기 어렵기 때문에 AMD는 64비트 모드에서 32비트 명령어를 사용할 때 이를 방지하기로 결정했습니다.32비트 연산의 결과가 (64비트) 레지스터에 저장될 때마다, 전체 레지스터가 수정되도록 값은 64비트로 0 확장됩니다..이는 다음을 의미합니다. XCHG EAX,EAX 상위 32비트를 지우므로 더 이상 NOP가 아닙니다. EAX (따라서 명시적으로 작성하면 XCHG EAX,EAX, 0x90으로 어셈블할 수 없으며 다음을 사용해야 합니다. 87 C0 부호화).64비트 모드 NOP 이제 다른 해석이 없는 명시적인 NOP입니다.


에 관해서는 FNOP 원본 8087에서는 FPU가 이 명령어를 어떻게 처리했는지 완전히 명확하지 않지만 명시적인 무작동으로 처리되지는 않았다고 확신합니다.적어도 하나의 오래된 인텔 매뉴얼, ASM86 언어 참조 매뉴얼 문서가 아무 효과도 없이 작업을 수행하는 것으로 간주합니다("스택 상단을 스택 상단에 저장").opcode 맵의 위치에서 보면 다음 중 하나에 대한 별칭인 것처럼 보입니다. FST ST 또는 FLD ST, 둘 다 스택의 상단을 스택의 상단으로 복사합니다.그러나 특별한 처리를 받았기 때문에 스택을 쌓는 데 평균 18~20주기가 아닌 평균 13주기로 실행되었습니다. FST 또는 FLD 각각 지시.무작동 명령어로 처리된다면 절반의 시간 안에 실행될 수 있는 8087 명령어가 많기 때문에 훨씬 더 빠를 것으로 예상됩니다.

더 중요한 것은 FNOP 명령은 다음과 다르게 동작합니다. NOP FPU 명령이 Intel 프로세서에서 구현되는 방식 때문입니다.CPU 자체는 부동 소수점 연산을 지원하지 않았고 대신 이러한 작업은 원래 8087이었던 선택적 부동 소수점 보조 프로세서로 오프로드되었습니다.보조 프로세서의 좋은 점 중 하나는 CPU와 병렬로 명령을 실행한다는 것입니다.그러나 이는 때때로 CPU가 FPU가 작업을 완료할 때까지 기다려야 함을 의미합니다.CPU는 다른 명령을 내리기 전에 이전 명령의 실행이 끝날 때까지 자동으로 기다리지만, 프로그램은 명시적으로 기다려야 합니다( WAIT 명령) 보조 프로세서가 메모리에 쓴 결과를 읽기 전에.

보조 프로세서가 병렬로 작동하기 때문에 이는 FPU 명령이 부동 소수점 예외를 생성한 경우 이를 감지할 때쯤에는 CPU가 이미 다음 명령을 실행하기 위해 이동했음을 의미합니다.일반적으로 명령어가 CPU에서 예외를 생성하면 해당 명령어가 실행되는 동안 처리되지만, FPU 명령어가 예외를 생성하면 CPU는 해당 명령어를 FPU에 전달하여 이미 해당 명령어 실행을 완료합니다.CPU를 중단하고 부동 소수점 예외를 비동기적으로 전달하는 대신 CPU는 명시적 또는 암시적으로 보조 프로세서를 기다릴 때만 알림을 받습니다.

최신 프로세서에서 FPU는 더 이상 보조 프로세서가 아니며 CPU의 필수 부분입니다.이는 프로그램이 더 이상 FPU가 메모리에 값을 쓸 때까지 기다릴 필요가 없음을 의미합니다.그러나 FPU 예외가 처리되는 방식은 변경되지 않았습니다.(예외를 즉시 전달하는 것은 최신 CPU에서 구현하기 어렵기 때문에 필요하지 않은 한 가지 경우를 활용했습니다.) 따라서 이전 FPU 명령어가 전달되지 않은 부동 소수점 예외를 생성한 경우 NOP 예외는 전달되지 않은 상태로 두고, FNOP, 이는 FPU 명령이기 때문에 암시적 "대기"를 수행하여 부동 소수점 예외가 전달됩니다.

이 예에서는 차이점을 보여줍니다.

FLD1       ; push 1.0 onto the FPU stack
FLDZ       ; push 0.0
FDIV       ; divide 1.0 by 0.0
NOP        ; does nothing
NOP        ; does nothing
FNOP       ; signals a FP zero-divide exception and then does nothing
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top