2016-11-30 1 views
2

Arduino를 사용하여 어셈블리에서 두 개의 8 비트 값 중 8 비트 평균을 계산하는 컴퓨터 과학 수업을위한 Atmel AVR 어셈블리에 함수를 작성해야합니다. 분기 명령을 사용하는 것은 허용되지 않습니다 (건너 뛸 수 있음). 어셈블리에서 두 개의 8 비트 값 중 8 비트 평균을 계산하려면 어떻게합니까?

내가 지금까지 무엇을 가지고 : 그것은 반환, 내가 69과 60의 평균을 계산해야 내 프로그램의 일부를 들어

.global average 
average: 
    add r24, r22 
    asr r24 
    ret 

-64 (64)는 누구나 알고 있나요 대신 어떻게 이 기능을 작동하게 만들까요? 어떤 도움이라도 대단히 감사 할 것입니다.

+3

정수 오버플로/회피를 피하면서 평균을내는 트릭 : http://stackoverflow.com/a/3816471/224132. 나는 오버플로없이 정수 평균을 찾아서 잠깐 후에 발견했습니다. 트릭을 알고 있었지만 기억할 수 없었기 때문입니다. 그것은 아마 서명 2뿐만 아니라 서명되지 않은 작동하지만, 확인하지 않았다. 원하는 경우 Google 검색 용어에 '서명 됨'을 입력하십시오. –

+0

내가 연결 한 대답은 서명 된 사람에게만 적용됩니다. 가장 높은 점수를 얻은 답변은 필요하지 않지만 ADD 및 ROR보다 많은 작업을 필요로합니다. 어쨌든 이것은 정수 트릭을 찾을 때 AVR asm으로 제한하지 않는다는 것을 보여줍니다. C에서는 AVR에 직접 구현하거나 컴파일러에 피드를 제공하고 어떻게 수행하는지 볼 수있는 많은 것을 찾을 수 있습니다. 예 : 이 중 일부는 유용합니다. https://graphics.stanford.edu/~seander/bithacks.html –

답변

10

트릭을 추가 한 다음 rotate-with-carry을 사용하여 9 비트 결과를 2로 나눈 다음 8 비트 결과를 레지스터에 남겨 둡니다.

두 개의 질문에 대한 답은 다음과 같습니다. first, second.

는 그

AVR의 구현은 :이 비트의 서명 또는 부호 해석 작동

add r24, r25  ; 9-bit result in C and r24 
    ror r24   ; rotate-through-carry, like x86's RCR instruction 

, 우리가하고있는 모든 추가의 9 비트 전체 결과에서 낮은 비트를 폐기하기 때문에 . 산술적 또는 논리적 인 시프트 선택이없고 랩 어라운드도 없습니다.

또한 점을 -infinity로 이동하여 나누는 것에 유의하십시오 (C의 정수 나누기 연산자처럼 0으로 잘리지 않음). 따라서 (1 + -2) >> 1-1입니다.


이 값은 함수가 아닌 매크로에 넣어야 할 정도로 충분히 작습니다. 대부분의 호출 사이트에서 2 개 이상의 명령어가 필요할 수 있으므로 인라인을 사용하면 2 단어의 CALL 대신 1 단어 RCALL instruction을 사용할 수 있어도 코드 크기가 절약됩니다.

+0

흥미 롭습니다. 그래서 x86에서 우리는'RCL'을 사용하여 같은 것을 달성 할 수 있습니다. 불행히도 컴파일러는이 최적화를 인식하지 못합니다. –

+0

@ LưuVĩnhPhúc : 예, 저는 더 큰 부호없는 타입으로 캐스팅 한 다음'>>'을 사용하는 것 이외에 C로 이것을 표현하는 법을 모르겠습니다. 아마도 컴파일러는 레지스터보다 넓은 유형의 경우 RCL로 다시 컴파일러를 최적화 할 수 없습니다. –

+0

RCL이 1이면 Intel (Skylake의 3)이 1uop 이상이므로 좁은 arg의 경우 64 비트 또는 32 비트 레지스터의 ADD + SHR이 Intel CPU보다 저렴합니다. MOVZX (또는 MOV)/ADD/SHR이 일반적으로 ADD + RCL을 상회해야합니다. 특히 제로 확장 MOV를 사용하면 비파괴 적으로 수행 할 수 있습니다. –

관련 문제