In: Computer Science
Calculator in Assembly Language (Please add comments to explain your steps)
Description:
You are responsible to implement several assembly functions to perform the simple arithmetic calculations for 2 64-bit integers. These functions will use the C function signature but the main logic within this function should be inline assembly code using the ASM block similar to the assembly example shown in class.
Program Specification:
1. long mult ( long op1, long op2 )
- Can’t use the MUL/IMUL instructions, meaning you use ADD repeatedly
- If there are overflow, return the overflowed values in RAX register
2. long XOR ( long op1, long op2 )
- xor will return the result of bit exclusive OR of op1 / op2
- can use XOR instruction
3. long rotate ( long op1, long direction, long number_of_bits )
- rotate will perform logical bit-rotation of input operand (op1)
- direction = 0 for left and 1 for right
- number_of_bits will dictate how many bits to rotate left or right
- you need to use rcl and rcr assembly instructions
4. long factorial ( long op1 )
- Input a positive integer (>0) and return the result of op1!
- Must use a loop in ASM to compute the result (no recursion)
Program Checklist:
You will submit p1_64.cpp on canvas and a file named readme.p1 text file with any comments (e.g Windows or macOS, 64-bit compilers that you use and what work or not work about your code). You MUST be able to compile and run the program from the command line. If I can't test your program, you're not going to get much credit for your work!
For #1, rewrite mult to use loop. For #2 & 3, write a new function using my examples as a good starting point. Also add 2 new printf() statements to print out the results similar to the others. For #4, rewrite the factorial C code with inline assembly code using a loop. Remember to add the “q” suffix for 64-bit to the assembly instructions.
Sample output in this sequence:
Operand 1 = 10 x000000000000000a Operand 2 = 5 x0000000000000005
Add(): 15 x000000000000000f
XOR(): 15 x000000000000000f
Mult(): 50 x0000000000000032
Mod(): 0 x0000000000000000
ShiftL: 320 x0000000000000140
ShiftR: 0 x0000000000000000
RotateL: 320 x0000000000000140
RotateR:-6341068275337658368 xa800000000000000
Fact(): 3628800 x0000000000375f00
p1sample.cpp
/* CS47 - Project #1 template */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* Example - add function */
long add (long op1, long op2)
{
long output=0;
asm
(
"movq %1, %%rax;"
"addq %2, %%rax;"
: "=a" (output)
: "r" (op1), "r" (op2)
:
); /* add the second operand to eax, eax has result */
return output;
}
/*
1. long mult (long op1, long op2)
- Cant use the MULQ/IMULQ instructions, meaning you use ADD repeatedly
- If there are overflow, return the overflowed values in EAX register
*/
long mult (long op1, long op2)
{
long output=0;
asm
(
"movq %1, %%rax;"
"imulq %2, %%rax;"
: "=a" (output)
: "r" (op1), "r" (op2)
:
); /* multiple the second operand to eax, eax has result */
return output;
}
/*
2. long mod (long op1, long op2)
- mod will return the remainder of op1 / op2
- can use IDIVQ instruction
*/
long mod (long op1, long op2)
{
long output=0;
long local_op2=op2;
asm
(
"movq %1, %%rax;"
"movq %2, %%rbx;"
"cdq;"
"idivq %%rbx;"
"movq %%rdx, %%rax;"
: "=a" (output)
: "r" (op1), "r" (local_op2)
:
);
return output;
}
/*
3. long shift (long op1, long direction, long number_of_bits)
- shift will perform arithmetic (SAR or SAL) bit-shifting of the input operand (op1)
- direction = 0 for left and 1 for right
- number_of_bits will dictate how many bits to shift left or right
*/
long shift (long op1, long direction, long number_of_bits)
{
long output=0;
long is_left = direction == 0 ? 1 : 0;
// printf("direction=%ld\n",is_left);
/* move first operand to eax */
/* move direction flag to ebx */
/* move bit count to ecx, but use cl only on sar or sal commands */
/* check if 0 (Left) */
/* shift right if not 0 */
asm
(
"movq %1, %%rax;"
"movq %2, %%rbx;"
"movq %3, %%rcx;"
"cmpq $1, %%rbx;"
"jz Shift_Left ;"
"sarq %%cl, %%rax ;"
"jmp done;"
"Shift_Left:"
"salq %%cl, %%rax;"
"done:"
: "=a" (output)
: "r" (op1), "r" (is_left), "r" (number_of_bits)
:
);
return output;
}
/*
4. int factorial ( int op1 )
- Input a positive integer (>0) and return the result of op1!
- Must use a loop to compute the result (no recursion)
*/
long factorial (long n)
{
if (n == 1)
return 1;
else
return n * factorial(n - 1);
}
int main(int argc, char** argv)
{
long op1, op2, result;
op1 = op2 = result = 0;
if (argc != 3)
{
printf("Usage: %s op1 op2 (two integers)\n", argv[0]);
return 1;
}
op1 = atol(argv[1]);
op2 = atol(argv[2]);
printf("Operand 1 = %ld x%016lx Operand 2 = %ld x%016lx\n", op1,op1,op2,op2);
result = add(op1, op2);
printf("Add():\t%10ld x%016lx\n", result, result);
result = mult(op1, op2);
printf("Mult():\t%10ld x%016lx\n", result, result);
if (op2 == 0)
{
printf("Mod Error: Divide by 0\n");
result = 0;
}
else
{
result = mod(op1, op2);
printf("Mod():\t%10ld x%016lx\n", result, result);
}
if (op2 < 0)
{
printf("Error: Shift count must be >= 0\n");
result = 0;
}
else
{
result = shift(op1, 0, op2);
printf("ShiftL:\t%10ld x%016lx\n", result, result);
result = shift(op1, 1, op2);
printf("ShiftR:\t%10ld x%016lx\n", result, result);
}
if (op1 <= 0)
{
printf("Error: Factorial input must be a positive integer >=1\n");
result = 0;
}
else
{
result = factorial(op1);
printf("Fact():\t%10ld x%016lx\n\n", result, result);
}
return 0;
}
For MacOS, open a terminal window and use the command "gcc -o calc p1sample.cpp" to compile. To run "./calc 2 3" or any 2 numbers as input. If gcc is not available replace it with "clang" as the compiler.
For Windows, install gcc in your system, you can install the 64-bit mingw from -> http://mingw-w64.org/doku.php (Links to an external site.)
Once it is install, you need to open a Windows command prompt, add the path by this command "PATH=c:\MinGW\bin;%PATH%" (e.g. assume c:\MinGW is the install directory). Afterward, if you type gcc -o calc.exe p1sample.cpp After a successful compile, you can run by "calc 2 3" or any 2 numbers
add(long, long):
push rbp
mov rbp, rsp
mov QWORD PTR [rbp-24], rdi
mov QWORD PTR [rbp-32], rsi
mov QWORD PTR [rbp-8], 0
mov rax, QWORD PTR [rbp-24]
mov rdx, QWORD PTR [rbp-32]
movq rax, %rax;addq rdx, %rax;
mov QWORD PTR [rbp-8], rax
mov rax, QWORD PTR [rbp-8]
pop rbp
ret
mult(long, long):
push rbp
mov rbp, rsp
mov QWORD PTR [rbp-24], rdi
mov QWORD PTR [rbp-32], rsi
mov QWORD PTR [rbp-8], 0
mov rax, QWORD PTR [rbp-24]
mov rdx, QWORD PTR [rbp-32]
movq rax, %rax;imulq rdx, %rax;
mov QWORD PTR [rbp-8], rax
mov rax, QWORD PTR [rbp-8]
pop rbp
ret
mod(long, long):
push rbp
mov rbp, rsp
mov QWORD PTR [rbp-24], rdi
mov QWORD PTR [rbp-32], rsi
mov QWORD PTR [rbp-8], 0
mov rax, QWORD PTR [rbp-32]
mov QWORD PTR [rbp-16], rax
mov rax, QWORD PTR [rbp-24]
mov rdx, QWORD PTR [rbp-16]
movq rax, %rax;movq rdx, %rbx;cdq;idivq %rbx;movq %rdx, %rax;
mov QWORD PTR [rbp-8], rax
mov rax, QWORD PTR [rbp-8]
pop rbp
ret
shift(long, long, long):
push rbp
mov rbp, rsp
mov QWORD PTR [rbp-24], rdi
mov QWORD PTR [rbp-32], rsi
mov QWORD PTR [rbp-40], rdx
mov QWORD PTR [rbp-8], 0
cmp QWORD PTR [rbp-32], 0
jne .L8
mov eax, 1
jmp .L9
.L8:
mov eax, 0
.L9:
mov QWORD PTR [rbp-16], rax
mov rax, QWORD PTR [rbp-24]
mov rdx, QWORD PTR [rbp-16]
mov rcx, QWORD PTR [rbp-40]
movq rax, %rax;movq rdx, %rbx;movq rcx, %rcx;cmpq $1, %rbx;jz Shift_Left ;sarq %cl, %rax ;jmp done;Shift_Left:salq %cl, %rax;done:
mov QWORD PTR [rbp-8], rax
mov rax, QWORD PTR [rbp-8]
pop rbp
ret
factorial(long):
push rbp
mov rbp, rsp
sub rsp, 16
mov QWORD PTR [rbp-8], rdi
cmp QWORD PTR [rbp-8], 1
jne .L12
mov eax, 1
jmp .L13
.L12:
mov rax, QWORD PTR [rbp-8]
sub rax, 1
mov rdi, rax
call factorial(long)
imul rax, QWORD PTR [rbp-8]
.L13:
leave
ret
.LC0:
.string "Usage: %s op1 op2 (two integers)\n"
.LC1:
.string "Operand 1 = %ld x%016lx Operand 2 = %ld x%016lx\n"
.LC2:
.string "Add():\t%10ld x%016lx\n"
.LC3:
.string "Mult():\t%10ld x%016lx\n"
.LC4:
.string "Mod Error: Divide by 0"
.LC5:
.string "Mod():\t%10ld x%016lx\n"
.LC6:
.string "Error: Shift count must be >= 0"
.LC7:
.string "ShiftL:\t%10ld x%016lx\n"
.LC8:
.string "ShiftR:\t%10ld x%016lx\n"
.LC9:
.string "Error: Factorial input must be a positive integer >=1"
.LC10:
.string "Fact():\t%10ld x%016lx\n\n"
main:
push rbp
mov rbp, rsp
sub rsp, 48
mov DWORD PTR [rbp-36], edi
mov QWORD PTR [rbp-48], rsi
mov QWORD PTR [rbp-8], 0
mov rax, QWORD PTR [rbp-8]
mov QWORD PTR [rbp-16], rax
mov rax, QWORD PTR [rbp-16]
mov QWORD PTR [rbp-24], rax
cmp DWORD PTR [rbp-36], 3
je .L15
mov rax, QWORD PTR [rbp-48]
mov rax, QWORD PTR [rax]
mov rsi, rax
mov edi, OFFSET FLAT:.LC0
mov eax, 0
call printf
mov eax, 1
jmp .L16
.L15:
mov rax, QWORD PTR [rbp-48]
add rax, 8
mov rax, QWORD PTR [rax]
mov rdi, rax
call atol
mov QWORD PTR [rbp-24], rax
mov rax, QWORD PTR [rbp-48]
add rax, 16
mov rax, QWORD PTR [rax]
mov rdi, rax
call atol
mov QWORD PTR [rbp-16], rax
mov rsi, QWORD PTR [rbp-16]
mov rcx, QWORD PTR [rbp-16]
mov rdx, QWORD PTR [rbp-24]
mov rax, QWORD PTR [rbp-24]
mov r8, rsi
mov rsi, rax
mov edi, OFFSET FLAT:.LC1
mov eax, 0
call printf
mov rdx, QWORD PTR [rbp-16]
mov rax, QWORD PTR [rbp-24]
mov rsi, rdx
mov rdi, rax
call add(long, long)
mov QWORD PTR [rbp-8], rax
mov rdx, QWORD PTR [rbp-8]
mov rax, QWORD PTR [rbp-8]
mov rsi, rax
mov edi, OFFSET FLAT:.LC2
mov eax, 0
call printf
mov rdx, QWORD PTR [rbp-16]
mov rax, QWORD PTR [rbp-24]
mov rsi, rdx
mov rdi, rax
call mult(long, long)
mov QWORD PTR [rbp-8], rax
mov rdx, QWORD PTR [rbp-8]
mov rax, QWORD PTR [rbp-8]
mov rsi, rax
mov edi, OFFSET FLAT:.LC3
mov eax, 0
call printf
cmp QWORD PTR [rbp-16], 0
jne .L17
mov edi, OFFSET FLAT:.LC4
call puts
mov QWORD PTR [rbp-8], 0
jmp .L18
.L17:
mov rdx, QWORD PTR [rbp-16]
mov rax, QWORD PTR [rbp-24]
mov rsi, rdx
mov rdi, rax
call mod(long, long)
mov QWORD PTR [rbp-8], rax
mov rdx, QWORD PTR [rbp-8]
mov rax, QWORD PTR [rbp-8]
mov rsi, rax
mov edi, OFFSET FLAT:.LC5
mov eax, 0
call printf
.L18:
cmp QWORD PTR [rbp-16], 0
jns .L19
mov edi, OFFSET FLAT:.LC6
call puts
mov QWORD PTR [rbp-8], 0
jmp .L20
.L19:
mov rdx, QWORD PTR [rbp-16]
mov rax, QWORD PTR [rbp-24]
mov esi, 0
mov rdi, rax
call shift(long, long, long)
mov QWORD PTR [rbp-8], rax
mov rdx, QWORD PTR [rbp-8]
mov rax, QWORD PTR [rbp-8]
mov rsi, rax
mov edi, OFFSET FLAT:.LC7
mov eax, 0
call printf
mov rdx, QWORD PTR [rbp-16]
mov rax, QWORD PTR [rbp-24]
mov esi, 1
mov rdi, rax
call shift(long, long, long)
mov QWORD PTR [rbp-8], rax
mov rdx, QWORD PTR [rbp-8]
mov rax, QWORD PTR [rbp-8]
mov rsi, rax
mov edi, OFFSET FLAT:.LC8
mov eax, 0
call printf
.L20:
cmp QWORD PTR [rbp-24], 0
jg .L21
mov edi, OFFSET FLAT:.LC9
call puts
mov QWORD PTR [rbp-8], 0
jmp .L22
.L21:
mov rax, QWORD PTR [rbp-24]
mov rdi, rax
call factorial(long)
mov QWORD PTR [rbp-8], rax
mov rdx, QWORD PTR [rbp-8]
mov rax, QWORD PTR [rbp-8]
mov rsi, rax
mov edi, OFFSET FLAT:.LC10
mov eax, 0
call printf
.L22:
mov eax, 0
.L16:
leave
ret