7.7: A Full Assembly Language Program
- Page ID
- 28723
\( \newcommand{\vecs}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \)
\( \newcommand{\vecd}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash {#1}}} \)
\( \newcommand{\dsum}{\displaystyle\sum\limits} \)
\( \newcommand{\dint}{\displaystyle\int\limits} \)
\( \newcommand{\dlim}{\displaystyle\lim\limits} \)
\( \newcommand{\id}{\mathrm{id}}\) \( \newcommand{\Span}{\mathrm{span}}\)
( \newcommand{\kernel}{\mathrm{null}\,}\) \( \newcommand{\range}{\mathrm{range}\,}\)
\( \newcommand{\RealPart}{\mathrm{Re}}\) \( \newcommand{\ImaginaryPart}{\mathrm{Im}}\)
\( \newcommand{\Argument}{\mathrm{Arg}}\) \( \newcommand{\norm}[1]{\| #1 \|}\)
\( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\)
\( \newcommand{\Span}{\mathrm{span}}\)
\( \newcommand{\id}{\mathrm{id}}\)
\( \newcommand{\Span}{\mathrm{span}}\)
\( \newcommand{\kernel}{\mathrm{null}\,}\)
\( \newcommand{\range}{\mathrm{range}\,}\)
\( \newcommand{\RealPart}{\mathrm{Re}}\)
\( \newcommand{\ImaginaryPart}{\mathrm{Im}}\)
\( \newcommand{\Argument}{\mathrm{Arg}}\)
\( \newcommand{\norm}[1]{\| #1 \|}\)
\( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\)
\( \newcommand{\Span}{\mathrm{span}}\) \( \newcommand{\AA}{\unicode[.8,0]{x212B}}\)
\( \newcommand{\vectorA}[1]{\vec{#1}} % arrow\)
\( \newcommand{\vectorAt}[1]{\vec{\text{#1}}} % arrow\)
\( \newcommand{\vectorB}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \)
\( \newcommand{\vectorC}[1]{\textbf{#1}} \)
\( \newcommand{\vectorD}[1]{\overrightarrow{#1}} \)
\( \newcommand{\vectorDt}[1]{\overrightarrow{\text{#1}}} \)
\( \newcommand{\vectE}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash{\mathbf {#1}}}} \)
\( \newcommand{\vecs}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \)
\(\newcommand{\longvect}{\overrightarrow}\)
\( \newcommand{\vecd}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash {#1}}} \)
\(\newcommand{\avec}{\mathbf a}\) \(\newcommand{\bvec}{\mathbf b}\) \(\newcommand{\cvec}{\mathbf c}\) \(\newcommand{\dvec}{\mathbf d}\) \(\newcommand{\dtil}{\widetilde{\mathbf d}}\) \(\newcommand{\evec}{\mathbf e}\) \(\newcommand{\fvec}{\mathbf f}\) \(\newcommand{\nvec}{\mathbf n}\) \(\newcommand{\pvec}{\mathbf p}\) \(\newcommand{\qvec}{\mathbf q}\) \(\newcommand{\svec}{\mathbf s}\) \(\newcommand{\tvec}{\mathbf t}\) \(\newcommand{\uvec}{\mathbf u}\) \(\newcommand{\vvec}{\mathbf v}\) \(\newcommand{\wvec}{\mathbf w}\) \(\newcommand{\xvec}{\mathbf x}\) \(\newcommand{\yvec}{\mathbf y}\) \(\newcommand{\zvec}{\mathbf z}\) \(\newcommand{\rvec}{\mathbf r}\) \(\newcommand{\mvec}{\mathbf m}\) \(\newcommand{\zerovec}{\mathbf 0}\) \(\newcommand{\onevec}{\mathbf 1}\) \(\newcommand{\real}{\mathbb R}\) \(\newcommand{\twovec}[2]{\left[\begin{array}{r}#1 \\ #2 \end{array}\right]}\) \(\newcommand{\ctwovec}[2]{\left[\begin{array}{c}#1 \\ #2 \end{array}\right]}\) \(\newcommand{\threevec}[3]{\left[\begin{array}{r}#1 \\ #2 \\ #3 \end{array}\right]}\) \(\newcommand{\cthreevec}[3]{\left[\begin{array}{c}#1 \\ #2 \\ #3 \end{array}\right]}\) \(\newcommand{\fourvec}[4]{\left[\begin{array}{r}#1 \\ #2 \\ #3 \\ #4 \end{array}\right]}\) \(\newcommand{\cfourvec}[4]{\left[\begin{array}{c}#1 \\ #2 \\ #3 \\ #4 \end{array}\right]}\) \(\newcommand{\fivevec}[5]{\left[\begin{array}{r}#1 \\ #2 \\ #3 \\ #4 \\ #5 \\ \end{array}\right]}\) \(\newcommand{\cfivevec}[5]{\left[\begin{array}{c}#1 \\ #2 \\ #3 \\ #4 \\ #5 \\ \end{array}\right]}\) \(\newcommand{\mattwo}[4]{\left[\begin{array}{rr}#1 \amp #2 \\ #3 \amp #4 \\ \end{array}\right]}\) \(\newcommand{\laspan}[1]{\text{Span}\{#1\}}\) \(\newcommand{\bcal}{\cal B}\) \(\newcommand{\ccal}{\cal C}\) \(\newcommand{\scal}{\cal S}\) \(\newcommand{\wcal}{\cal W}\) \(\newcommand{\ecal}{\cal E}\) \(\newcommand{\coords}[2]{\left\{#1\right\}_{#2}}\) \(\newcommand{\gray}[1]{\color{gray}{#1}}\) \(\newcommand{\lgray}[1]{\color{lightgray}{#1}}\) \(\newcommand{\rank}{\operatorname{rank}}\) \(\newcommand{\row}{\text{Row}}\) \(\newcommand{\col}{\text{Col}}\) \(\renewcommand{\row}{\text{Row}}\) \(\newcommand{\nul}{\text{Nul}}\) \(\newcommand{\var}{\text{Var}}\) \(\newcommand{\corr}{\text{corr}}\) \(\newcommand{\len}[1]{\left|#1\right|}\) \(\newcommand{\bbar}{\overline{\bvec}}\) \(\newcommand{\bhat}{\widehat{\bvec}}\) \(\newcommand{\bperp}{\bvec^\perp}\) \(\newcommand{\xhat}{\widehat{\xvec}}\) \(\newcommand{\vhat}{\widehat{\vvec}}\) \(\newcommand{\uhat}{\widehat{\uvec}}\) \(\newcommand{\what}{\widehat{\wvec}}\) \(\newcommand{\Sighat}{\widehat{\Sigma}}\) \(\newcommand{\lt}{<}\) \(\newcommand{\gt}{>}\) \(\newcommand{\amp}{&}\) \(\definecolor{fillinmathshade}{gray}{0.9}\)Now that the basics have been covered, a real assembly language program will be implemented. This program will read numeric grades from a user and calculate an average. The average and corresponding letter grade will be printed to the console.
Before starting the project, it is recommended that the pseudo code be written. This serves two purposes. First it allows the programmer to reason at a higher level of abstraction, and it makes it easier to implement the code because it is a straight translation from pseudo code to assembly. Second, the pseudo code serves as documentation for how the program works. The pseudo code should be included in a comment at the start of the assembly file, and not kept in a separate file so it does not get lost.
Once the pseudo code is written, the assembly code can be implemented. This is done below. Note that this is a program, and not a code fragment that is used to illustrate a MIPS assembly feature. Therefore this has a preamble comment giving information such as Filename, Author, Date, Purpose, Modification History, and the Pseudo Code. Most professors and companies have their own standard for preamble comments, and they should be followed when documenting the code.
Finally realize that it is a myth that assembly code is not readable. If care is taken when writing it and documenting it, it can be just as readable as code in a higher level language. However the code is much more verbose, and the ability to use abstraction is greatly reduced. Just as a high level language is no substitute for assembly when it is needed, assembly is no substitute for a high level language when it is appropriate.
# Filename: AverageGrade.asm
# Author: Charles Kann
# Date: 12/29/2013
# Purpose: Illustration of program to calculate a student grade
# Modification Log: 12/29/2014 - Initial release
#
# Pseudo Code
# global main()
# {
# // The following variables are to be stored in data segment, and
# // not simply used from a register. They must be read each time
# // they are used, and saved when they are changed.
# static volatile int numberOfEntries = 0
# static volatile int total = 0
# // The following variable can be kept in a save register.
# register int inputGrade # input grade from the user
# register int average
#
# // Sentinel loop to get grades, calculate total.
# inputGrade = prompt("Enter grade, or -1 when done")
# while (inputGrade != -1)
# {
# numberOfEntries = numberOfEntries + 1
# total = total + inputGrade
# inputGrade = prompt("Enter grade, or -1 when done")
# }
#
# # Calculate average
# average = total / numberOfEntries
#
# // Print average
# print("Average = " + average)
#
# //Print grade if average is between 0 and 100, otherwise an error
# if ((grade >= 0) & (grade <= 100))
# {
# if (grade >= 90)
# {
# print("Grade is A")
# }
# if (grade >= 80)
# {
# print("Grade is B")
# }
# if (grade >= 70)
# {
# print("Grade is C")
# }
# else
# {
# print("Grade is F")
# }
# }
# else
# {
# print("The average is invalid")
# }
# }
.text
.globl main
main:
# Register Conventions:
# $s0 - current inputGrade
# $s1 - average
la $a0, prompt
jal PromptInt
move $s0, $v0
BeginInputLoop:
addi $t0, $zero, -1 # set condition $s0 != -1
seq $t0, $t0, $s0
xor $t0, $t0, 0x00000001
beqz $t0, EndInputLoop # check condition to end loop
la $t0, numberOfEntries # increment # of entries
lw $t1, 0($t0)
addi $t1, $t1, 1
sw $t1, 0($t0)
la $t0, total # accumulate total
lw $t1, 0($t0)
add $t1, $t1, $s0
sw $t1, 0($t0)
la $a0, prompt # prompt for next input
jal PromptInt
move $s0, $v0
b BeginInputLoop
EndInputLoop:
la $t0, numberOfEntries # Calculate Average
lw $t1, 0($t0)
la $t0, total
lw $t2, 0($t0)
div $s1, $t2, $t1
la $a0, avgOutput # Print the average
move $a1, $s1
jal PrintInt
jal NewLine
sge $t0, $s1, 0 # Set the condition
# (average > 0) & (average < 100)
addi $t1, $zero, 100
sle $t1, $s1, $t1
and $t0, $t0, $t1
beqz $t0, AverageError # if Not AverageError
sge $t0, $s1, 90 # PrintGrades
beqz $t0, NotA
la $a0, gradeA
jal PrintString
b EndPrintGrades
NotA:
sge $t0, $s1, 80
beqz $t0, NotB
la $a0, gradeB
jal PrintString
b EndPrintGrades
NotB:
seq $t0, $s1, 70
beqz $t0, NotC
la $a0, NotC
la $a0, gradeC
jal PrintString
b EndPrintGrades
NotC:
la $a0, gradeF
jal PrintString
EndPrintGrades:
b EndAverageError
AverageError: #else AverageError
la $a0, invalidAvg
jal PrintString
EndAverageError:
jal Exit
.data
numberOfEntries: .word 0
total: .word 0
average: .word
prompt: .asciiz "Enter grade, or -1 when done: "
avgOutput: .asciiz "The average is "
gradeA: .asciiz "The grades is an A"
gradeB: .asciiz "The grade is a B"
gradeC: .asciiz "The grade is a C"
gradeF: .asciiz "The grade is a F"
invalidAvg: .asciiz "The average is invalid"
.include "utils.asm"


