You are on page 1of 39

Simulation of ARM Processor and Stack Operation

Your task for this lab is to write a program that extends the
simulation of the ARM processor and includes stack operations.
The program will have an array that represents the general ARM
registers, and a second multi-dimensional array that represents
memory. The program must also have allocated stack space within
the memory array.
The program will read content into the memory array from a file,
execute the instructions it finds in the array one instruction at a
time, and print the contents of the registers (including a program
counter) and stack after each instruction. Note, when printing the
stack do not print anything below the stack pointer, or above your
stack base.
The program will implement the following instructions: ADD,
ADDI, SUBI, LDUR, STUR, B, BL, BR. And at least on
Conditional Branch instruction.
Instructions in memory will use the assembly mnemonics rather
than binary op codes.
Instruction arguments will be register aliases (ex. X0, X1, X2, …)
memory locations in the memory array (100, 104, …), or
immediate values (#-3, #5, #0, …).
The program should use the specific address - 200, as the default
address for the
start instructions in memory.

© 2022 All Rights Reserved. Programming Exam Help


Load and store instructions will only use indirect addressing (ie. [Xn,
#nn] ).
Branch instructions will use immediate or register addressing.
The program can limit the number of registers available for use in
the program. At least 8 must be available, including X0, X1, X9,
X10, SP (X28), LR (X30). Additional registers may be implemented.
Data will be signed integers.
The Stack:

The stack must be at least 100 words deep. Make sure your stack will
not grow over your program/data area.
The program must have a check and a “Ran out of Stack Space/Stack
Overflow” error message.
Choose a high memory area for the stack.
The stack should grow down.
Stack memory locations should be on double word boundaries
(increment/decrement by 8).
Remember to initiate the stack pointer (SP) to the top of the stack.
Use BR XZR to halt the program.

Test Files:

© 2022 All Rights Reserved. Programming Exam Help


Students will create an input file to test their emulator. The program
must be able to read the name of the file as an argument

The instructions in the file to be executed must include:


At least one example of each instruction implemented.
At least 12 instructions.
Instructions to complete at least one loop.
At least one push and pop on the stack.
At least one function call.

Output

The output of the program will be a listing showing:

The current instruction


The values of any registers used in that instruction. Including the
Program Counter.
The portion of the stack which is in use – (note: this may be
limited to the current stack frame).
Additional information, such as the value of all registers, or other
useful items may be shown as well.
SAMPLE OUTPUT
Instruction executed: LDUR X0, XZR, #100

© 2022 All Rights Reserved. Programming Exam Help


Registers: X0 = 512, SP=1000, PC=204*
 
Stack: 1000: 98 ***

Hit enter for next instruction: >


 
Instruction executed: SUBI SP, SP, #8
 
Registers: SP=992, PC=208
 
Stack: 1000: 98

992: **
 
Hit enter for next instruction:>
 
Instruction executed: STUR X0, [SP, #0]
 
Registers: X0 = 512, SP=992, PC=212

© 2022 All Rights Reserved. Programming Exam Help


Stack: 1000: 4A
 
992: 512
 
Hit enter for next instruction: >

Solution:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
#define MEMORY_SIZE 1024 /* by default memory has size
1024 positions */
#define STACK_SIZE 256 /* size of stack */
#define FIELD_LEN 10 /* maximum length for an
instruction field string */
#define MAX_LINE_LEN 100 /* maximum length in a line */

© 2022 All Rights Reserved. Programming Exam Help


/* definition of the register numbers */
enum {
X0 = 0, X1, X2, X3, X4, X5, X6, X7, X8, X9,
X10, X11, X12, X13, X14, X15, X16, X17, X18, X19,
X20, X21, X22, X23, X24, X25, X26, X27, X28, X29,
X30, X31, SP = 28, FP, LR, XZR

};
 
/**
* Returns the last character in the string
*/
char lastchar(char *str)
{
return (str[strlen(str) - 1]);
}
 
/**
* Returns 1 if the given character represents a decimal digit, 0 otherwise
*/
int is_digit(char c)
{

© 2022 All Rights Reserved. Programming Exam Help


return (c >= '0' && c <='9');
}
 
/**
* Returns 1 if the given character represents a whitespace char, 0
otherwise
*/
int is_space(char c)
{
return (c == ' ' || c == '\r' || c == '\n' || c == '\t'
|| c == '\v' || c == '\f');
}

/**
* Copies the string str2 to str1 removing the first char if fst=1 and
* removing the last char is lst = 1
*/
void copytrim(char *str1, char *str2, int fst, int lst)
{

© 2022 All Rights Reserved. Programming Exam Help


if (fst == 1)
str2++;
strcpy(str1, str2);
if (lst == 1)
str1[strlen(str1) - 1] = 0;
}
 

/**
* Check if a string represents a valid int
*/
int valid_int(char *str)
{
int i = 0;

if (str[0] == '-' || str[0] == '+')


i++;
for (; i < strlen(str); i++)
if (!is_digit(str[i])) /* if not a digit, is not a number
*/
return 0;
return (1);
}

© 2022 All Rights Reserved. Programming Exam Help


 
/**
* Split the instruction line by spaces, save the instruction in
memory
*/
int save_instruction(char *inst,char mem[MEMORY_SIZE]
[FIELD_LEN], int nline)
{
char *ptr;
int nparts;
int address;
 
ptr = strtok(inst, " "); /* split string using spaces */
if (ptr == NULL) /* if can't split */
{
fprintf(stderr, "Error: line %d: invalid instruction format\n", nline
+ 1);
return (-1); /* return error */
}
/* try to get the address */
if (sscanf(ptr, "%d", &address) != 1 || address <0 ||
address >= MEMORY_SIZE || (address & 3)) /* if error or
invalid address */
{

© 2022 All Rights Reserved. Programming Exam Help


fprintf(stderr, "Error: line %d: invalid address\n", nline + 1);

return (-1); /* return error */


}

ptr = strtok(NULL, " "); /* split next part using spaces */


nparts = 0; /* no parts initially */
while (ptr != NULL)
{
if (nparts >= 4) /* if too many parts */
{
fprintf(stderr, "Error: line %d: invalid instruction
format\n", nline + 1);
return (-1);
}

if (strlen(ptr) > FIELD_LEN) /* if field is too long */


{
fprintf(stderr, "Error: line %d: instruction field %d is too
long\n", nline + 1, nparts + 1);

return (-1);
}

© 2022 All Rights Reserved. Programming Exam Help


strcpy(mem[address + nparts], ptr); /* save field in memory */
nparts++; /* we have one more part */
ptr = strtok(NULL, " "); /* split next part of string using
spaces */
}
if (nparts == 0)
{
fprintf(stderr, "Error: line %d: invalid instruction format\n",
nline + 1);
return (-1);
}

if (address < 200) /*if data address*/


{
/* check for valid number */
if (!valid_int(mem[address]))
{
fprintf(stderr, "Error: line %d: invalid data\n", nline + 1);
return (-1);
}
}

© 2022 All Rights Reserved. Programming Exam Help


return (0);
}
 
/**
* Load program code from a file and saves it in memory in the
addresses given
* as the first field in the line
*/

void load_program(char *filename, char mem[MEMORY_SIZE]


[FIELD_LEN])
{
FILE *f;
char buffer[MAX_LINE_LEN];
int nline;
 
f = fopen(filename, "rt"); /* open file for reading */
if (f == NULL) /* error opening */
{
fprintf(stderr, "Error: unable to open file \"%s\"\n", filename);
exit(EXIT_FAILURE);

© 2022 All Rights Reserved. Programming Exam Help


}
printf("Loading program from \"%s\"\n", filename);
 
/* read all lines in the file */
nline = 0; /* start at line 0 */
while (fgets(buffer, MAX_LINE_LEN, f) != NULL)
{
/* remove ending spaces and newline */
while (is_space(lastchar(buffer)))
buffer[strlen(buffer) - 1] = 0;
/* skip empty lines */
if (buffer[0] != 0)
{
/* save instruction in memory */
if (save_instruction(buffer, mem, nline) == -1) /* if error
*/

{
fclose(f); /* close file */
exit(EXIT_FAILURE);
}
}

© 2022 All Rights Reserved. Programming Exam Help


nline++; /* advance line number */
}
fclose(f); /* close the file */
}
 
 
/**
* Shows the contents of all changed registers
*/
void print_registers(int *regs, int *affected, int PC)
{
int i;
int first;
 
printf("Registers:\t");
 
first = 1;
for (i = 0; i < 31; i++)
{
if (affected[i])
{
if (!first)

© 2022 All Rights Reserved. Programming Exam Help


printf(", ");
switch (i)
{
case SP:
printf("SP");
break;
case FP:
printf("FP");
break;
case LR:
printf("LR");
break;
default:

printf("X%d", i);
}
printf("=%d",regs[i]);
first = 0;
}

}
if (!first)
printf(", ");
printf("PC=%d\n", PC);

© 2022 All Rights Reserved. Programming Exam Help


}
 
/**
* Prints the stack contents
*/
void print_stack(int sp, char memory[MEMORY_SIZE]
[FIELD_LEN], int memused[MEMORY_SIZE])
{
int addr;
int first;

printf("Stack:\t");

first = 1;
for (addr = MEMORY_SIZE; addr >= sp; addr-= 8)
{
if (!first)
printf(" \t");
printf("%6d: ", addr);
if (memused[addr])
printf("%d", atoi(memory[addr]));
printf("\n");
first = 0;
}

© 2022 All Rights Reserved. Programming Exam Help


if (first)
printf("\n");
}
 
/**
* Prints the memory
*/
void print_memory(char memory[MEMORY_SIZE]
[FIELD_LEN], int memused[MEMORY_SIZE])
{
int addr;
int first;

printf("Memory:\t");

first = 1;
for (addr = 0; addr < MEMORY_SIZE - STACK_SIZE; addr +=
4)
{
if (memused[addr])
{

© 2022 All Rights Reserved. Programming Exam Help


if (!first)
printf(" \t");
printf("%6d: ", addr);

printf("%d", atoi(memory[addr]));
printf("\n");
first = 0;
}
}
if (first)
printf("\n");
}
 
 
/**
* Gets the register number from the string if its a valid register Xn
* If not valid returns -1
*/
int get_register(char *reg)
{
int nreg;

© 2022 All Rights Reserved. Programming Exam Help


if (!strcmp(reg, "SP"))
nreg = SP;
else if (!strcmp(reg, "FP"))
nreg = FP;
else if (!strcmp(reg, "LR"))
nreg = LR;
else if (!strcmp(reg, "XZR"))
nreg = XZR;
else if (sscanf(reg, "X%d", &nreg) != 1)
return (-1);
if (nreg < 0 || nreg > 31)
return (-1);
return (nreg);
}
 
/**
* Simulates the program in memory starting at address 200
*
*/
void simulate_program(char memory[MEMORY_SIZE]
[FIELD_LEN])
{

© 2022 All Rights Reserved. Programming Exam Help


int PC;
int regs[32]; /* registers */
int affected[32]; /* registers affected */
int flagZ;
int memused[MEMORY_SIZE];
char *opcode, *op1, *op2, *op3;
char t1[FIELD_LEN];
char t2[FIELD_LEN];
char t3[FIELD_LEN];
int i;
int r1, r2, r3, r;
int halt;

PC = 200; /* start simulating at address 200 */

/* initialize registers */
for (i = 0; i < 32; i++)
{
regs[i] = 0;
affected[i] = 0;
}

© 2022 All Rights Reserved. Programming Exam Help


regs[SP] = MEMORY_SIZE; /* stack top at end of memory */
 
/* initialize memory used */
for (i = 0; i < MEMORY_SIZE; i++)
{
memused[i] = 0;
}
 
flagZ = 0; /* initialize flags */
 
printf("Starting simulation...\n");
halt = 0;
while (!halt) /* repeat until halt is found */
{

opcode = memory[PC]; /* fetch instruction */


op1 = memory[PC + 1]; /* fetch operands */
op2 = memory[PC + 2];
op3 = memory[PC + 3];
PC+=4; /* advance to next instruction */

© 2022 All Rights Reserved. Programming Exam Help


/* clear affected registers */
for (i = 0; i < 31; i++)
affected[i] = 0;

if (!strcmp(opcode, "ADD") || !strcmp(opcode, "ADDS"))


{
if (lastchar(op1) != ',' || lastchar(op2) != ',')
{
printf("\n<< Invalid instruction operand at address %d >>\
n", PC - 4);
halt = -1; /* halt simulation */
}
else
{
copytrim(t1, op1, 0, 1);
copytrim(t2, op2, 0, 1);
r1 = get_register(t1);
r2 = get_register(t2);
r3 = get_register(op3);
if (r1 == -1 || r2 == -1 || r3 == -1)
{

© 2022 All Rights Reserved. Programming Exam Help


printf("\n<< Invalid instruction operand at address
%d >>\n", PC - 4);
halt = -1; /* halt simulation */
}
else
{
r = regs[r2] + regs[r3];
/* if S instruction, update flag */
if (lastchar(opcode) == 'S')
flagZ = (r == 0);
 

if (r1 != XZR)
{
regs[r1] = r;
}
affected[r1] = 1;
affected[r2] = 1;
affected[r3] = 1;
}
}
}
else if (!strcmp(opcode, "ADDI") || !strcmp(opcode,
"ADDIS"))
{

© 2022 All Rights Reserved. Programming Exam Help


if (lastchar(op1) != ',' || lastchar(op2) != ',' || op3[0] != '#')
{
printf("\n<< Invalid instruction operand at address %d >>\n",
halt = -1; /* halt simulation */
}
else
{
copytrim(t1, op1, 0, 1);
copytrim(t2, op2, 0, 1);
copytrim(t3, op3, 1, 0);
r1 = get_register(t1);
r2 = get_register(t2);
if (r1 == -1 || r2 == -1 || !valid_int(t3))
{

printf("\n<< Invalid instruction operand at address


%d >>\n", PC - 4);
halt = -1; /* halt simulation */
}
else
{

© 2022 All Rights Reserved. Programming Exam Help


r3 = atoi(t3);
r = regs[r2] + r3;
/* if S instruction, update flag */
if (lastchar(opcode) == 'S')
flagZ = (r == 0);
if (r1 != XZR)
regs[r1] = r;
affected[r1] = 1;
affected[r2] = 1;
}
}
}
else if (!strcmp(opcode, "SUBI") || !strcmp(opcode,
"SUBIS"))
{

if (lastchar(op1) != ',' || lastchar(op2) != ',' ||


op3[0] !=
'#')
{
printf("\n<< Invalid instruction operand at
address %d
>>\n", PC - 4);
halt = -1; /* halt simulation */

© 2022 All Rights Reserved. Programming Exam Help


}
else
{
copytrim(t1, op1, 0, 1);
copytrim(t2, op2, 0, 1);
copytrim(t3, op3, 1, 0);
r1 = get_register(t1);
r2 = get_register(t2);
if (r1 == -1 || r2 == -1 || !valid_int(t3))
{
printf("\n<< Invalid instruction operand at address
%d >>\n", PC - 4);

halt = -1; /* halt simulation */


}
else
{
r3 = atoi(t3);
r = regs[r2] - r3;
/* if S instruction, update flag */
if (lastchar(opcode) == 'S')
flagZ = (r == 0);

© 2022 All Rights Reserved. Programming Exam Help


if (r1 != XZR)
regs[r1] = r;
affected[r1] = 1;
affected[r2] = 1;
}
}
}
else if (!strcmp(opcode, "LDUR"))
{
if (lastchar(op1) != ',' || lastchar(op2) != ',' || op2[0] != '['
|| op3[0] != '#' || lastchar(op3) != ']')
{

printf("\n<< Invalid instruction operand at address %d >>\n", PC - 4);


halt = -1; /* halt simulation */
}
else
{
copytrim(t1, op1, 0, 1);
copytrim(t2, op2, 1, 1);
copytrim(t3, op3, 1, 1);
r1 = get_register(t1);
r2 = get_register(t2);

© 2022 All Rights Reserved. Programming Exam Help


if (r1 == -1 || r2 == -1 || !valid_int(t3))
{
printf("\n<< Invalid instruction operand at address %d
>>\n", PC - 4);
halt = -1; /* halt simulation */
}
else
{
r3 = atoi(t3);

if (r2 == SP && (regs[r2] + r3 < MEMORY_SIZE -


STACK_SIZE))
{
printf("\n<< Stack overflow found at address %d
>>\n", PC - 4);
halt = -1; /* halt simulation */
}
else if (r2 == SP && ((regs[r2] + r3) & 7) != 0)
{
printf("\n<< Misaligned stack access found at address %d
>>\n", PC - 4);
halt = -1; /* halt simulation */
}
else if (regs[r2] + r3 < 0 || regs[r2] + r3 >=
MEMORY_SIZE

© 2022 All Rights Reserved. Programming Exam Help


|| ((regs[r2] + r3) & 3) != 0 /* if not aligned */
|| !valid_int(memory[regs[r2] + r3]))
{
printf("\n<< Invalid memory access found at
address %d >>\n", PC - 4);
halt = -1; /* halt simulation */
}
else
{
memused[regs[r2] + r3] = 1;
if (r1 != XZR)
regs[r1] = atoi(memory[regs[r2] + r3]);
affected[r1] = 1;
affected[r2] = 1;
}
}
}
}

else if (!strcmp(opcode, "STUR"))


{
if (lastchar(op1) != ',' || lastchar(op2) != ',' ||
op2[0] != '['
|| op3[0] != '#' || lastchar(op3) != ']')
{
printf("\n<< Invalid instruction operand at
address %d >>\n", PC - 4);

© 2022 All Rights Reserved. Programming Exam Help


halt = -1; /* halt simulation */
}
else
{
copytrim(t1, op1, 0, 1);
copytrim(t2, op2, 1, 1);
copytrim(t3, op3, 1, 1);
r1 = get_register(t1);
r2 = get_register(t2);
if (r1 == -1 || r2 == -1 || !valid_int(t3))
{
printf("\n<< Invalid instruction operand at address
%d >>\n", PC - 4);
halt = -1; /* halt simulation */

}
else
{
r3 = atoi(t3);
if (r2 == SP && (regs[r2] + r3 < MEMORY_SIZE
- STACK_SIZE))
{
printf("\n<< Stack overflow found at address %d
>>\n", PC - 4);
halt = -1; /* halt simulation */
}

© 2022 All Rights Reserved. Programming Exam Help


else if (r2 == SP && ((regs[r2] + r3) & 7) != 0)
{
printf("\n<< Misaligned stack access found at
address %d >>\n", PC - 4);
halt = -1; /* halt simulation */
}
else if (regs[r2] + r3 < 0 || regs[r2] + r3 >=
MEMORY_SIZE
|| ((regs[r2] + r3) & 3) != 0 /* if not aligned */
|| !valid_int(memory[regs[r2] + r3]))
{
printf("\n<< Invalid memory access found at
address %d >>\n", PC - 4);
halt = -1; /* halt simulation */
}
else
{
memused[regs[r2] + r3] = 1;
sprintf(memory[regs[r2] + r3], "%d", regs[r1]);
affected[r1] = 1;
affected[r2] = 1;
}
}

}
}

© 2022 All Rights Reserved. Programming Exam Help


else if (!strcmp(opcode, "B"))
{
if (!valid_int(op1))
{

printf("\n<< Invalid instruction operand at address %d >>\n",


PC - 4);
halt = -1; /* halt simulation */
}
else
{
r1 = atoi(op1);
if (r1 < 0 || r1 >= MEMORY_SIZE
|| (r1 & 3) != 0) /* if not aligned */
{
printf("\n<< Invalid memory access found at
address %d >>\n", PC - 4);
halt = -1; /* halt simulation */
}
else
{
PC = r1;
}
}
}

© 2022 All Rights Reserved. Programming Exam Help


else if (!strcmp(opcode, "BL"))
{
if (!valid_int(op1))
{
printf("\n<< Invalid instruction operand at address %d >>\
n", PC - 4);
halt = -1; /* halt simulation */
}
else
{
r1 = atoi(op1);
if (r1 < 0 || r1 >= MEMORY_SIZE
|| (r1 & 3) != 0) /* if not aligned */
{
printf("\n<< Invalid memory access found at address
%d >>\n", PC - 4);
halt = -1; /* halt simulation */
}
else
{
regs[LR] = PC;
PC = r1;
affected[LR] = 1;
}

© 2022 All Rights Reserved. Programming Exam Help


}
}

else if (!strcmp(opcode, "BR"))


{
r1 = get_register(op1);
if (r1 == -1)
{
printf("\n<< Invalid instruction operand at
address %d >>\n", PC - 4);
halt = -1; /* halt simulation */
}
else
{
if (regs[r1] < 0 || regs[r1] >= MEMORY_SIZE
|| (regs[r1] & 3) != 0) /* if not aligned */
{
printf("\n<< Invalid memory access found at
address %d >>\n", PC - 4);
halt = -1; /* halt simulation */
}

© 2022 All Rights Reserved. Programming Exam Help


else
{
PC = regs[r1];
affected[r1] = 1;
if (r1 == XZR)
halt = 1; /* BR XZR halts the program */
}

}
}
else if (!strcmp(opcode, "B.EQ"))
{
if (!valid_int(op1))
{
printf("\n<< Invalid instruction operand at address
%d >>\n", PC - 4);
halt = -1; /* halt simulation */
}
else
{
r1 = atoi(op1);
if (r1 < 0 || r1 >= MEMORY_SIZE
|| (r1 & 3) != 0) /* if not aligned */
{

© 2022 All Rights Reserved. Programming Exam Help


printf("\n<< Invalid memory access found
at address %d >>\n", PC - 4);
halt = -1; /* halt simulation */
}
else
{
if (flagZ)
PC = r1;
}
}
}

else if (!strcmp(opcode, "B.NE"))


{
if (!valid_int(op1))
{
printf("\n<< Invalid instruction operand at
address %d >>\n", PC - 4);
halt = -1; /* halt simulation */
}
else
{
r1 = atoi(op1);
if (r1 < 0 || r1 >= MEMORY_SIZE
|| (r1 & 3) != 0) /* if not aligned */

© 2022 All Rights Reserved. Programming Exam Help


{
printf("\n<< Invalid memory access found at
address %d >>\n", PC - 4);
halt = -1; /* halt simulation */
}
else
{
if (!flagZ)
PC = r1;
}
}
}

else /*if invalid opcode */


{
printf("\n<< Invalid instruction at
address %d >>\n", PC - 4);

halt = -1; /* halt simulation */


}
if (halt != -1)
{
printf("\nInstruction executed:\t%s %s %s %s\
n",opcode, op1, op2, op3);

© 2022 All Rights Reserved. Programming Exam Help


print_registers(regs, affected, PC);
print_stack(regs[SP], memory, memused);
print_memory(memory, memused);
printf("\nHit enter for next instruction: >");
fflush(stdout);
getchar();
}
}

printf("\nEnd of simulation\n");
}
int main(int argc, char **argv)
{
int i;
char memory[MEMORY_SIZE][FIELD_LEN]; /*
memory array */
/* by default use code.txt as the input file */
char *filename = "code.txt";

if (argc >= 2) /* if an input file was given */


filename = argv[1]; /* use it as the input filename */

© 2022 All Rights Reserved. Programming Exam Help


/* clear memory */
for (i = 0; i < MEMORY_SIZE; i++)
strcpy(memory[i], "0");

/* load program from file */


load_program(filename, memory);

/* simulate the program in memory */


simulate_program(memory);

return (EXIT_SUCCESS);
}

© 2022 All Rights Reserved. Programming Exam Help

You might also like