시프트 명령 문서의 검증 코드다. if __name__ == "__main__": 아래가 자체 테스트다.
"""시프트 명령(SHL, SHR, SAL, SAR) 검증. 실행: python3 37_shift-instructions_verify.py
MASM이 없어 시프트·회전 명령을 파이썬 함수로 흉내 낸다(한 칸씩 n번 민다).
문서의 값과 추적 표의 답을 단언하고, 8비트 256가지 값을 모두 검사한다."""
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__":
# --- 빠른 곱셈 ---
assert shl(5, 1)[0] == 10
assert shl(5, 2)[0] == 20
# --- SHR로 나누기 ---
dl, _ = shr(80, 1); assert dl == 40
dl, _ = shr(dl, 2); assert dl == 10
# --- SAR은 부호를 지킨다 (-80 = B0h) ---
dl = (-80) & 0xFF; assert dl == 0xB0
dl, _ = sar(dl, 1); assert signed(dl) == -40 and dl == 0xD8
dl, _ = sar(dl, 2); assert signed(dl) == -10 and dl == 0xF6
# --- 11001111을 한 칸 오른쪽으로 ---
assert shr(0b11001111, 1) == (0b01100111, 1)
assert sar(0b11001111, 1) == (0b11100111, 1)
# --- 추적 표 (네 문제) ---
al, cf = shr(0x6B, 1); assert (al, cf) == (0x35, 1) # a
al, cf = shl(al, 3); assert (al, cf) == (0xA8, 1) # b
al, cf = sar(0x8C, 1); assert (al, cf) == (0xC6, 0) # c
al, cf = sar(al, 3); assert (al, cf) == (0xF8, 1) # d
# --- 예시로 보기 추적 표: 01101011을 한 칸씩 ---
assert shl(0b01101011, 1) == (0b11010110, 0)
assert shl(0b11010110, 1) == (0b10101100, 1)
assert shr(0b01101011, 1) == (0b00110101, 1)
# --- 8비트 전수 검사 ---
for x in range(256):
for n in range(0, 9):
# 왼쪽으로 n칸 = 2^n을 곱하고 8비트만 남긴다
assert shl(x, n)[0] == (x * 2 ** n) % 256
# 부호 없는 수를 오른쪽으로 n칸 = 2^n으로 나눈 몫
assert shr(x, n)[0] == x // 2 ** n
# 부호 있는 수를 산술 오른쪽으로 n칸 = 2^n으로 나누고 내림
assert signed(sar(x, n)[0]) == signed(x) // 2 ** n
if n >= 1:
# CF는 마지막으로 밀려 나간 비트
assert shl(x, n)[1] == (x >> (8 - n)) & 1
assert shr(x, n)[1] == (x >> (n - 1)) & 1
# 곱셈 결과가 8비트에 들어갈 때만 "곱하기 2"가 그대로 맞다
assert (shl(x, 1)[0] == x * 2) == (x < 128)
assert sal is shl # SAL은 SHL과 같은 명령이다
# 넘치는 예: 200을 한 칸 밀면 400이 아니라 144, CF = 1
assert shl(200, 1) == (144, 1)
# 부호 없는 200에 SAR을 쓰면 오히려 커진다: 228
assert sar(200, 1)[0] == 228
# 그림의 값을 수로 읽으면: 207 → 103 (SHR), -49 → -25 (SAR)
assert shr(207, 1)[0] == 103 and signed(207) == -49 and signed(sar(207, 1)[0]) == -25
# 음수에 SHR을 쓰면 부호가 깨진다: -80 → 88
assert shr(0xB0, 1)[0] == 88
# SAR의 내림: -5 >> 1 = -3 (0 쪽이 아니라 아래쪽으로)
assert signed(sar((-5) & 0xFF, 1)[0]) == -3
assert signed(sar(0xFF, 7)[0]) == -1 # -1은 아무리 밀어도 -1
# 카드
assert shl(0x3C, 2) == (0xF0, 0) # C2
assert shr(0xF0, 3) == (0x1E, 0)
assert shl(7, 3)[0] == 56 # 7 × 8
assert shl(3, 4)[0] + shl(3, 1)[0] == 54 # 3 × 18 = 3×16 + 3×2
assert shl(0x80, 1) == (0x00, 1)
# 32비트: 123 × 36 = 123×32 + 123×4
assert shl(123, 5, 32)[0] + shl(123, 2, 32)[0] == 123 * 36
print("ALL CHECKS PASSED")