-
Notifications
You must be signed in to change notification settings - Fork 16
/
cs241.tex
4282 lines (3859 loc) · 231 KB
/
cs241.tex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
\documentclass[]{article}
\usepackage[margin = 1.5in]{geometry}
\setlength{\parindent}{0in}
\usepackage{amsfonts}
\usepackage{amssymb}
\usepackage{amsmath}
\usepackage{amsthm}
\usepackage{mathtools}
\usepackage{tikz}
\usepackage{qtree}
\usepackage{float}
\usepackage[lined]{algorithm2e}
\usepackage[T1]{fontenc}
\usepackage{ae,aecompl}
\usepackage{color}
\usepackage[pdftex,
pdfauthor={Chris Thomson},
pdftitle={CS 241: Foundations of Sequential Programs},
pdfsubject={Lecture notes from CS 241 at the University of Waterloo},
pdfkeywords={CS 241, course notes, notes, Waterloo, University of Waterloo, MIPS, compilers, parsing, finite automata, theory},
pdfproducer={LaTeX},
pdfcreator={pdflatex}]{hyperref}
\usepackage{cleveref}
\DeclarePairedDelimiter{\set}{\lbrace}{\rbrace}
\definecolor{darkish-blue}{RGB}{25,103,185}
\hypersetup{
colorlinks,
citecolor=darkish-blue,
filecolor=darkish-blue,
linkcolor=darkish-blue,
urlcolor=darkish-blue
}
\theoremstyle{definition}
\newtheorem*{defn}{Definition}
\newtheorem*{theorem}{Theorem}
\newtheorem*{corollary}{Corollary}
\newtheorem{ex}{Example}[section]
\crefname{ex}{Example}{Example}
\setlength{\marginparwidth}{1.5in}
\newcommand{\lecture}[1]{\marginpar{{\footnotesize $\leftarrow$ \underline{#1}}}}
\makeatletter
\def\blfootnote{\gdef\@thefnmark{}\@footnotetext}
\makeatother
\begin{document}
\let\ref\Cref
\title{\bf{CS 241: Foundations of Sequential Programs}}
\date{Winter 2013, University of Waterloo \\ \center Notes written from Gordon Cormack's lectures.}
\author{Chris Thomson}
\blfootnote{I'd love to hear your feedback. Feel free to email me at \href{mailto:[email protected]}{[email protected]}.}
\blfootnote{See \href{http://cthomson.ca/notes}{cthomson.ca/notes} for updates.
\ifdefined\sha % Also, \commitDateTime should be defined.
Last modified: \commitDateTime{} ({\href{https://github.com/christhomson/lecture-notes/commit/\sha}{\sha}}).
\fi
}
\maketitle
\newpage
\tableofcontents
\newpage
\section{Introduction \& Character Encodings}
\lecture{January 7, 2013}
\subsection{Course Structure}
The grading scheme is 50\% final, 25\% midterm, and 25\% assignments. There are eleven assignments. Don't worry about any textbook. See the \href{https://www.student.cs.uwaterloo.ca/~cs241/W2013.pdf}{course syllabus} for more information.
\subsection{Abstraction}
\textbf{Abstraction} is the process of removing or hiding irrelevant details. Everything is just a sequence of bits (binary digits). There are two possible values for a bit, and those values can have arbitrary labels such as:
\begin{itemize}
\item Up / down.
\item Yes / no.
\item 1 / 0.
\item On / off.
\item Pass / fail.
\end{itemize}
Let's say we have four projector screens, each representing a bit of up/down, depending on if the screen has been pulled down or left up (ignoring states between up and down). These screens are up or down independently. There are sixteen possible combinations:
\begin{center}
\begin{tabular}{cccc}
\underline{Screen 1} & \underline{Screen 2} &\underline{Screen 3} & \underline{Screen 4} \\
Up (1) & Down (0) & Up (1) & Down (0) \\
Down (0) & Down (0) & Down (0) & Up (1) \\
\vdots & \vdots & \vdots & \vdots \\
\end{tabular}
\end{center}
Note that there are sixteen combinations because $k = 4$, and there are $2^k$ combinations since there are two possible values for each of $k$ screens.
\subsection{Endianness}
Let's consider the sequence $1010$. This sequence of bits has different interpretations when following different conventions.
\begin{itemize}
\item \textbf{Unsigned, little-endian}: $(1 \times 2^0) + (0 \times 2^1) + (1 \times 2^2) + (0 \times 2^3) = 1 + 4 = 5$.
\item \textbf{Unsigned, big-endian}: $(0 \times 2^0) + (1 \times 2^1) + (0 \times 2^2) + (1 \times 2^3) = 2 + 8 = 10$.
\item \textbf{Two's complement, little-endian}: $5$ (interpret as $0101$, so 0 is the two's complement sign bit). Similarly, $1011$ would be $-2^3 + 2^2 + 2^0 = -8 + 4 + 1 = -3$.
\item \textbf{Two's complement, big-endian}: $10 - 16 = -6$.
\item \textbf{Computer terminal}: LF (line feed).
\end{itemize}
Note that a two's complement number $n$ will satisfy $-2^{k-1} \le n < 2^{k-1}$.
\subsection{ASCII}
\textbf{ASCII} is a set of meanings for 7-bit sequences.
\begin{center}
\begin{tabular}{cc}
\underline{Bits} & \underline{ASCII Interpretation} \\
$0001010$ & LF (line feed) \\
$1000111$ & G \\
$1100111$ & g \\
$0111000$ & 8
\end{tabular}
\end{center}
In the last case, $0111000$ represents the character `$8$', not the unsigned big- or little-endian number $8$. \\ \\
ASCII was invented to communicate text. ASCII can represent characters such as A-Z, a-z, 0-9, and control characters like ();!. Since ASCII uses 7 bits, $2^7 = 128$ characters can be represented with ASCII. As a consequence of that, ASCII is basically only for Roman, unaccented characters, although many people have created their own variations of ASCII with different characters.
\subsection{Unicode}
\textbf{Unicode} was created to represent more characters. Unicode is represented as a 32-bit binary number, although representing it using 20 bits would also be sufficient. The ASCII characters are the first 128 symbols in Unicode, followed by additional symbols.
\\ \\
A 16-bit representation of Unicode is called \textbf{UTF-16}. However, there's a problem: we have \emph{many} symbols ($> 1M$) but only $2^{16} = 65,536$ possible ways to represent them. Common characters are represented directly, and there is also a `see attachment' bit for handling the many other symbols that didn't make the cut to be part of the $65,536$. Similarly, there is an 8-bit representation of Unicode called \textbf{UTF-8}, with the ASCII characters followed by additional characters and a `see attachment' bit.
\\ \\
The bits themselves do not have meaning. Their meaning is in your head -- everything is up for interpretation.
\subsection{A Message for Aliens} \lecture{January 9, 2013}
In a computer, meaning is in the eye of the beholder. We must agree on a common interpretation -- a convention. However, the English language and numbers also have their meaning determined by a set of conventions.
\\ \\
NASA wanted to be able to leave a message for aliens on a plaque on their spacecraft, however it was clear that aliens would not understand our language or even 0s and 1s. NASA wanted their message to be a list of prime numbers. They decided they would use binary to represent the numbers, but since 0s and 1s would be ambiguous to aliens, they used a dash (\textemdash) instead of 0, and 1 for 1. It's only a convention, but it's one that NASA determined aliens would have a higher chance of understanding.
\subsection{Hexadecimal}
Hexadecimal (hex) is base 16. It has sixteen case-insensitive digits: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, and f.
\\ \\
Why is hex useful? It makes conversions easy. We group bits into sequences of four:
\begin{align*}
\underbrace{\underbrace{0011}_{3} \underbrace{1010}_{\text A}}_{\text{3A}}
\end{align*}
Conversions are made especially easy when the sequences of bits are lengthy:
\begin{align*}
\underbrace{\underbrace{10}_{2} \underbrace{1110}_{\text E} \underbrace{0111}_{7} \underbrace{0011}_{3} \underbrace{1011}_{\text B} \underbrace{1001}_{9} \underbrace{1000}_{8} \underbrace{0011}_{3}}_{\text{2E73B983}}
\end{align*}
\section{Stored Program Computers}
Stored program computers are also known as the \textbf{Von Neumann architecture}. They group bits into standard-sized sequences.
\\ \\
In modern times, standard-sized sequences of bits are:
\begin{itemize}
\item \textbf{Bytes}. A byte is 8-bits (256 possible values). Example: 00111010.
\item \textbf{Words}. A word is only guaranteed to be ``more than a byte.'' Words are often 16-bits ($2^{16} = 65,536$ possible values), 32-bits ($2^{32} \approx 4 \times 10^9$), or 64-bits ($2^{64} \approx 10^{19}$).
\end{itemize}
A ``64-bit CPU'' just means it's a CPU that uses 64-bit words.
\subsection{Storage Devices}
\subsubsection{Registers}
There are typically a finite number of fixed-sized sequence of bits, called \textbf{registers}. You can put bits in, peek at them, and modify them.
\\ \\
Calculators typically have 2-3 registers for recalling numbers and maintaining state.
\\ \\
There are a couple of downsides to registers. They're expensive to build, which is why there is a finite number of them. They're also difficult to keep track of.
\subsubsection{RAM (Random Access Memory)}
RAM is essentially a physical array that has \textbf{address lines}, \textbf{data lines}, and \textbf{control lines}. Data is fed into RAM using electrical lines. Data will remain in RAM until overwritten.
\\ \\
If you want to place a happy face character at address 100, you set the address lines to 100, the data lines to 10001110 (which is the Unicode representation of a happy face), and give the control lines a kick.
\\ \\
RAM could be implemented in several different ways. It could even be created with a \textbf{cathode ray tube}. The \textbf{core} method is synonymous with RAM, however. It involves a magnetic core, and the data remains magnetized after the magnet is removed. Bits are read by toggling the state (toggling the magnetic poles) and seeing if it was easier to toggle than expected (similar to unlocking an already-unlocked door), and then toggling back after. No one really uses magnetic cores anymore.
\\ \\
\textbf{Capacitive memory} (also known as dynamic RAM or \textbf{DRAM}) is still used today. It involves an insulator and two conductive plates, one of which is more negatively-charged than the other. The electrons will remain in their state even when the poles are removed. There is a problem, however. Insulators are not perfect -- electrons will eventually make their way through the insulator. In order to alleviate this, we have to refresh the charge fairly often (every second, for instance).
\\ \\
\textbf{Switches} are typically used only for registers and cache. They produce more heat, but are much faster.
\subsection{Control Unit Algorithm}
The CPU contains a \textbf{control unit}, several \textbf{registers}, PC (\textbf{program counter}), and IR (\textbf{instruction register}), and is connected to RAM with electrical lines.
\begin{verbatim}
PC <- some fixed value (e.g. 0)
loop
fetch the word of RAM whose address is in PC, put it in IR
increment PC
decode and execute the machine instructon that's in IR
end loop
\end{verbatim}
IR would contain an instruction like ``add register 1 to register 2, and put the result into register 7.''
\section{First Steps with MIPS}
\lecture{January 11, 2013}
\subsection{Unix}
You'll need Unix to use MIPS in this course. Unix was originally created in the 1970s at AT\&T Bell Labs. Unix is still popular today, especially for servers. Linux is a Unix dialect, and Mac OS X is also based on Unix.
\\ \\
Unix has three types of files:
\begin{itemize}
\item \textbf{Binary files}. A sequence of arbitrary bytes.
\item \textbf{Text files}. A sequence of ASCII characters, with lines terminated by a LF / newline.
\item \textbf{Tools}. These are programs, which are technically binary files.
\end{itemize}
\subsubsection{Getting Access to a Unix System}
If you use Linux or Mac OS X, you're in good shape. However, Windows is not Unix-based, so you'll have to pursue one of these alternative options:
\begin{itemize}
\item Install Linux. You can dual-boot it alongside Windows if you'd like, or you could install it inside a virtual machine.
\item Install \href{http://www.cygwin.com/}{Cygwin}. When installing it, choose to install everything.
\item Login to the \verb+student.cs+ servers remotely. You can use \href{http://www.putty.org/}{PuTTY} for that.
\end{itemize}
\subsubsection{Commands You Should Know}
\begin{itemize}
\item \verb+ssh [email protected]+ -- logs you into the \verb+student.cs+ systems remotely through SSH.
\item \verb+cat unix_text_file.txt+ -- copies the contents of the file to the current terminal. If a non-text file is given to \verb+cat+, incorrect output will result.
\item \verb+xxd -b unix_file.txt+ -- prints the binary representation of the file to the terminal. The numbers in the left column are the locations in the file. If it's a Unix text file, the ASCII representation is presented on the right, with all non-printable characters printed as dots. \verb+xxd+ is not aware of newline characters -- it arbitrarily splits the file into 16 bytes per line.
\item \verb+xxd unix_file.txt+ -- prints the hex representation of the file to the terminal. Identical to the previous command (\verb+xxd -b+) in every other way.
\item \verb+ls -l+ -- lists all files in the current directory in the long-listing form, which shows the number of bytes in the file, permissions, and more.
\end{itemize}
\subsection{Getting Started with MIPS}
The MIPS CPU uses 32-bit words since it's a 32-bit machine, and it's big-endian. You can use \verb+xxd+ to inspect MIPS files. MIPS has 32 registers (numbered 0 to 31).
\\ \\
At the end of our MIPS programs, we will copy the contents of register \$31 to the program counter (PC) to ``return.''
\subsubsection{Running MIPS Programs}
Upon logging in to the \verb+student.cs+ servers, run \verb+source ~cs241/setup+ in order to add the required executables to your \verb+PATH+. Then, when given a MIPS executable called \verb+eg0.mips+, you can run \verb+java mips.twoints eg0.mips+ in order to run the program.
\\ \\
\verb+mips.twoints+ is a Java program that requests values for registers \$1 and \$2 and then runs the given MIPS program. There are other MIPS runner programs, such as \verb+mips.array+, which populate the 31 registers in different ways.
\subsubsection{Creating MIPS Programs}
Start with \verb+vi thing.asm+ (or use your favorite editor). Inside this file, you'll create an \textbf{assembly language file}, which is a textual representation of the binary file you want to create. Each line in this file should be in the form \verb+.word 0xabcdef12+ (that is, each line should start with \verb+.word 0x+ -- the \verb+0x+ is a convention that indicates that hex follows). You can add comments onto the end of lines, starting with a semi-colon (Scheme style).
\\ \\
Next, you'll need to convert your assembly language file into a binary file. You can do that by running \verb+java cs241.wordasm < thing.asm > thing.bin+. You can then inspect \verb+thing.bin+ with \verb+xxd+ in hex, or in binary if you're masochistic.
\\ \\
A few important things you should know for developing MIPS programs:
\begin{itemize}
\item \$0 is a register that will always contain 0. It's special like that.
\item \$30 points to memory that could be used as a stack.
\item \$31 will be copied to the program counter at the end of execution in order to ``return.''
\item You can specify register values using base 10 values or as hex values (if prefixed by \verb+0x+).
\item It takes 5-bits to specify a register in binary MIPS instructions, since $2^5 = 32$.
\item In documentation, it's conventional to call S and T \textbf{source registers}, and D the \textbf{destination register}.
\item MIPS uses two's complement numbers by default, unless specified otherwise.
\item Loops and conditionals are accomplished by adding or subtracting from the program counter.
\end{itemize}
There is a \href{https://www.student.cs.uwaterloo.ca/~cs241/mips/mipsref.pdf}{MIPS reference sheet} available on the course website that you'll find to be quite useful. It contains the binary representations for all MIPS instructions. You can convert the binary instructions into hex and place the instructions into an assembly language file as \verb+.word+ instructions.
\subsubsection{A Few Important MIPS Instructions}
\begin{enumerate}
\item \textbf{Load Immediate \& Skip} (\verb+lis+): loads the next word of memory into the D register. You specify a \verb+lis+ instruction followed by an arbitrary word next. The program counter will then skip past the arbitrary word that follows, to avoid executing it.
\item \textbf{Set Less Than [Unsigned]} (\verb+slt+): compares S to T. If S < T, 1 is put into the D register, otherwise 0 is put into the D register.
\item \textbf{Jump Register} (\verb+jr+): copies the value in the source register S to the program counter.
\item \textbf{Jump and Link Register} (\verb+jalr+): assigns the program counter to register 31, then jumps to it.
\item \textbf{Branch on Equal} (\verb+beq+): if S is equal to T, it adds the specified number to the program counter (times 4). There is also \textbf{Branch on Unequal} (\verb+bne+) which does the opposite.
\end{enumerate}
\subsubsection{MIPS Program Workflow}
\lecture{January 14, 2013}
The MIPS CPU understands \textbf{binary machine language programs}, however we cannot write them directly. Instead, we write \textbf{assembly language programs} in text files. By convention, we name these text files with the extension \verb+.asm+. Assembly language contains instructions like \verb+.word 0x00221820+. We feed the assembly language program into \verb+cs241.wordasm+, which is an \textbf{assembler}. An assembler translates assembly language into binary machine code that can be executed.
\\ \\
Assembly language can also look like this: \verb+add $3, $1, $2+. Assembly language in this form has to be fed into a different assembler (\verb+cs241.binasm+) that understands that flavor of assembly syntax.
\\ \\
There is a \href{https://www.student.cs.uwaterloo.ca/~cs241/mips/mipsasm.html}{MIPS reference manual} available on the course website. It might be useful in situations such as:
\begin{itemize}
\item When you want to be an assembler yourself. You'll need to lookup the mapping between assembly instructions like \verb+add $3, $1, $2+ and their binary equivalents.
\item When you need to know what's valid assembly code that an assembler will accept.
\item When you want to write your own assembler you'll need a specification of which instructions to handle.
\end{itemize}
\subsubsection{The Format of MIPS Assembly Language}
MIPS assembly code is placed into a Unix text file with this general format:
\begin{verbatim}
labels instruction comment
\end{verbatim}
\textbf{Labels} are any identifier followed by a colon. For example, \verb+fred:+, \verb+wilma:+, and \verb+x123:+ are some examples of valid labels.
\\ \\
\textbf{Instructions} are in the form \verb+add $3, $1, $2+. Consult the MIPS reference sheet for the syntax of each MIPS instruction.
\\ \\
\textbf{Comments} are placed at the end of lines and must be prefixed by a semicolon. Lines with only comments (still prefixed with a semicolon) are acceptable as well. For example: \verb+; hello world+.
\\ \\
It's important to note that there is a \textbf{one-to-one correspondence} between instructions in assembly and instructions in machine code. The same MIPS instructions will always produce the same machine code.
\subsubsection{More MIPS Instructions}
Here's a more comprehensive overview of the instructions available to you in the CS 241 dialect of MIPS. Note that for all of these instructions, $0 \le d, s, t \le 31$, since there are 32 registers in MIPS numbered from 0 to 31.
\begin{itemize}
\item \verb+.word+. This isn't really a MIPS instruction in and of itself. It provides you with a way to include arbitrary bits in the assembler's output. Words can be in several different forms. For example:
\begin{itemize}
\item \verb+.word 0x12345678+ (hex)
\item \verb+.word 123+ (decimal)
\item \verb+.word -1+ (negative decimals whose representation will eventually be represented in two's complement)
\end{itemize}
\item \verb+add $d, $s, $t+. Adds \$s to \$t and stores the result in \$d.
\item \verb+sub $d, $s, $t+. Subtracts \$t from \$s and stores the result in \$d (\$d = \$s - \$t).
\item \verb+mult $s, $t+. Multiplies \$s and \$t and stores the result in the \verb+HI+ and \verb+LO+ registers. Uses two's complement.
\item \verb+multu $s, $t+. Provides the same functionality as \verb+mult+, but uses unsigned numbers.
\item \verb+div $s, $t+. Divides \$s by \$t. The remainder is stored in \verb+HI+ and the quotient is stored in \verb+LO+.
\item \verb+divu $s, $t+. Provides the same functionality as \verb+div+, but uses unsigned numbers.
\item \verb+mflo $d+. Copies the contents of the \verb+LO+ register to \$d.
\item \verb+mfhi $d+. Copies the contents of the \verb+HI+ register to \$d.
\item \verb+lis $d+ (load immediate and skip). Copies the word from the program counter (the next word) into \$d, adds 4 to PC in order to skip the word you just loaded.
\item \verb+lw $t, i($s)+ (load word, $-32,768 \le i \le 32,767$). For example: \verb+lw $3, 100($5)+ will get the contents of \$5, add 100, treat the result as an address, fetch a word from RAM at that address, and put the result into \$3.
\item \verb+sw $t, i($s)+ (store word, $-32,768 \le i \le 32,767$). This works in a similar way to \verb+lw+, except it stores the contents of \$t at RAM at this address.
\item \verb+slt $d, $s, $t+ (set less than). Sets \$d to 1 if \$s < \$t, or to 0 otherwise.
\item \verb+sltu $d, $s, $t+ (set less than unsigned). Sets \$d to 1 if \$s < \$t, or to 0 otherwise. Interprets the numbers as unsigned numbers.
\item \verb+beq $s, $t, i+ (branch if equal, $-32,768 \le i \le 32,767$). Adds $4i$ to the program counter if \$s is equal to \$t. Note that 4 is still added (in addition to adding the $4i$ for this specific command) as you move to the next instruction, as with all instructions.
\item \verb+bne $s, $t, i+ (branch if not equal, $-32,768 \le i \le 32,767$). Works the same way as \verb+beq+, except it branches if \$s is not equal to \$t.
\item \verb+jr $s+ (jump register). Copies \$s to the program counter.
\item \verb+jalr $s+ (jump and link register). Copies \$s to the program counter and copies the previous value of the program counter to \$31.
\end{itemize}
\subsubsection{Example Program: Sum from 1 to N}
We want a program that sums the numbers from 1 to $n$, where $n$ is the contents of \$1, and we want the result to be placed in \$3.
\begin{verbatim}
; $1 is N.
; $3 is the sum.
; $2 is temporary.
add $3, $0, $0 ; zero accumulator
; beginning of loop
add $3, $3, $1 ; add $1 to $3
lis $2 ; decrement $1 by 1
.word -1
add $1, $1, $2
bne $1, $0, -5 ; n = 0? If not, branch to beginning of loop
jr $31 ; return
\end{verbatim}
If we enter 10 for \$1 (to get the sum of the numbers from 1 to 10), we should get 55. But the actual result is \verb+0x00000037+. Note that $37_{16} = 55_{10}$, so the program works as expected. The end result is \$1 being \verb+0x00000000+ ($0_{10}$), \$2 being \verb+0xffffffff+ ($-1_{10}$), and \$3 being \verb+0x00000037+ ($55_{10}$).
\\ \\
\underline{Aside}: it's only a convention that we reserve \$1 and \$2 as registers for input parameters and \$3 as the register for the result -- the MIPS system itself does not treat these registers in a special way.
\subsubsection{Housekeeping Notes}
\begin{itemize}
\item \verb+cs241.binasm+ will be available on Thursday after the assignment 1 deadline has passed. You can use this for future assignments as necessary.
\item You don't need to memorize the binary representation of MIPS commands for exams, or the ASCII representation of characters. You'll be provided with the MIPS reference sheet and an ASCII conversion chart for the exams.
\end{itemize}
\subsubsection{Labels} \lecture{January 16, 2013}
Part of the assembler's job is to count instructions and keep track of their locations (\verb+0x00000004+, \verb+0x00000008+, \verb+0x0000000c+, etc.). The assembler can use this information to simplify the programmer's job with \textbf{labels}.
\\ \\
Labels are identifiers in the form \verb+foo:+ (a string followed by a colon). A label \verb+foo:+ is equated to the \textbf{location} of the line on which it is defined.
\\ \\
Some instructions like \verb+beq+ and \verb+bne+ rely on relative locations of lines. Counting these yourself is tedious, and can be troublesome in some situations. The locations you specify, both in places where they're specified relatively (\verb+beq+ or \verb+bne+) and in places where they're specified absolutely (\verb+jr+), may become invalid if you add or remove any lines in your codebase.
\\ \\
Labels can be used in place of integer constants. If you have an instruction like \verb+bne $1, $2, -5+, you can replace it with \verb+bne $1, $2, foo+. The assembler will compute:
\begin{align*}
\frac{\text{location(label) - location(next instruction)}}{4}
\end{align*}
The third argument of \verb+bne+ is always a number. It can an integer literal, or it can be a label which will be converted to an integer by the assembler. MIPS itself has no knowledge of labels -- only the assembler does.
\section{Accessing RAM in MIPS}
\subsection{RAM vs. Registers}
There are some key differences between RAM and registers:
\begin{itemize}
\item There is lots of RAM available, but there are a finite number of registers available (usually not very many).
\item You can compute addresses with RAM, but registers have fixed names that cannot be computed (i.e. you can compute memory address \verb|0x00000008 = 0x00000004 + 0x0000004|, but you can't compute \$2).
\item You can create large, rich data structures in RAM. Registers provide small, fixed, fast storage mechanisms.
\end{itemize}
\subsection{Storing in RAM}
\begin{verbatim}
lis $5
.word 100000
sw $1, 0($5)
lw $3, 0($5)
jr $31
\end{verbatim}
The example above uses memory address 100000. But how do we know that we have that much RAM? How do we know it's not already being used by someone else? This is clearly a bad practice.
\\ \\
We really shouldn't just use an arbitrary memory address without any type of safety checking. So, we'll reserve some memory ourselves. We can add a word after the last \verb+jr+ instruction, which means memory will be allocated for the word instruction, however it'll never be executed.
\\ \\
MIPS requires that we actually specify a word for that space in memory. The contents of it don't matter, so we'll just use \verb+.word 28234+, which is entirely arbitrary. We can then replace 100000 in the above example with 20. For now, we can assume that our MIPS program will always run in memory starting at memory address 0, so memory addresses and locations in our code can be treated as being the same.
\\ \\
But wait! Hard-coding 20 is a bad idea, in case the program changes, and it's tedious to calculate the proper location (20). We should use a label instead.
\subsubsection{Stack}
\$30 is the conventional register to place the \textbf{stack pointer} in (sometimes abbreviated as \$sp). The stack pointer points to the first address of RAM that's reserved for use by other people. Here's an example of storing and fetching something using the stack:
\begin{verbatim}
sw $1, -4($30)
lw $3, -4($30)
jr $31
\end{verbatim}
All memory with an address less than the value of \$30 could be used by your program. You can use this method to create 100,000+ storage locations, and that wouldn't have been possible with registers without having 100,000 registers, and without hard-coding \$1, \$2, \ldots, \$100000.
\\ \\
The stack pointer isn't magical. It doesn't change on its own, but you can change it yourself if you'd like. Just make sure to change the stack pointer back to its original state before you return (before \verb+jr $31+).
\\ \\
Here's another example of a program which sums the numbers from 1 to $n$ without modifying anything except \$3. Actually, it's okay to modify \$1 and \$2, so long as they are returned to their original state before returning.
\begin{verbatim}
sw $1, -4($30) ; save on stack
sw $2, -8($30) ; save on stack
lis $2
.word 8
sub $30, $30, $2 ; push two words
add $3, $0, $0
; beginning of loop
foo: add $3, $3, $1
lis $2
.word -1
add $1, $1, $2
bne $1, $0, foo
lis $2
.word 8
add $30, $30, $2 ; restore stack pointer
lw $1, -4($30) ; restore from stack
lw $2, -8($30)
jr $31
\end{verbatim}
\verb+mips.array+ is a MIPS runner that passes an array $A$ of size $N$ into your MIPS program. The address of $A$ will be in \$1, and the size of $A$ (which is $N$) will be in \$2.
\\ \\
To access array elements, you would execute instructions such as these:
\begin{verbatim}
lw $3, 0($1)
sw $4, 4($1)
\end{verbatim}
Note that each array index increases by 4.
\\ \\
You can also compute the array index. In C/C++, you might have an expression A[i]. $A$ is in \$1 and $i$ is in \$3. How can we fetch A[i] into $x$ (let's say, into \$7)?
\begin{enumerate}
\item Multiply $i$ by 4.
\item Add to $A$.
\item Fetch RAM at the resulting address.
\end{enumerate}
\begin{verbatim}
add $3, $3, $3
add $3, $3, $3 ; these two lines give i * 4
add $3, $3, $1 ; A + i * 4
lw $7, 0($3)
\end{verbatim}
Note that the two first lines each double the value in \$3, so the two lines together effectively multiplied $i$ by 4.
\\ \\
Here's an example program to sum the integers in an array $A$ of length $N$. \$1 contains the address of $A$, \$2 contains $N$, and \$3 will contain the output (the sum). \$4 is used temporarily.
\begin{verbatim}
add $3, $0, $0
loop:
lw $5, 0($1) ; fetch A[i]
add $3, $3, $5 ; add A[i] to sum
lis $4 ; load -1 into $4
.word -1
add $2, $2, $4 ; decrement $2
lis $4
.word 4
add $1, $1, $4
bne $2, $0, loop ; loop if not done.
jr $31
\end{verbatim}
\section{Procedures in MIPS} \lecture{January 18, 2013}
Recall the \verb+sum.asm+ program from earlier, which sums the numbers from 1 to $N$ (\$1), and puts the result in \$3:
\begin{verbatim}
sum: ; only needed for next example, sum10.asm
add $3, $0, $0 ; $3 is the accumulator C
loop:
add $3, $3, $1 ; C = C + N
lis $2
.word -1
add $1, $1, $2 ; C = C + (-1)
bne $1, $0, loop
jr $31
\end{verbatim}
Now, let's create a program \verb+sum10.asm+ which sums the numbers from 1 to 10, and puts the result in \$3. We'll add the \verb+sum:+ label to the top of our \verb+sum.asm+ file, as indicated in the code above, so we have a way to jump to the \verb+sum.asm+ line (which is part of how procedures are called in MIPS). This is \verb+sum10.asm+:
\begin{verbatim}
; PROLOGUE
sw $31, -4($30) ; push word onto stack
lis $2
.word 4
sub $30, $30, $2
; PROCEDURE CALL
lis $1
.word 10
lis $4
.word sum ; address of sum procedure is in $4
jalr $4 ; puts old PC value into $31, jumps to $4
; EPILOGUE
lis $2
.word 4
add $30, $30, $2 ; restore stack pointer
lw $31, -4($30) ; restore $31
jr $31
\end{verbatim}
\underline{Aside}: Note that if you ever get into an infinite loop while executing a MIPS program, you can push CTRL-C to forcefully end the process immediately.
\\ \\
We use \verb+jalr+ instead of \verb+jr+ so the \verb+sum+ routine knows how to get back. \verb+jalr+ is the only instruction that can access the contents of the \verb+PC+.
\\ \\
How do we actually run this program? We \verb+cat+ together the two programs! It really is that simple. You execute \verb+cat sum10.asm sum.asm | java cs241.binasm > foo.mips+ to get a MIPS program in binary. Note that the order of the \verb+cat+ arguments matters \textendash{} you must place your runner program before the procedures (by listing it first in the \verb+cat+ command) so a procedure isn't executed prior to your runner program.
\subsection{Recursion}
Recursion is nothing special. You need to save any local variables (which are stored in registers), including given parameters and the return address, onto the stack so we can change them back when we're done. We don't want subroutines (recursive calls) to mess with those values, so subroutines must preserve their own values. ``It's always good hygiene to save your registers.''
\\ \\
Let's build \verb+gcd.asm+, where \$1 = a, \$2 = b, and \$3 will hold the result. We will use the following algorithm:
\begin{align*}
gcd(a, b) = \begin{cases}
b & a = 0 \\
gcd(b \% a, a) & a \ne 0
\end{cases}
\end{align*}
Here's \verb+gcd.asm+:
\begin{verbatim}
gcd:
sw $31, -4($30) ; save return address
sw $1, -8($30) ; and parameters
sw $2, -12($30)
lis $4
.word 12
sub $30, $30, $4
add $3, $2, $0 ; tentatively, result = b
beq $1, $0, done ; quit if a = 0
div $2, $1 ; stores quotient in LO, remainder in HI
add $2, $1, $0 ; copy a to $2
mfhi $1 ; $1 <- b % a
lis $4
.word gcd
jalr $4
done:
lis $4
.word 12
add $30, $30, $4
lw $31, -4($30)
lw $1, -8($30)
lw $2, -12($30)
jr $31
\end{verbatim}
An \textbf{invariant} means if something is true as a pre-condition then it is always true as a post-condition.
\\ \\
Notice in the \verb+gcd.asm+ example, you aren't actually erasing the stack contents. If you're storing secret data, you should overwrite it with zeroes, or (ideally) garbage data. For assignment 2, at least, we can just leave our garbage lying around.
\subsection{Input and Output}
\verb+getchar+ and \verb+putchar+ simulate RAM, however they actually send the data from/to the user's keyboard/monitor. \verb+getchar+ is located at memory address \verb+0xffff0004+ and \verb+putchar+ is at address \verb+0xffff000c+. If you load or store a byte at either of these addresses, you will retrieve or send the byte from/to standard input (STDIN) or standard output (STDOUT).
\\ \\
We will create an example program, \verb+cat.asm+, to copy input to output:
\begin{verbatim}
lis $1
.word 0xffff0004 ; address of getchar()
lis $3
.word -1 ; EOF signal
loop:
lw $2, 0($1) ; $2 = getchar()
beq $2, $3, quit ; if $2 == EOF, then quit
sw $2, 8($1) ; putchar() since getchar() and putchar() are 8 apart
beq $0, $0, loop
quit: jr $31
\end{verbatim}
\section{Building an Assembler} \lecture{January 21, 2013}
An assembler is just a program that reads input and produces output. The input and output of an assembler just happen to be programs.
\\ \\
You need to be more familiar with the MIPS assembly language in order to write an assembler, compared to just writing MIPS assembly code. You need to know \emph{exactly} what is a valid MIPS assembly program and what isn't in order to write a proper assembler.
\\ \\
You must ensure you implement and test every little detail on the MIPS reference sheet. You need to test the range for all numbers and reject all programs that contain numbers that are not within the valid ranges, for instance.
\\ \\
Sometimes when we look at a MIPS program there is no meaning because the MIPS assembly code is not well-formed (it's invalid). In that case, we need to have the assembler output an error report. For us, our assembler will identify well-formed MIPS programs in the `all or nothing' sense \textendash{} that is, if the program is valid we will produce valid binary machine code, otherwise we'll indicate that there's \emph{some} problem.
\\ \\
Don't imagine all the ways a program can be wrong. Write your assembler to identify correct MIPS assembly code as per the specification, and if the program does not follow those finite number of rules, then it is invalid and should be rejected.
\subsection{Assemblers In This Course}
It'd be nice if our assembler's error reports could produce helpful error messages. However, that involves mind reading (pretty much) and is beyond the scope of this course.
\\ \\
For assignments in this course, you can use Scheme, C++, or Java. Scheme is recommended, especially since you'll be dealing with data structures of lengths that aren't pre-determined, which is easier to handle in Scheme than in C++ or Java. The tools provided for Java are supported for assignment testing, so you can use them, but we won't actively be covering them.
\\ \\
For assignments 3 and 4, you will be provided a scanner for use in your assembler.
\subsection{The Assembly Process}
\begin{enumerate}
\item Read in a text file containing MIPS assembly code. [Input]
\item Scan each line, breaking it into components. [Analysis]
\item Parse components, checking well-formedness. [Analysis]
\item Other error checking. [Analysis]
\item Construct equivalent binary MIPS code. [Synthesis]
\item Output binary code. [Output]
\end{enumerate}
\subsubsection{Output}
How do we actually output binary code? In C, the only \emph{safe} way is to use \verb+putchar+, which outputs one byte. Here's how to output a 32-bit big-endian word in C:
\begin{verbatim}
putchar(...)
putchar(...)
putchar(...)
putchar(...)
\end{verbatim}
You can't use a built-in C function that outputs a whole word at once, because your computer architecture (Intel machines) will probably force that word to be written in little-endian, which won't work with MIPS.
\\ \\
In Scheme, you can use \verb+(write-byte ...)+ which works in a similar way.
\subsubsection{Scanners}
Scanners are way more annoying than they seem at first glance. We'll be given a scanner for assignments 3 and 4, called \verb+asm.cc+, \verb+asm.ss+, or \verb+asm.java+.
\\ \\
The scanner takes a line of text (a string) and gives you a list of all components in the string. For example, the line \verb+foo: bar: add $1, $2, foo+ will give you:
\begin{itemize}
\item label \verb+foo+
\item label \verb+bar+
\item instruction \verb+add+
\item register \verb+$1+
\item comma ,
\item register \verb+$2+
\item comma ,
\item identifier \verb+foo+
\end{itemize}
You should have code to check the validity of \verb+add+'s parameters \textendash{} you shouldn't have code to check for identifiers in place of registers, etc. You must also ensure that there aren't too many or too few arguments, but to perform this check you should simply check that you have exactly the correct number of arguments.
\\ \\
You can use \verb+cs241.binasm+ combined with \verb+xxd+ as a reference implementation because it's a valid MIPS assembler.
\\ \\
The assembler builds a \textbf{symbol table} that keeps track of mappings between identifiers and their locations. The symbol table is later used during the synthesis process to check the validity of label usage, since labels can be used before they're defined. Not all error checking occurs in the analysis steps, since this check during the synthesis process is considered error checking.
\\ \\
If \verb+foo+ did not exist in the symbol table, then you should error out. Whether \verb+foo+ was defined before it was used is irrelevant because it's perfectly valid to use labels before they're defined.
\\ \\
When an error is encountered, we must write to an error file. In our case, we'll write our output (the binary file) to standard output (STDOUT) and any error messages to standard error (STDERR). Ensure the assembler does not crash when it runs into an invalid program.
\\ \\
If there's an error, it doesn't matter what you've already written to standard output \textendash{} it'll be ignored. You could have written half a program or nothing, but it doesn't matter if an error message has been written to standard error.
\\ \\
The scanner will check hex numbers to ensure their general format is correct. That is, it will let you know that \verb+0xg+ is not a valid hex number. However, it may or may not check the ranges of numbers.
\\ \\
One common hiccup is not to throw an error when you are given \verb+.word 10, $1+, which is not valid. \verb+.word+ commands can only take one number, in decimal, hex, or a label identifier.
\section{Outline of an Assembler} \lecture{January 23, 2013}
You'll be writing a two-pass assembler.
\begin{enumerate}
\item \textbf{Pass 1} \textendash{} analysis (build intermediate representation, construct symbol table).
\item \textbf{Pass 2} \textendash{} synthesis (construct equivalent MIPS binary machine code and output it).
\end{enumerate}
\subsection{Pass 1 \textendash{ } Analysis}
Pass 1 should generally follow this pseudocode: \\
\begin{algorithm}[H]
location\_counter = 0\;
\For{every line of input in source file}{
read the line\;
scan line into a sequence of tokens\;
\For{each LABEL at the start of the sequence}{
\If{LABEL is already in the symbol table}{
output ERROR to standard error\;
quit\;
}
add(label, location\_counter) to symbol table\;
}
\If{next token is an OPCODE}{
\If{remaining tokens are NOT exactly what is required by the OPCODE}{
output ERROR to standard error\;
quit\;
}
output a representation of the line to the intermediate representation (which can be text, a token sequence, etc.)\;
location\_counter += 4\;
}
}
\end{algorithm}
\subsubsection{Efficient Symbol Tables}
\textbf{Scheme}:
\begin{verbatim}
(define st (make-hash))
(hash-set! st ``foo'' 42)
(hash-ref st ``foo'' #f) ; returns #f if key not found
(hash-ref st ``foo'' #f) => 42
(hash-ref st ``bar'' #f) => #f
\end{verbatim}
\textbf{C++}:
\begin{verbatim}
using namespace std;
#include <map>
#include <string>
map<string, int> st;
st[``foo''] = 42;
// Incorrect way of accessing elements:
x = st[``foo'']; // x gets 42
y = st[``bar'']; // y gets 0, (bar, 0) gets added to st.
// Correct way of accessing elements:
if (st.find(``biff'') != st.end()) { ... not found ... }
\end{verbatim}
Why do we use \verb+map+s? It's more efficient because it converts strings into numbers in order to make lookups more efficient.
\subsubsection{The Supplied Scanners}
The supplied scanners will find a sequence of tokens on the given line for you. For each token, you'll get a tuple (kind, lexeme, value), where the lexeme is the literal text of the token. For example, take the line \verb+foo: beq $3, $6, -2+. The provided scanners will return a list with this data:
\begin{itemize}
\item (LABEL, ``foo:'', ?)
\item (OPCODE, ``beq'', ?)
\item (REGISTER, ``\$3'', 3)
\item (COMMA, ``,'', ?)
\item (REGISTER, ``\$6'', 6)
\item (COMMA, ``,'', ?)
\item (INT, ``-2'', -2)
\end{itemize}
\subsection{Pass 2 \textendash{} Synthesis}
Pass 2 should generally follow this pseudocode:
\begin{algorithm}
location\_counter = 0\;
\For{each OPCODE in the intermediate representation}{
construct corresponding MIPS binary instruction (inside of an int variable)\;
output the instruction\;
location\_counter += 4;
}
\end{algorithm}
\subsubsection{Creating MIPS Binary Instructions}
We can form a MIPS binary instruction using a \textbf{template} and appropriate values for any variables in the command (usually denoted $s$, $t$, and $d$). The template is the integer that represents the binary associated with a particular instruction, with all of the variables ($s$, $t$, and $d$) being zeroes.
\\ \\
Bitwise operations compare integers bit by bit and perform the requested operation at that level. For example, given the numbers $a$ and $b$ that can represented in binary as 000111000 and 11011000, respectively, $a | b$ (a bitwise OR) will result in 11011100 and \verb+a & b+ (a bitwise AND) will result in 00011000.
\\ \\
Suppose we want to zero out all but the last byte of $b$. We'd do \verb+b & 255+, which is the same as \verb+b & 0xff+.
\\ \\
In Scheme, \verb+(bitwise-and a b)+ and \verb+(bitwise-ior a b)+ are the available utilities for performing bitwise operations. In C++, you can use \verb+a & b+ and \verb+a | b+.
\\ \\
Shifting bits can also be useful. You can use \verb+a << n+ in C++ to perform a left-shift by $n$ bits (adding $n$ zeroes to the right, discarding from the left). C++ also supports \verb+a >> 5+, which adds $n$ zeroes to the left and discards from the right. Scheme supports left and right shifts using \verb+(arithmetic-shift a n)+, where positive $n$ shifts right and negative $n$ shifts left.
\\ \\
To fill our template with the appropriate $s$, $t$, and $d$ values, you would perform an operation like this:
\begin{verbatim}
template | (s << 21) | (t << 16) | (0xffff & i)
\end{verbatim}
Note that this adjusts $s$ to the proper position, which in this case is 21 bits from the end. The \verb+0xffff+ which is ANDed with $i$ is 16-bits, as required by $i$.
\\ \\
You can output bytes using shifts and several output calls. Here's some sample code for outputting a byte in C++:
\begin{verbatim}
void outbyte(int b) {
putchar(b >> 24);
putchar(b >> 16);
putchar(b >> 8);
putchar(b >> 4);
}
\end{verbatim}
Here's similar code for Scheme:
\begin{verbatim}
(define (outbyte b)
(write-byte (bitwise-and (arithmetic-shift b -24) 255))
(write-byte (bitwise-and (arithmetic-shift b -16) 255))
(write-byte (bitwise-and (arithmetic-shift b -8) 255))
(write-byte (bitwise-and b 255)))
\end{verbatim}
\subsection{Assembler Requirements} \lecture{January 25, 2013}
Your assembler is a Scheme/C/C++/Java program. You could also submit it in Scala, if you'd like.
\\ \\
In the end, your assembler should be able to be run such that it takes a \verb+.asm+ file as standard input, and produces MIPS binary code as standard output. That is, you should be able to run it like so:
\begin{itemize}
\item Scheme: \verb+racket asm.ss < myprog.asm 1> myprog.mips 2>myprog.err+
\item C++:
\begin{verbatim}
g++ asm.cc
valgrind --log-file=foo ./a.out < myprog.asm 1> myprog.mips 2> myprog.err
grep ``ERROR SUMMARY'' foo
\end{verbatim}
\end{itemize}
For C++, leak checking is turned off for the Marmoset tests. You still shouldn't leak memory all over the place, though.
\\ \\
\verb+grep ``ERROR'' myprog.err+ should not match anything if your program is valid, or should match otherwise (if there's an error).
\\ \\
To check the accuracy of your assembler, you can compare it with \verb+cs241.binasm+:
\begin{verbatim}
java cs241.binasm < myprog.asm > myprog.ref.mips
diff myprog.mips myprog.ref.mips
\end{verbatim}
This should give no output. Remember: there is a one-to-one mapping of valid MIPS assembly code to valid MIPS binary machine code.
\\ \\
You're going to have to make a large test suite to test your assembler. For valid code, you only need a handful of test cases. However, for error cases, you'll need a separate test case for each error since our assembler will quit as soon as it encounters the first error. Write a test script to run all of these cases, because it'll become tedious otherwise. You can share test cases you make with others, however you are not allowed to share information about the test cases Marmoset uses to test your code.
\\ \\
We're going to take a look at the \href{https://www.student.cs.uwaterloo.ca/~cs241/mips/mipsasm.html}{specification of the CS 241 dialect of MIPS}. You'll likely want to print this out and mark every statement/condition twice: once after you implement it and once after you test it. [Note: you should look at \href{https://www.student.cs.uwaterloo.ca/~cs241/mips/mipsasm.html}{the specification itself} rather than relying on the notes here.]
\subsubsection{Locations and Labels}
Locations start at $0, 4, 8, \ldots$. The size of a program is the number of instructions multiplied by four. Locations are typically written in hex.
\\ \\
Each line may or may not contain labels, an instruction, and a comment. All three are optional. You can have none, one of these, two of these, or all three of these.
\\ \\
Lines without an instruction are known as \textbf{NULL lines}. Each non-NULL line has output into machine code.
\\ \\
Label definitions must be at the beginning of the line. You may have zero of more labels on a line. Multiple labels are permitted on a single line. A label looks like this: \verb+foo: ...+
\\ \\
Any given label can only be given a single definition in a MIPS program. You cannot have a label defining multiple lines or locations.
\\ \\
The \textbf{location} of a line is simply $4 \times \text{(number of non-NULL lines that precede it)}$. For example:
\begin{verbatim}
; hello 0
foo: 0
add $1, $8, $3 0
bar: bif: ; hello again 4
lw $7, 0($2) 4
jr $31 8
.word 32 12
\end{verbatim}
Note that all lines have a location (including NULL lines), however some lines may have the same location due to non-NULL lines. You are guaranteed that every line that contains an instruction (that is, every line that will be converted to machine code) will have a distinct location associated with it.
\\ \\
You should have a location counter variable which is incremented by 4 after you translate each instruction.
\\ \\
A \textbf{label} is simply a mapping between an identifier and a location.
\subsubsection{Comments}
Comments are ignored entirely. The provided scanners will throw away these comments for you.
\subsubsection{Instructions}
An \textbf{instruction} is an opcode (name of command) followed by zero or more operands.
\\ \\
After a label, you must either hit the end of the line (either it was a blank line, or a line with comments that were already stripped away) or an opcode.
\\ \\
For assignment 3, you can assume \verb+.word+ is the only opcode in existence.
\\ \\
If you do encounter a valid opcode, ensure it has the proper operands. The existence, types, and ranges of all operands must be verified for acceptability. Also, you must ensure there are no extra operands.
\\ \\
There are several types of operands:
\begin{itemize}
\item Registers.
\item Unsigned numbers.
\item Signed numbers.
\item Hex numbers (\verb+0x...+; the case of $a$ to $f$ does not matter).
\item Labels (the \emph{use} of labels, not a label definition).
\end{itemize}
\subsubsection{Operand Format}
Each instruction has specific requirements for its operands. Some instructions have the same requirements for their operands as other instructions, so they can be grouped together to remove duplication. In the second pass, you simply use a different template to fill different instructions from within the same grouping.
\begin{itemize}
\item \verb+add, sub, slt, slt+ \textendash{} \verb+add+, register, comma, register, comma, register, nothing else.
\item \verb+mult, div, multu, divu+ \textendash{} \verb+mult+, register, comma, register, nothing else.
\item \verb+mfhi, mflo, lis+ \textendash{} \verb+mfhi+, register, nothing else.
\item \verb+lw, sw+ \textendash{} lw, register, comma, $i$, bracket(, register, bracket), nothing else, where $i$ can be an unsigned, negative, or hex number within the 16-bit range. Test cases needed: (in)valid with unsigned, (in)valid with hex, etc. Note: there is no rule stating that you must load a multiple of four.
\item \verb+beq, bne+ \textendash{} \verb+beq+, register, comma, register, $i$, nothing else. $i$ in this case can be an unsigned, negative, or hex number in the 16-bit range, or it could be the use of a label. In the case of a label, you calculate the numerical value by calculating: $$\frac{\text{location(label)} - \text{location counter} - 4}{4}$$
\item \verb+jr, jalr+ \textendash{} \verb+jr+, register, nothing else.
\item \verb+.word+ \textendash{} \verb+.word+, $i$, nothing else, where $i$ can be an unsigned, negative, or hex number in the 16-bit range, or it could be the use of a label.
\end{itemize}
\section{Loaders, Relocation, and Linkers} \lecture{January 28, 2013}
\subsection{Loaders}
For the use of this section, we have \verb+ft.asm+:
\begin{verbatim}
ASSEMBLY RAM LOCATION BINARY
lis $3 0 0 00001814
.word ft 4 4 00000010
lw $3, 0($3) 8 8 8c630000
jr $31 c c 03e00008
ft: .word 42 10 10 0000002a
\end{verbatim}
After assembling \verb+ft.asm+, you'll have a MIPS binary machine program (say, \verb+ft.mips+). But how does the program get into the CPU? The program is sent to the IO registers of RAM, which sends it to a loader, which stores it in RAM and executes it for you.
\\ \\
The \textbf{loader} is itself a MIPS program. It must exist in the MIPS CPU, or in RAM accessible from the MIPS CPU. A loader is a program in RAM that:
\begin{itemize}
\item Figures out the length ($n$ words) of a binary MIPS program.
\item Finds $n$ words of available RAM at some address $\alpha$.
\item Reads the file into RAM starting at $\alpha$.
\item Puts $\alpha$ (the address) into some register (let's say \verb+$5+).
\item Executes the program (\verb+jalr $5+).
\item Does something else afterwards (\verb+mips.twoints+ prints the values of all the registers and then terminates, for instance).
\end{itemize}
This raises another question: how does the loader itself get into RAM? In the old days, there were hardware switches on RAM that allowed you to physically punch words into RAM. Today, we have manufacturing processes that do that for us. Regardless, we still want our loader to be \emph{really} small (in terms of the number of words).
\\ \\
Instead of hard-coding the loader into RAM, a mini-loader is written (with less code than a full loader would require) to load the loader. This process is known by various names, including:
\begin{itemize}
\item Initial Program Loader (IPI) in IBM mainframe land.
\item Bootstrapping (bootstrap) in mini/micro.
\end{itemize}
The mini-loader is permanently stored in a portion of RAM that is read-only. The mini-loader is actually manufactured into RAM.
\\ \\
\underline{Exercise}: write the smallest file \verb+mini.mips+ such that you can write an arbitrary program and run it like this: \verb+java mips.twoints mini.mips < program.mips+.
\subsection{Relocation}
Up until this point, we have assumed that $\alpha = 0$. That is, the location in the program has been equal to its address in RAM. Suppose instead that $\alpha = 8$. In fact, we can test this with \verb+mips.twoints+ like so: \verb+java mips.twoints ft.mips 8+ (the last parameter is the value for $\alpha$, which must be a multiple of 4).
\\ \\
In the case where $\alpha = 8$, the \verb+ft.mips+ program would set \verb+$3+ to \verb+0x8c63000+, which isn't correct. We need to offset our label values when $\alpha \not = 0$.
\\ \\
We use ``sticky notes'' to indicate where $\alpha$ needs to be added. We encode these sticky notes using a \textbf{MERL file} (MIPS executable relocatable linkable file). A MERL file is a binary file with three components:
\begin{enumerate}
\item \textbf{Header}. A MERL header is three words. The first word is a cookie, which is an arbitrary identifier that indicates that this is a MERL file. The cookie for MERL files is \verb+0x10000002+. Note that \verb+0x10000002+ is the hex representation of \verb+beq $0, $0, 2+, which means our program will execute normally if the MERL file is itself run directly where $\alpha = 0$. The second word is the size of the header, MIPS code, and sticky notes (indicates end/length of file). The third word is the size of the header and MIPS code (indicates the location of the first sticky note).
\item \textbf{MIPS code}. This is regular binary MIPS code, starting at location \verb+0c+.
\item \textbf{Sticky notes}. Every relocation (REL) sticky note is composed of two words: a sticky-note-type indicator (in this case it's 1 to indicate the sticky note means to add $\alpha$), and the location in MERL to add $\alpha$ to. Other types of sticky notes have different formats.
\end{enumerate}
Here's an example MERL file:
\begin{verbatim}
ASSEMBLY RAM LOCATION BINARY
.word 0x10000002 8 0 10000002
.word 40 c 4 00000028
.word 32 10 8 00000020
lis $3 14 c 00001814
.word ft 18 10 00000010
lw $3, 0($3) 1c 14 8c630000
jr $31 20 18 03e00008
ft: .word 42 24 1c 0000002a
.word 1 28 20 00000001
.word 0x10 2c 24 00000010
\end{verbatim}
\lecture{January 30, 2013}
For more information about MERL, you should consult the \href{https://www.student.cs.uwaterloo.ca/~cs241/merl/merl.html}{MERL specification}.
\\ \\
The easy way to encode a MERL file is to put a label at the end of the code, and another label at the end of the whole file (after your sticky notes).
\\ \\
The general process for creating a MERL file was to take your MIPS assembly, add the MERL header and sticky notes into an augmented \verb+.asm+ program, then run it through \verb+cs241.binasm+ to get a \verb+.merl+ file. However, you can use \verb+java cs241.linkasm+ instead to do all of this for you.
\subsection{Linkers}
If you want to use \verb+proc.asm+ in multiple programs, you don't want to have to re-assemble it over and over again. With the procedure process that involved \verb+cat+ (as previously discussed), we had to worry about identifier conflicts when defining labels. Linkers solve both of these problems.
\\ \\
A \textbf{linker} allows for the separate assembly of procedures. You can assemble \verb+main.asm+ and \verb+proc.asm+ separately with \verb+cs241.linkasm+ to generate two MERL files (\verb+main.merl+ and \verb+proc.merl+), then you can run both files through a linker and get \verb+both.merl+. You needn't worry about identifier conflicts for re-assembling.
\\ \\
If you feed \verb+main.asm+ into \verb+cs241.binasm+ (or \verb+cs241.linkasm+, or any other assembler), you'll get an error stating that you're using an undefined identifier (label). \verb+cs241.linkasm+ provides a mechanism for specifying that certain identifiers will be defined later.
\begin{verbatim}
main.asm: proc.asm:
.import proc .export proc
lis $1 proc: jr $31
.word proc
jr $31
\end{verbatim}
This is an example of the \verb+.import+ and \verb+.export+ directives that \verb+cs241.linkasm+ understands. \verb+.import proc+ indicates to the assembler to that the \verb+proc+ identifier must be defined later. It creates a sticky note that says to place the value of \verb+proc+ into certain places of your program where the identifier is used. In \verb+proc.asm+, we specify \verb+.export proc+, which creates a note that \verb+proc+ is available to other programs at location \verb+0xc+ (for instance).
\\ \\
\verb+.import+ and \verb+.export+ instructions create sticky notes with a specific format code (\verb+0x11+ for \verb+.import+ and \verb+0x05+ for \verb+.export+), a location to be encoded (\verb+.import+) or value (\verb+.export+), and name (a 32-bit word containing the number of words that encode the name of the identifier, followed by those $n$ words).
\\ \\
By convention, references to currently-undefined identifiers get zero-filled (\verb+0x00000000+) prior to being defined.
\begin{verbatim}
beq $0, $0, 2 ; skip over header ; 0x00000000 0x10000002
.word endmodule ; 0x00000004 0x0000003c
.word endcode ; 0x00000008 0x0000002c
lis $3 ; 0x0000000c 0x00001814
.word 0xabc ; 0x00000010 0x00000abc
lis $1 ; 0x00000014 0x00000814
reloc1:
.word A ; 0x00000018 0x00000024
jr $1 ; 0x0000001c 0x00200008
B:
jr $31 ; 0x00000020 0x03e00008
A:
beq $0, $0, B ; 0x00000024 0x1000fffe
reloc2:
.word B ; 0x00000028 0x00000020
endcode:
.word 1 ; relocate ; 0x0000002c 0x00000001
.word reloc1 ; location ; 0x00000030 0x00000018
.word 1 ; relocate ; 0x00000034 0x00000001
.word reloc2 ; location ; 0x00000038 0x00000028
\end{verbatim}
When a linker links two MERL files together, the resulting MERL file will contain a new header, code from file 1, code from file 2 (relocated to be after code 1), and sticky notes (combined and relocated). Code 1 does not need to be relocated because it was and remains at location \verb+0xc+. Code 2 needs to be relocated to \verb.0xc + (size of code 1)..
\subsubsection{What a Linker Does}
\begin{itemize}
\item Creates a combined header.
\item Concatenates all code segments.
\begin{itemize}
\item Relocates $\text{code}_i$ by $\displaystyle \sum_{j < i} \text{length}(\text{code}_j)$.
\item Relocates the locations in the sticky notes by the same amount.
\end{itemize}
\item REL (relocation entry) entries are copied directly to the new MERL, once they're relocated.
\item Relocated ESD (external symbol definition) entries are copies.
\item For each ESR (external symbol reference):
\begin{itemize}
\item If there is an ESD with the same name\dots
\begin{itemize}
\item Store the value of the ESD at the location specified in the ESR.
\item Add REL entry with ESR location to the combined stickies.
\end{itemize}
\item Otherwise, if there is no ESD\dots
\begin{itemize}
\item Add ESR to combined stickies.
\end{itemize}
\end{itemize}
When the ESRs are all gone, you can run your program.
\end{itemize}
\subsection{Assemblers, Linkers, and Loaders on Linux} \lecture{February 1, 2013}
In this course, we've been using tools designed for a MIPS CPU. We'll now take a brief look at how assemblers, linkers, and loaders work on Linux machines instead of on MIPS CPUs.
\\ \\
The \textbf{ELF format} is the Linux equivalent to MERL for MIPS. ELF means executable linkable format. ELF is a \emph{really} complicated format. You can learn more about the ELF format by running \verb+man elf+ on a Linux machine.
\\ \\
The assembler on Linux is called \verb+as+. Linux uses a different assembly language than MIPS because your CPU is probably an Intel or AMD CPU, not a MIPS CPU.
\\ \\
The linker is called \verb+ld+.
\\ \\
The loader is implicit. Fun fact: \verb+a.out+ was a format like ELF (but simpler), and it literally meant ``the \textbf{out}put from the \textbf{a}ssembler.'' The name \verb+a.out+ is still used today as the default name for code compiled with \verb|gcc| and \verb|g++|.
\subsection{Libraries}
You may have a bunch of procedures that you want to use in many \verb+asm+ files. You can package these in a \textbf{library} so the linker can search the sticky notes for the ESD (external symbol definition) for the procedures it needs. Think of it as a match.com for MERLs.
\\ \\
How do you create an archive? It could be just a folder. But on Linux, you use \verb+ar+ (which is an abbreviation for ``archive'') which produces an archive similar to a zip file.
\\ \\
The standard libraries on Linux systems are stored at \verb+/usr/lib+.
\subsubsection{Dynamic Linking}
So far, we've been discussing \textbf{static linking}, where all external symbol references are resolved by combining with external symbol definitions to create REL entries. There are several shortcomings to static linking, however.
\begin{itemize}