Interoperability with C and assignment 5
PhD Student
Fall 2017
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.
Skills needed
#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;
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;
}
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;
}
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;
}
}
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
#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;
}
// 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);
}
// 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
gcc -c ex2a.c
as ex2b.s -o ex2b.o
gcc ex2a.o ex2b.o -o ex2
To compile:
./ex2
To run:
Assignment 5 is quite large, so here's how I suggest you should approach part a:
Let's do this together for queueEmpty()
#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
// 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]);
}
}
// 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
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
An elaboration on things we saw today, and part b of assignment 5.