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{\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{\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"