CPSC 355: Tutorial 13
Interoperability with C and assignment 5
PhD Student
Fall 2017
Outline
We'll be talking about how to approach assignment 5 (part a) today. It's quite long, so I want you to get started on it sooner rather than later.
Assignment 5
- Use static/global variables
- Interoperability with C
- Using command line arguments (we'll talk about this next day)
Skills needed
Assignment 5
#include <stdio.h>
#include <stdlib.h>
#define QUEUESIZE 8
#define MODMASK 0x7
#define FALSE 0
#define TRUE 1
/* Function Prototypes */
void enqueue(int value);
int dequeue();
int queueFull();
int queueEmpty();
void display();
/* Global Variables */
int queue[QUEUESIZE];
int head = -1;
int tail = -1;
Assignment 5
int main()
{
int operation, value;
do {
system("clear");
printf("### Queue Operations ###\n\n");
printf("Press 1 - Enqueue, 2 - Dequeue, 3 - Display, 4 - Exit\n");
printf("Your option? ");
scanf("%d", &operation);
switch (operation) {
case 1:
printf("\nEnter the positive integer value to be enqueued: ");
scanf("%d", &value);
enqueue(value);
break;
case 2:
value = dequeue();
if (value != -1)
printf("\nDequeued value is %d\n", value);
break;
case 3:
display();
break;
case 4:
printf("\nTerminating program\n");
exit(0);
default:
printf("\nInvalid option! Try again.\n");
break;
}
printf("\nPress the return key to continue . . . ");
getchar();
getchar();
} while (operation != 4);
return 0;
}
Assignment 5
void enqueue(int value)
{
if (queueFull()) {
printf("\nQueue overflow! Cannot enqueue into a full queue.\n");
return;
}
if (queueEmpty()) {
head = tail = 0;
} else {
tail = ++tail & MODMASK;
}
queue[tail] = value;
}
int dequeue()
{
register int value;
if (queueEmpty()) {
printf("\nQueue underflow! Cannot dequeue from an empty queue.\n");
return (-1);
}
value = queue[head];
if (head == tail) {
head = tail = -1;
} else {
head = ++head & MODMASK;
}
return value;
}
int queueFull()
{
if (((tail + 1) & MODMASK) == head)
return TRUE;
else
return FALSE;
}
Assignment 5
int queueEmpty()
{
if (head == -1)
return TRUE;
else
return FALSE;
}
void display()
{
register int i, j, count;
if (queueEmpty()) {
printf("\nEmpty queue\n");
return;
}
count = tail - head + 1;
if (count <= 0)
count += QUEUESIZE;
printf("\nCurrent queue contents:\n");
i = head;
for (j = 0; j < count; j++) {
printf(" %d", queue[i]);
if (i == head) {
printf(" <-- head of queue");
}
if (i == tail) {
printf(" <-- tail of queue");
}
printf("\n");
i = ++i & MODMASK;
}
}
Assignment 5
For part a, you need to implement the functions
void enqueue(int value);
int dequeue();
int queueFull();
int queueEmpty();
void display();
In assembly, in a separate file (a5a.s)
This isn't too bad, let's see how to do this via example
Example
#include <stdio.h>
#include <stdlib.h>
int total_count = 0;
int threshold = 128;
int count_element(int element);
int main(int argc, char *argv) {
for(int i = 0; i < 15; i++) {
int value = rand() % 255;
printf("element %d = %d", i, value);
if(count_element(value)) {
printf(" > %d", threshold);
}
putchar('\n');
}
printf("There were %d elements > %d\n", total_count, threshold);
}
int count_element(int element){
if(element > threshold) {
total_count += 1;
return 1;
}
return 0;
}
Example
// File: ex2a.c
#include <stdio.h>
#include <stdlib.h>
int total_count = 0;
int threshold = 128;
int count_element(int element);
int main(int argc, char *argv) {
for(int i = 0; i < 15; i++) {
int value = rand() % 255;
printf("element %d = %d", i, value);
if(count_element(value)) {
printf(" > %d", threshold);
}
putchar('\n');
}
printf("There were %d elements > %d\n", total_count, threshold);
}
Example
// File: ex2b.s
// Author: Joshua Horacsel
// Contains the count element function
.global count_element // The .global count_element statement makes
// count_element visible to main
count_element:
// Setup a local stack frame
stp x29, x30, [sp, -16]!
mov x29, sp
// load the threshold into w1
adrp x1, threshold
add x1, x1, :lo12:threshold
ldr w1, [x1]
// load total_count into w3
adrp x2, total_count
add x2, x2, :lo12:total_count
ldr w3, [x2] // keep track of x2 (address to total count)
// Check if w0 (element) > w1(threshold)
cmp w0, w1
mov w0, wzr // set return val to 0
b.le end_count // if it's not, end
add w3, w3, 1 // add 1 to total count
str w3, [x2] // store it in x2 (address to total count)
mov w0, 1 // set return val to 1
end_count:
ldp x29, x30, [sp], 16
ret
Example
gcc -c ex2a.c
as ex2b.s -o ex2b.o
gcc ex2a.o ex2b.o -o ex2
To compile:
./ex2
To run:
How to approach A5
Assignment 5 is quite large, so here's how I suggest you should approach part a:
- Step 1: Copy all the source from the handout into the file "a5aMain.c", create a file "a5a.s".
- Step 2: Test the functionality of the code
- Step 3: Choose a function to translate into assembly (other than the main function, that needs to remain in C)
- Step 4: Comment that function out of a5aMain.c
- Step 5: Implement that function in a5a.s
- Step 6: Test functionality of your code (make sure you didn't break anything)
- Step 7: If there's anything left to write in assembly, go to step 3, otherwise you're done.
Let's do this together for queueEmpty()
Another Example
#include <stdio.h>
#include <stdlib.h>
#define NUM_VALS 10
int value_array[NUM_VALS];
void fill_array();
int main(int argc, char *argv) {
fill_array();
for(int i = 0; i < NUM_VALS; i++) {
printf("value_array[%d] = %d\n", i, value_array[i]);
}
}
void fill_array() {
register int i;
for(i = 0; i < NUM_VALS; i++) {
value_array[i] = rand() % 255;
}
}
Again, let's selectively translate this into assembly
Another Example
// File: ex3a.c
#include <stdio.h>
#include <stdlib.h>
#define NUM_VALS 10
int value_array[NUM_VALS];
void fill_array();
int main(int argc, char *argv) {
fill_array();
for(int i = 0; i < NUM_VALS; i++) {
printf("value_array[%d] = %d\n", i, value_array[i]);
}
}
Another Example
// File: ex3b.s
NUM_VALS = 10
.global fill_array
fill_array:
stp x29, x30, [sp, -32]!
mov x29, sp
str x19, [x29, 16] // Save x19 because we need to use it
str x20, [x29, 24] // Save x20
mov w19, wzr // init the counter to 0
// load the address of value_array into x1
adrp x20, value_array
add x20, x20, :lo12:value_array
loop_top:
bl rand
and w0, w0, 0xFF // w0 = rand() & 0xFF
str w0, [x20, w19, SXTW 2] // store w0 at address x1 + (w19 << 2)
// i.e. value_array[w19] = w0
add w19, w19, 1
loop_test:
cmp w19, NUM_VALS
b.lt loop_top
ldr x19, [x29, 16] // reload x19 for the calling function
ldr x20, [x29, 24] // reload x20 for the calling function
ldp x29, x30, [sp], 32
ret
Another Example
gcc ex3a.c ex3b.s -o ex3
Compiling (let's be a bit lazier this time):
./ex3
Running:
This should be all you need for part a of assignment 5
Next Day
An elaboration on things we saw today, and part b of assignment 5.
CPSC 355: Tutorial 13
By Joshua Horacsek
CPSC 355: Tutorial 13
- 2,072