×
Samples Blogs Make Payment About Us Reviews 4.9/5 Order Now

Game Of Life Simulation in ARM Assembly Language Assignment Solution

July 01, 2024
Rehana Magnus
Rehana Magnus
🇨🇦 Canada
Assembly Language
Rehana Magnus, PhD in Computer Science from the esteemed Acadia Institute of Technology, Canada. With 6 years of experience, specializes in assembly language programming. Proficient in low-level coding, optimizing performance, and enhancing system functionality.
Key Topics
  • Instructions
  • Requirements and Specifications
Tip of the day
Use modular coding in Verilog assignments by breaking the design into smaller modules. This improves readability, simplifies debugging, and allows for easier testing and reuse of code components in larger designs.
News
In 2024, Visual Studio Code now offers enhanced GitHub Copilot integration for faster, while PyCharm has improved debugging and testing tools, making it ideal for Python students​

Instructions

Objective
After the blip in the Marvel Universe https://marvelcinematicuniverse.fandom.com/wiki/Blip, we can’t couldn’t remember if we’d given you this assignment before. So we are redoing
assignment 4, but in assembly!In Assignment 4, you wrote a program to simulate The Game of Life in C. For this assignment, you will be implementing doRow function from that assignment but in assembly. If your doRow does not work as specified below and/or does not work, you should start by fixing your C code. Even if your original C code for doRow works it may be worthwhile to consider how to simplify it for assembly.
  • Write your code in doRow.S .
  • Assume non-degenerate input.
  • We have provided correct implementations of the other Life functions as library.
functions. Your version of doRow MUST work with our library function simLoop.
Look at Assignment 6 and the Style Guide for examples to write/modify the prolog and
epilog.
  • The parameters doRow will receive from our version of simLoop are exactly as outlined below. [See Assignment 4 writeup for full details on Life]
  • Remember to push and pop to the stack as per calling convention

Requirements and Specifications

In order to run your program, you MUST ssh into the pi-cluster from ieng6 or be on a campus network or VPN. Both your ieng6 and pi cluster account share the same files, so anything you copy onto the lab machines (scp to ieng6) will ALSO be on the pi-cluster when you ssh in. GIT only works from ieng6 since the pi-cluster is on an internal network.
From Your Personal Computer :
  1. Open a Terminal
  2. ssh into your ieng6 account
  3. git clone the starter code (link)
  4. ssh into the pi-cluster using the following command:
  5. $ ssh @pi-cluster

    ex: $ ssh cs30sp20xx@pi-cluster

  6. You are ready to start! (REMEMBER: To do your ARM assignment you need to get back to your local machine!)
Source Code
A4 sim(do row function)
/**
 * Assignment: life
 * Name: Ramtin Kazemi
 * PID: A16567965
 * Class: UCSD CSE30-SP21
 *
 */
#include <sim.h>
#define CIMP
extern void asm_doRow(belem*, belem*, size_t, size_t, size_t);
/**
 * gets x mod N (works for negative numbers as well! Use this instead of %)
 */
size_t getModVal(int x, size_t N) {
  size_t adj = x / N;
  return ((x + adj * N) % N);
}
/**
 * process one row of the board
 */
static void doRow(belem* dest, belem* src, size_t row, size_t rows,
                  size_t cols) {
  for (int i = 0; i < cols; i++) {
    int count = 0;
    if (row == 0) {
      if (src[(row + 1) * cols + i] - '0') {
        count++;
      }
      if (src[(rows - 1) * cols + i] - '0') {
        count++;
      }
      if (i == 0 || i > cols - 1) {
        if (src[row * cols + i + 1] - '0') {
          count++;
        }
        if (src[rows - 1 * cols + i + 1] - '0') {
          count++;
        }
        if (src[row + 1 * cols + i + 1] - '0') {
          count++;
        }
        if (i == 0) {
          if (src[row * cols + cols - 1] - '0') {
            count++;
          }
          if (src[rows - 1 * cols + cols - 1] - '0') {
            count++;
          }
          if (src[row + 1 * cols + cols - 1] - '0') {
            count++;
          }
        } else {
          if (src[row * cols + i - 1] - '0') {
            count++;
          }
          if (src[row + 1 * cols + i - 1] - '0') {
            count++;
          }
          if (src[rows - 1 * cols + i - 1] - '0') {
            count++;
          }
        }
      } else if (i == cols - 1) {
        if (src[row * cols + i - 1] - '0') {
          count++;
        }
        if (src[row + 1 * cols + i - 1] - '0') {
          count++;
        }
        if (src[rows - 1 * cols + i - 1] - '0') {
          count++;
        }
        if (src[0 * cols + 0] - '0') {
          count++;
        }
        if (src[rows - 1 * cols + 0] - '0') {
          count++;
        }
        if (src[1 * cols + 0] - '0') {
          count++;
        }
      }
    } else if (row == rows - 1) {
      if (src[row - 1 * cols + i] - '0') {
        count++;
      }
      if (src[0 * cols + i] - '0') {
        count++;
      }
      if (i == 0 || i > cols - 1) {
        if (src[row * cols + i + 1] - '0') {
          count++;
        }
        if (src[row - 1 * cols + i + 1] - '0') {
          count++;
        }
        if (src[0 * cols + i + 1] - '0') {
          count++;
        }
        if (i == 0) {
          if (src[0 * cols + cols - 1] - '0') {
            count++;
          }
          if (src[row - 1 * cols + cols - 1] - '0') {
            count++;
          }
          if (src[row * cols + cols - 1] - '0') {
            count++;
          }
        } else {
          if (src[row * cols + i - 1] - '0') {
            count++;
          }
          if (src[row - 1 * cols + i - 1] - '0') {
            count++;
          }
          if (src[0 * cols + i - 1] - '0') {
            count++;
          }
        }
      } else if (i == cols - 1) {
        if (src[row * cols + i - 1] - '0') {
          count++;
        }
        if (src[0 * cols + i - 1] - '0') {
          count++;
        }
        if (src[row - 1 * cols + i - 1] - '0') {
          count++;
        }
        if (src[0 * cols + 0] - '0') {
          count++;
        }
        if (src[row - 1 * cols + 0] - '0') {
          count++;
        }
        if (src[row * cols + 0] - '0') {
          count++;
        }
      }
    } else {
      if (src[row + 1 * cols + i] - '0') {
        count++;
      }
      if (src[rows - 1 * cols + i] - '0') {
        count++;
      }
      if (i == 0 || i > cols - 1) {
        if (src[row * cols + i + 1] - '0') {
          count++;
        }
        if (src[row - 1 * cols + i + 1] - '0') {
          count++;
        }
        if (src[row + 1 * cols + i + 1] - '0') {
          count++;
        }
        if (i == 0) {
          if (src[row * cols + cols - 1] - '0') {
            count++;
          }
          if (src[row - 1 * cols + cols - 1] - '0') {
            count++;
          }
          if (src[row + 1 * cols + cols - 1] - '0') {
            count++;
          }
        } else {
          if (src[row * cols + i - 1] - '0') {
            count++;
          }
          if (src[row + 1 * cols + i - 1] - '0') {
            count++;
          }
          if (src[rows - 1 * cols + i - 1] - '0') {
            count++;
          }
        }
      } else if (i == cols - 1) {
        if (src[row * cols + i - 1] - '0') {
          count++;
        }
        if (src[row + 1 * cols + i - 1] - '0') {
          count++;
        }
        if (src[row - 1 * cols + i - 1] - '0') {
          count++;
        }
        if (src[row * cols + 0] - '0') {
          count++;
        }
        if (src[rows - 1 * cols + 0] - '0') {
          count++;
        }
        if (src[row + 1 * cols + 0] - '0') {
          count++;
        }
      }
    }
    if (src[row * cols + i] - '0') {
      if (count == 0 || count == 1) {
        dest[row * cols + i] = '0';
      } else if (count >= 4) {
        dest[row * cols + i] = '0';
      }
    } else {
      if (count == 3) {
        dest[row * cols + i] = '1';
      }
    }
  }
}
/**
 * perform a simulation for "steps" generations
 *
 * for steps
 * calculate the next board
 * swap current and next
 */
void simLoop(boards_t* self, unsigned int steps) {
  for (int i = 0; i < steps ; i++) { //Make: warning: comparison of integer expressions of different signedness: 'int' and 'size_t'??
    for (size_t j = 0; j < self->numRows; j++) {
      doRow(self->nextBuffer, self->currentBuffer, j, self->numRows,
            self->numCols);
    }
    swapBuffers(self);
    self->gen++;
  }
}
A4 Board
/**
 * Assignment: life
 * Name : Ramtin Kazemi
 * PID: A16567965
 * Class: UCSD CSE30-SP21
 *
 */
#include "cse30life.h"
#include "board.h"
/**
 * create a new board
 *
 * - malloc a boards structure
 * - set the generation to 0
 * - open the file (if it doesn't exist, return a NULL pointer
 * - read the first line which is the number of rows
 * - read the second line which is the number of cols
 * - set the # of rows and # of cols in the boards structure
 * - malloc bufferA and bufferB
 * - Set currentBuffer and nextBuffer
 * - clear both board buffers
 * - read the file until done. each row contains a row and a columns separted
 * by
 * white space
 * for each line, set the cell in the current buffer
 * - close the file
 * - return the boards pointer if successfull or NULL ptr otherwise
 */
boards_t *createBoard(char *initFileName) {
  boards_t *board = malloc(sizeof(boards_t));
  FILE *file;
  if ((file = fopen(initFileName, "r")) == NULL) {
    return NULL;
  }
  int temp = 0,temp1 = 0, num1 = 0, num2 = 0;
  fscanf(file, "%d", &temp);
  board->numCols = 0;
  board->numRows=0;
  if(temp<3){
    return NULL;
  }
  fgetc(file);
  fscanf(file, "%d", &temp1);
  if(temp1<3){
    return NULL;
  }
  board->numCols = temp1;
  board->numRows = temp;
  //causd memory leak!
  board->bufferA =malloc(sizeof(belem) * (board->numCols * board->numRows));
  //caused memory leak!
  board->bufferB =malloc(sizeof(belem) * (board->numCols * board->numRows));
  board->gen = 0;
  clearBoards(board);
  board->currentBuffer = board->bufferA;
  board->nextBuffer = board->bufferB;
  while (fscanf(file, "%d%d", &num1, &num2) > 0) {
    size_t index = getIndex(board->numCols,num1,num2);
    board->currentBuffer[index] = '1';
    board->nextBuffer[index]='1';
    fgetc(file);
  }
  fclose(file);
  file=NULL;
  free(file);
  initFileName=NULL;
  free(initFileName);
  return board;
}
/**
 * delete a board
 */
void deleteBoard(boards_t **bptrPtr) {
  free((*bptrPtr)->bufferA);
  free((*bptrPtr)->bufferB);
  (*bptrPtr)->bufferA=NULL;
  (*bptrPtr)->bufferB=NULL;
  //GradeScope: allocs: 7 frees: 9 bytes allocated: 9370 errors: 2. fixed after taking out these two lines
  //free((*bptrPtr)->currentBuffer);
  //free((*bptrPtr)->nextBuffer);
  (*bptrPtr)->currentBuffer=NULL;
  (*bptrPtr)->nextBuffer=NULL;
  free(*bptrPtr);
  *bptrPtr = NULL;
}
/**
 * set all the belems in both buffers to 0
 */
void clearBoards(boards_t *self) {
  for (size_t i = 0; i < self->numRows; i++) {
    for (size_t j = 0; j < self->numCols; j++) {
      size_t r = getIndex(self->numCols,i,j);
      self->bufferA[r] = 0;
      self->bufferB[r] = 0;
    }
  }
}
/**
 * swap the current and next buffers
 */
void swapBuffers(boards_t *self) {
  //"no for loops are needed, just a regular temp swap as mentioned in the lecture week2 or 3"
  //for (size_t i = 0; i < self->numRows; i++) {
    //for (size_t j = 0; j < self->numCols; j++) {
      //size_t r = getIndex(self->numCols,i,j);
      belem *temp = NULL;
      temp = self->currentBuffer;
      self->currentBuffer = self->nextBuffer;
      self->nextBuffer = temp;
    //}
  //}
}
/**
 * get a cell index
 */
size_t getIndex(size_t numCols, size_t row, size_t col) {
  return (row * numCols + col); //given in the write up
}
doRow in ARM assembly language
 .arch armv7
 .cpu cortex-a53
 .equ NUL, 0
 .global asm_doRow
 // !!! SET FP_OFFSET TO THE NUMBER OF (SAVED REGISTERS -1 * 4)
 // TODO - ADJUST FOR CALLEE SAVED REGISTERS
 .equ FP_OFFSET, 32 // (# of saved regs - 1) * 4
 .equ NCOLS_OFFSET, 4 // number columns (5th parameter)
 // TODO - ALLOCATE LOCAL SPACE or PARAMETER SPACE
 // (you can save incoming parameters in either one)
 .equ LOCAL_SPACE, 0 // total local space
 .equ PARAM_SPACE, 0 // total param space
 // TODO define your local variable offsets here
 // offsets are referenced to the framepointer.
 .equ XX_OFFSET, 0
asm_doRow:
 push {r4-r10, fp, lr}
 add fp, sp, #FP_OFFSET
 sub sp, sp, #(LOCAL_SPACE + PARAM_SPACE)
 mov r4, r0 // save buffer pointers
 mov r5, r1
 mov r6, r2 // save row
 ldr r7, [fp, #NCOLS_OFFSET] // load cols
 // set cols and rows
 mov r0, r3
 mov r1, r7
 bl setNRowsNCols
 mov r7, #0 // for (col = 0; col < cols; col++) {
forCol:
 mov r8, #0 // count = 0;
 mov r9, #-1 // for (i = -1; i <= 1; i++) {
fori:
 mov r10, #-1 // for (j = -1; j <= 1; j++) {
forj:
 cmp r9, #0 // if (i != 0 || j != 0 ) {
 bne if1
 cmp r10, #0
 beq nextj
if1:
 // get index
 mov r0, r6 // load row
 add r0, r0, r9 // row + i
 mov r1, r7 // load col
 add r1, r1, r10 // col + j
 bl nGetIndexRC // index = nGetIndexRC(row+i, col+j);
 ldrb r1, [r5, r0] // load src[index]
 add r8, r8, r1 // count += src[index];
nextj:
 add r10, r10, #1 // j++
 cmp r10, #1 // repeat if j<=1
 ble forj
 add r9, r9, #1 // i++
 cmp r9, #1 // repeat if i<=1
 ble fori
 // get index
 mov r0, r6 // load row
 mov r1, r7 // load col
 bl nGetIndexRC // index = nGetIndexRC(row, col);
 ldrb r1, [r5, r0] // load src[index]
if2:
 cmp r1, #0 // if (src[index] != 0)
 beq else2
if3:
 cmp r8, #2 // if (count < 2) {
 bge elseif3
 mov r2, #0 // dest[index] = 0;
 b saveDest
elseif3:
 cmp r8, #4 // else if (count < 4) {
 bge else3
 mov r2, #1 // dest[index] = 1;
 b saveDest
else3:
 mov r2, #0 // else dest[index] = 0;
 b saveDest
else2:
if4:
 cmp r8, #3 // if (count == 3) {
 bne else4
 mov r2, #1 // dest[index] = 1;
 b saveDest
else4:
 mov r2, #0 // else dest[index] = 0;
saveDest:
 strb r2, [r4, r0] // save dest[index]
 add r7, r7, #1 // col++
 ldr r0, [fp, #NCOLS_OFFSET] // load cols
 cmp r7, r0 // if col < cols
 blt forCol // repeat for
 sub sp, fp, #FP_OFFSET
 pop {r4-r10, fp, lr}
 bx lr
Final program
/**
 * Assignment: life
 * Name: Ramtin Kazemi
 * PID: A16567965
 * Class: UCSD CSE30-SP21
 *
 */
#include <sim.h>
#define CIMP
extern void asm_doRow(belem *, belem *, size_t, size_t, size_t);
/**
 * gets x mod N (works for negative numbers as well! Use this instead of %)
 */
size_t getModVal(int x, size_t N){
     size_t adj = x/N;
     return((x+adj*N)%N);
}
/**
 * process one row of the board
 */
static void doRow(belem *dest, belem *src, size_t row, size_t rows, size_t cols){
 size_t col;
 int i,j;
 size_t r, c;
 size_t count;
 size_t index;
 for (col = 0; col < cols; col++) {
  count = 0;
  for (i = -1; i <= 1; i++) {
   r = getModVal(row + i, rows);
   for (j = -1; j <= 1; j++) {
    c = getModVal(col + j, cols);
    if (i != 0 || j != 0 ) {
     index = getIndex(cols, r, c);
     count += src[index];
    }
   }
  }
  index = getIndex(cols, row, col);
  if (src[index] != 0) {
   if (count < 2) {
    dest[index] = 0;
   }
   else if (count < 4) {
    dest[index] = 1;
   }
   else
    dest[index] = 0;
  }
  else {
   if (count == 3) {
    dest[index] = 1;
   }
   else
    dest[index] = 0;
  }
 }
}
/**
 * perform a simulation for "steps" generations
 *
 * for steps
 * calculate the next board
 * swap current and next
 */
void simLoop(boards_t *self, unsigned int steps){
 unsigned step;
 size_t row;
 for (step = 0; step < steps; step++) {
  for (row = 0; row < self->numRows; row++)
   doRow(self->nextBuffer, self->currentBuffer, row, self->numRows, self->numCols);
  swapBuffers(self);
  self->gen++;
 }
}

Related Samples

Explore our Assembly Language Assignments samples, meticulously crafted to demystify low-level programming. From basic instructions to intricate system calls, each sample elucidates hardware interactions and optimization strategies. Ideal for students delving into computer architecture and embedded systems, fostering proficiency in assembly programming.