In case you have questions, here's some relevant contact information:
| Email address | mburrel@uwo.ca |
|---|---|
| Office hours | Friday 13:30 to 15:30 (right after tutorial) |
| Office location | Western Science Centre 127 |
I've posted the code I wrote on the board in tutorial for dealing with fopen, fread and fclose. Note I actually made a mistake in tutorial (I forgot to give readString the length of the filename array when reading in from the user).
Here are the files I wrote up during tutorial that could maybe give you a starting point for assignment 4. I added a few comments to them.
Remember that for your assignment, you should put all your functions in one file.
Don't you hate having to compile your stuff every time you change something? Well okay, maybe it's not so bad if you only have one file, but even then...ehh. Makefiles are glorious things which do all the compiling for you. But wait, there's more! They actually make compiling more efficient than doing it by hand.
gmake (the Unix utility that uses Makefiles) is dependency-driven. When it wants to compile something, it only builds the dependencies for that file if necessary. Example: let's say we had a program (not unlike your assignment 4) that was built out of C and assembler files. These C and assembler files are the dependencies of the program you're trying to compile. gmake won't recompile them unless they've changed (it looks at the timestamps to figure out the last time you modified them to accomplish this).
So, a concrete example. In my hypothetical program I have an awesome.m, which looks like so:
define(multiply, `mov $1, %o0 call .mul mov $2, %o1') .global square square: save %sp, -96, %sp multiply(%i0, %i0) mov %o0, %i0 ret restore
And let's say you have a C file, try-square.c, which looks like so:
#include <stdio.h>
signed square(signed);
int
main(void)
{
printf("square(%d) = %d\n", 50, square(50));
return 0;
}
What we would like to do is turn both of these into a program we can run. To do this we need a Makefile! So, use your favourite text editor and create a file (in the same directory as your source files) called Makefile. Note: your Makefile must be called Makefile. With the capital M and everything.
My first Makefile is going to look like this:
try-square: try-square.o awesome.o
gcc -o $@ $^
The first line says "if you want to make a file called try-square, first you need its dependencies, which are try-square.o and awesome.o. Once you have those dependencies, then you can execute the gcc command listed there". The special variables $@ and $^ get substituted by the name of the target (try-square) and dependencies (try-square.o awesome.o) respectively.
Nota bene: when indenting in a Makefile, you must use tabs, never spaces. If you use spaces, your Makefile will likely not work. If you get mysterious errors like "missing separator", check to make sure you don't have spaces where they're not supposed to be. To clarify, after a colon (between try-square: and try-square.o) and at the beginning of an indented line (before gcc -o ...) you must have hard tabs. To help you out, I'm going to make the whitespace pink wherever you should put a tab.
So, we've successfully written our rule. We've described what file to make, what its dependencies are and what to do once we've got those dependencies. We save our Makefile and try it out using the gmake command:
obelix[68]% gmake cc -c -o try-square.o try-square.c gmake: *** No rule to make target `awesome.o', needed by `try-square'. Stop.
Fiddle-sticks! The good news is gmake knew what it was supposed to do: it was supposed to get the try-square.o and awesome.o dependencies. It just needs some help doing that. (Note that is already has some built-in knowledge of how to turn .c files into .o files, but doesn't know anything about .m files).
We move our attention to what are called automatic rules (sometimes called implicit rules). The rule we made for try-square was a very concrete rule. It was a rule for one target and a very specific, concrete set of dependencies. Automatic rules allow us to generate target files for certain classes of files.
We'll write 3 automatic rules. They, respectively, turn .m files into .S files, .S files into .o files and .c files into .o files.
.SUFFIXES: .m .S .c .o
.m.S:
m4 <$^ >$@
.S.o:
gcc -c $^
.c.o:
gcc -Wall -c $^
# and the rule we had before
try-square: try-square.o awesome.o
gcc -o $@ $^
The first line (the .SUFFIXES line) tells gmake the list of all the file extensions/suffixes we'll be working with. It needs that to figure out dependencies with automatic/implicit rules. Anyway! If we save our new Makefile and try it, we now get:
obelix[70]% gmake m4 <awesome.m >awesome.S gcc -c awesome.S gcc -o try-square try-square.o awesome.o rm awesome.S
Some things to note:
It gets better, though. Let's say we change one of our files. Let's say we change try-square.c (for instance, so that it computes the square of 100 instead of the square of 50). After we're done our change, we run gmake again and get:
obelix[72]% gmake gcc -Wall -c try-square.c gcc -o try-square try-square.o awesome.o
Notice anything different? gmake was clever enough to know that awesome.m didn't change and so there was no use reassembling it. It's not so important in a project this small, but in a project with thousands of files (and when you get into industry, you will be working with projects of thousands of files), recompiling only what's necessary is a huge win.
Here are the files I used for this part of the tutorial if you'd like to download them:
Obelix is a fantastic computer, but it's the only SPARC compute server on the GAUL network, which means sometimes it can get a bit overloaded. This is especially true towards the end of the term when all the undergrads are trying to get their projects done.
Thankfully 4 SPARC machines (Ultra 10s) in MC10 which you can use. They're not as nice as obelix, except when you're the only one using them!
If you still want to work remotely (e.g., from home), you can log in to these 4 machines via rlogin. Their names are:
Here's how I'd recommend working on SPARC machines remotely on the gaul network:
The important bit of information here is the load average at the end of the first line. The screenshot to the left is showing load averages of 0.00, 0.01 and 0.04. In Unix, the load of a system is a measure of how much time the CPU spends running programs. A program using up 100% CPU (e.g., an infinite loop) will induce a load of 1.00. In this case the load average is extremely low: the system is effectively idle. Thus, you should be able to use obelix without noticing any slowness.
Note that w (or uptime) gives you three load averages. The first number is the system load averaged over the past minute; the second is averaged over the past 5 minutes; and the third is averaged over the past 15 minutes. The middle number is probably a good one to pay attention to for general "how heavily used is this computer?" kind of curiosity.
Note none of this, of course, will do anything to help network slowness :(
Here's a quick reference for working with GAUL. I'm going to assume that you're working on your own computer, possibly from home, since most of you will be.
Working with GAUL, and specifically obelix, is a necessary evil of this course. Ideally you would be able to do all the work on your own computer. However, since practically no one has a SPARC processor in their home computer and this course teaches SPARC (because it's very beautiful), you need to be able to get your work done on a SPARC machine. Enter GAUL and obelix.
This tutorial is currently Windows-only. OS X and Linux to come.
If you're just getting started, probably the first thing you want to do is get some of the examples from the course website onto the obelix. For the purposes of this example, we'll use sum.s.
Run WinSCP. Fill in obelix.gaul.csd.uwo.ca as the hostname and fill in your GAUL username and password. Everything else can be left unchanged. Example screenshot:

The first time you connect, it will warn about the key not being in your cache and will ask if you trust the key. Select "yes".
You should be presented with a new window with two panes. In the left pane, find the file on your computer where you want to transfer. In the right pane, find the directory on obelix where you want to transfer to. Note: I highly recommend creating a new directory/folder (which can be done inside WinSCP) specific to 2208 and putting everything in there. Example screenshot:

Now that you've got a file transferred over, you can log onto obelix via SSH to do some real work! Once again, this is Windows-only for the time being.
Run PuTTY. Fill in obelix.gaul.csd.uwo.ca for the hostname. Everything else can be left alone. Example screenshot:

A new window will open asking for your username and password. After successfully entering those in, you will be at what's called a "shell" which is prompting you for new commands. Example screenshot:

Note my fonts and colours might not match yours (I think I changed the defaults). Also, if you get something telling you about your terminal type being unknown and prompting you for a new terminal type, just type in vt100 and hit enter. If you really care, I can explain, but it's not very interesting.
Here's a list of courses I've been a TA for in the past:
Recently, I was a TA for CS 208, dealing with SPARC assembly. The course is over, but for those who would like to see SPARC assembly beyond the scope of the course, or for those who are curious, I've written a short tutorial on SPARC's VIS instructions. SPARC's VIS instructions are so-called vector or SIMD instructions and most useful in multimedia applications, such as video, graphics, or audio processing. They're also one area where assembly is still widely used: modern compilers are currently not very good at using vector instructions.