수학 하기

수학 하기

모든 계산은 레지스터 사이에서 이루어집니다. 산술 명령어는 목적지를 먼저 지정하고, 그 뒤에 읽어들일 두 개의 소스가 옵니다: 는 dest = src1 + src2를 의미합니다.

산술 연산
t2, t0, t1←add
t0 = 7t1 = 5+t2 = 12

t2에 t0 및 t1 위치를 추가합니다.

왼쪽에서 들어오는 두 개의 선은 t0와 t1이며, 항상 그 순서입니다. 실행되는 연산이 덧셈, 뺄셈, 곱셈, 나눗셈, 나머지 중 무엇이든 같은 형태로 들어옵니다. 두 개의 값이 들어가고, 하나의 연산이 일어나고, 하나의 결과가 오른쪽의 t2로 나옵니다. 이 t2를 먼저 지정하는 것은 결과가 거기에 저장되기 때문이며, 이는 이 단원의 모든 산술 명령어가 따르는 유일한 순서 규칙과 일치합니다.

더하기와 빼기

는 두 레지스터에 담긴 숫자를 가져와 그 합을 세 번째 레지스터에 저장합니다. 는 뺄셈에 대해 같은 일을 합니다: 은 t0 - t1을 계산합니다. 두 명령어 모두 레지스터에서만 읽습니다.

산술 등록
add t2, t0, t1 # t2 = t0 + t1
sub t2, t0, t1 # t2 = t0 - t1

알아둘 점: 레지스터는 32비트만 담을 수 있으므로 한계가 있습니다. 결과가 너무 커서 들어가지 않아도 오류는 발생하지 않습니다. 값은 조용히 되돌아가서 매우 낮은 숫자가 되고 실행은 계속됩니다. 일상적인 값은 이 한계에 도달하지 않지만, 한계에 대해 알아둘 가치는 있습니다.

두 번째 레지스터 대신 고정된 숫자를 사용하려면 즉시값을 뜻하는 문자 i를 추가합니다: 은 상수 1을 더합니다. subi는 없으므로 상수를 빼려면 음수를 더합니다: .

💡
는 상수를 더합니다. 는 두 개의 레지스터를 더합니다. 이 둘을 혼동하는 것이 초보자가 가장 흔히 하는 실수입니다.

곱하기와 나누기

은 두 레지스터를 곱합니다. 는 그것들을 정수로 나누고 소수 부분을 버리므로 7 / 2는 3이 됩니다. 은 나머지를 주므로 7 % 2는 1이 됩니다. 나눗셈은 절대 충돌을 일으키지 않습니다. 0으로 나누면 -1을 반환합니다.

곱하기, 나누기, 나머지
mul t2, t0, t1 # t2 = t0 * t1
div t2, t0, t1 # t2 = t0 / t1 (정수)
rem t2, t0, t1 # t2 = t0 % t1 (나머지)

전체 구성

두 숫자를 더하고 결과를 출력하세요
li t0, 7
li t1, 5
add t1, t0, t1 # t1 = 7 + 5 = 12
mv a0, t1 # 출력 서비스는 a0을 읽는다
li a7, 1
ecall
li a7, 10
ecall

은 7을 t0에 로드합니다. 는 5를 t1에 로드합니다. 은 그것들을 더하고 12를 t1에 씁니다. 은 결과를 a0에 복사합니다. print 서비스는 항상 a0에서 값을 읽기 때문입니다. 그런 다음 이 print-integer 서비스를 선택하고 이 그것을 실행합니다. 마지막으로 과 이 프로그램을 끝냅니다.

보너스: 시프트를 이용한 곱셈

인수가 2의 거듭제곱일 때는 보다 빠른 방법이 있습니다. (논리 왼쪽 시프트)은 레지스터의 비트를 왼쪽으로 옮기며, 시프트하는 각 위치가 값을 두 배로 만듭니다: 1만큼 시프트하면 2배, 2는 4배, 3은 8배입니다. 시프트는 곱셈보다 비용이 적게 들기 때문에 컴파일러는 자주 이것을 사용합니다.

이동 기능을 사용하여 8을 곱하기
li t0, 5 # 5부터 시작
# 왼쪽으로 3비트 시프트 (5 * 2^3 = 5 * 8)
sll a0, t0, 3 # a0 = 40
li a7, 1 # 정수 출력
ecall
li a7, 10
ecall

는 5를 t0에 넣습니다. 은 그 비트를 세 자리 왼쪽으로 시프트합니다. 각 자리가 값을 두 배로 만들므로 5는 세 번 두 배가 되어(5, 10, 20, 40) a0에 40이 들어갑니다. 나머지는 이전의 print 패턴을 따릅니다. 3을 1이나 2로 바꾸고 실행하기 전에 결과를 예측해 보세요.

시프트로 곱하기
5sll a0, t0, 0
×2 →
10sll a0, t0, 1
×2 →
20sll a0, t0, 2
×2 →
40sll a0, t0, 3
0
0
0
0
0
1
0
1

5를 0비트 왼쪽으로 시프트하면 5가 그대로 남습니다.

여덟 개의 상자는 그 위에 있는 숫자의 이진 형태이며, 각각 한 비트이고 평소처럼 왼쪽에서 오른쪽으로 읽습니다. 전체 행을 한 위치 왼쪽으로 시프트하는 것은 2를 곱하는 것과 같은 연산입니다. 어떤 진법에서든 숫자를 한 자리 왼쪽으로 옮기면 그 값에 그 진법을 곱하기 때문입니다. 이진법에는 두 개의 숫자만 있으므로 곱하는 수는 2입니다. 세 번 시프트하면 이것이 복합되어 8을 곱하는 것이 되며, 이는 이 숫자 5에 하는 것과 일치합니다.