회전 명령 문서의 검증 코드다. if __name__ == "__main__": 아래가 자체 테스트다.
"""회전 명령(ROL, ROR, RCL, RCR) 검증. 실행: python3 39_rotate-instructions_verify.py
MASM이 없어 시프트·회전 명령을 파이썬 함수로 흉내 낸다(한 칸씩 n번 민다).
문서의 값과 추적 표의 답을 단언하고, 8비트 전수 검사를 한다."""
def mask(bits):
return (1 << bits) - 1
def signed(x, bits=8):
"""비트열 x를 부호 있는 수(2의 보수)로 읽는다."""
return x - (1 << bits) if x >> (bits - 1) else x
def shl(x, n, bits=8, cf=0):
"""왼쪽 시프트(SHL = SAL). (결과, CF)를 돌려준다. 한 칸씩 n번 민다."""
for _ in range(n):
cf = (x >> (bits - 1)) & 1 # 밀려 나가는 맨 위 비트가 CF로 간다
x = (x << 1) & mask(bits) # 맨 아래 빈칸은 0
return x, cf
sal = shl # SAL은 SHL의 다른 이름이다
def shr(x, n, bits=8, cf=0):
"""논리 오른쪽 시프트. 맨 위 빈칸을 0으로 채운다."""
for _ in range(n):
cf = x & 1
x >>= 1
return x, cf
def sar(x, n, bits=8, cf=0):
"""산술 오른쪽 시프트. 맨 위 빈칸을 원래 부호 비트로 채운다."""
for _ in range(n):
cf = x & 1
x = (x >> 1) | (x & (1 << (bits - 1)))
return x, cf
def rol(x, n, bits=8, cf=0):
"""왼쪽 회전. 맨 위 비트가 CF와 맨 아래 비트 두 곳으로 간다."""
for _ in range(n):
cf = (x >> (bits - 1)) & 1
x = ((x << 1) & mask(bits)) | cf
return x, cf
def ror(x, n, bits=8, cf=0):
"""오른쪽 회전. 맨 아래 비트가 CF와 맨 위 비트 두 곳으로 간다."""
for _ in range(n):
cf = x & 1
x = (x >> 1) | (cf << (bits - 1))
return x, cf
def rcl(x, n, bits=8, cf=0):
"""CF를 낀 왼쪽 회전. CF가 맨 아래로 들어오고 맨 위 비트가 CF로 나간다."""
for _ in range(n):
out = (x >> (bits - 1)) & 1
x = ((x << 1) & mask(bits)) | cf
cf = out
return x, cf
def rcr(x, n, bits=8, cf=0):
"""CF를 낀 오른쪽 회전. CF가 맨 위로 들어오고 맨 아래 비트가 CF로 나간다."""
for _ in range(n):
out = x & 1
x = (x >> 1) | (cf << (bits - 1))
cf = out
return x, cf
def shld(dest, src, n, bits=16):
"""dest를 왼쪽으로 n칸 밀고, 빈 아래 칸을 src의 위쪽 n비트로 채운다. src는 그대로."""
cf = 0
for i in range(n):
cf = (dest >> (bits - 1)) & 1
incoming = (src >> (bits - 1 - i)) & 1
dest = ((dest << 1) & mask(bits)) | incoming
return dest, cf
def shrd(dest, src, n, bits=16):
"""dest를 오른쪽으로 n칸 밀고, 빈 위 칸을 src의 아래쪽 n비트로 채운다. src는 그대로."""
cf = 0
for i in range(n):
cf = dest & 1
incoming = (src >> i) & 1
dest = (dest >> 1) | (incoming << (bits - 1))
return dest, cf
if __name__ == "__main__":
# --- ROL ---
assert rol(0b11110000, 1) == (0b11100001, 1)
assert rol(0x3F, 4)[0] == 0xF3
# --- ROR ---
assert ror(0b11110000, 1) == (0b01111000, 0)
assert ror(0x3F, 4)[0] == 0xF3
# --- 추적 표 앞 묶음 (ROR, ROL) ---
al, cf = ror(0x6B, 1); assert (al, cf) == (0xB5, 1) # a
al, cf = rol(al, 3); assert (al, cf) == (0xAD, 1) # b
# --- RCL ---
bl, cf = 0x88, 0 # clc
bl, cf = rcl(bl, 1, cf=cf); assert (cf, bl) == (1, 0b00010000)
bl, cf = rcl(bl, 1, cf=cf); assert (cf, bl) == (0, 0b00100001)
# --- RCR ---
ah, cf = rcr(0x10, 1, cf=1); assert (cf, ah) == (0, 0b10001000)
# --- 추적 표 뒤 묶음 (RCR, RCL) ---
al, cf = rcr(0x6B, 1, cf=1); assert (al, cf) == (0xB5, 1) # a
al, cf = rcl(al, 3, cf=cf); assert (al, cf) == (0xAE, 1) # b
# stc 대신 clc였다면 rcr의 결과는 35h
assert rcr(0x6B, 1, cf=0) == (0x35, 1)
# 중간 단계 (문서의 추적 표)
assert rcl(0xB5, 1, cf=1) == (0x6B, 1)
assert rcl(0x6B, 1, cf=1) == (0xD7, 0)
assert rcl(0xD7, 1, cf=0) == (0xAE, 1)
# --- 8비트 전수 검사 ---
for x in range(256):
assert rol(x, 8)[0] == x and ror(x, 8)[0] == x # 8칸 돌면 제자리
for n in range(0, 9):
assert ror(rol(x, n)[0], n)[0] == x # 되돌릴 수 있다
assert bin(rol(x, n)[0]).count("1") == bin(x).count("1") # 잃는 비트가 없다
assert rol(x, n)[0] == ror(x, (8 - n) % 8)[0] # 왼쪽 n칸 = 오른쪽 8-n칸
assert rol(x, 4)[0] == ((x << 4) | (x >> 4)) & 0xFF # 4칸 = 위아래 니블 바꾸기
for c in (0, 1):
y, c2 = rcl(x, 9, cf=c); assert (y, c2) == (x, c) # CF까지 9칸이 한 바퀴
y, c2 = rcr(x, 9, cf=c); assert (y, c2) == (x, c)
y, c2 = rcl(x, 1, cf=c)
assert rcr(y, 1, cf=c2) == (x, c)
# RCL 1칸: 9비트 수 (CF,x)를 왼쪽으로 한 칸 돌린 것
nine = (c << 8) | x
nine = ((nine << 1) | (nine >> 8)) & 0x1FF
assert (y, c2) == (nine & 0xFF, nine >> 8)
# ROL 뒤의 CF는 새 맨 아래 비트, ROR 뒤의 CF는 새 맨 위 비트
for x in range(256):
y, c = rol(x, 1); assert c == y & 1
y, c = ror(x, 1); assert c == y >> 7
# 카드
assert rol(0x81, 1) == (0x03, 1)
assert ror(0x81, 1) == (0xC0, 1)
assert rcl(0x81, 1, cf=0) == (0x02, 1)
assert rcr(0x81, 1, cf=0) == (0x40, 1)
assert rol(0x26, 4)[0] == 0x62
# 두 바이트를 이어 한 칸 오른쪽으로: SHR 위 바이트, RCR 아래 바이트
hi, lo = 0x81, 0x03 # 8103h
hi, c = shr(hi, 1); lo, c = rcr(lo, 1, cf=c)
assert (hi << 8 | lo) == 0x8103 >> 1 == 0x4081
for v in range(0, 65536, 7):
hi, lo = v >> 8, v & 0xFF
hi, c = shr(hi, 1); lo, c2 = rcr(lo, 1, cf=c)
assert (hi << 8 | lo) == v >> 1 and c2 == v & 1
print("ALL CHECKS PASSED")