Assignment 0: Introducing Nachos

Due date: January 26th

Individual submissions for this assignment. Students will work in teams of three for the remaining assignments.

1. Introduction

This assignment will familiarize you with Nachos, the operating system and machine simulator combination that you will use to implement the concepts discussed in class. This assignment will also give you a chance to write a relatively simple program in the subset of C++ that we will use for this class.

2. What is Nachos?

Nachos is divided into two main parts:

As this course is about writing operating systems, and not designing or simulating hardware, you may not change the machine simulator but may modify or augment any portion of the operating system code that runs on it. The machine simulator resides in the directory /c/cs422/nachos/code/machine. Other components (such as thread management) reside under the directory /c/cs422/nachos/code.

There will be a Nachos programming assignment for each of the following topics:

The assignments are cumulative in that you use code developed in each assignment to complete subsequent ones.

Nachos runs as a UNIX user process; your operating system code and the machine simulator are linked together into a single executable. In reality, operating systems run on bare hardware (without machine simulator code). This hardware handles everything from interrupts to registers to page tables. User processes run on top of the operating system and make system calls, calls to operating system functions in the kernel. The concept of using a simulated machine is a useful one in operating system design, as it can be significantly more difficult to debug and test an operating system running on real, bare hardware. While the Nachos machine simulator functions well as a platform for developing operating system code and corresponds roughly to the physical hardware of a DECstation, its emulation is by no means exhaustive.

3. Machine Directory Questions

Enclosed is a brief description of the code in the Nachos directory machine. You should use this list to guide you in reviewing all of the existing code in the system. The description also includes questions to help you notice and pinpoint some of the most important parts of the system. The key part of this exercise is understanding the base system. Your goal is to clearly grasp how it all fits together so that you can make intelligent design decisions when you approach future assignments. This may seem tedious, but if you understand how the base system works now, you will have much less difficulty completing future assignments.

These questions are not meant to be tricky--most of the answers can be found in comments in the Nachos source and in the Nachos Roadmap, though you may have to look elsewhere (such as the textbook) for some backgound information.

3.1 Mipssim

3.1.1 mipssim.h

Defines opcodes and decoding tables.

3.1.2 mipssim.cc

This is the actual machine simulator; it contains some of the methods for the Machine and Instruction classes.

3.1.3 Questions

1. How many different instruction formats are there? What are they called?

2. How many registers can you possibly have in a single instruction?

3. What is the minimum number of MIPS assembly instructions needed to add the contents of two registers, and store the result back to memory? Why can't this be done in a single instruction?

3.2 Machine

3.2.1 machine.h

Defines the machine constants (e.g., sector size, page size, physical memory size, TLB size, etc.) and register names (e.g., stack, pc, etc.).

3.2.2 machine.cc

Provides most of the routines and data structures associated with the Machine class.

3.2.3 Questions

1. What causes the machine to change into system mode? What events in the user program can cause this?

2. Let's say that you wanted to execute: register 3 gets register 1 + register 2. What single C statement, involving three function calls, could you use to do this?

3. If you execute DumpState(), will you see the contents of the memory of your Nachos machine?

4. How many registers are there in this machine?

5. Can this machine have both a TLB and a page table?

3.3 Console

3.3.1 console.h

Defines the Console class. The console is the controlling terminal of a machine. We conventionally think of the console (or a terminal) as a single device, but in reality there are two: the keyboard for input and the display for output.

3.3.2 console.cc

3.3.3 Questions

1. Where is the console created? (The answer to this is not Console::Console(). We want to know where the constructor is called from.)

2. What are its initial read and write handlers?

3. Where is the function Read() (used by Console::CheckCharAvail()) defined? Why does the code invoke Read() here, and not ReadPartial()?

4. What are the status flags in the Console class and what do they mean?

3.4 Disk

3.4.1 disk.h

Defines the Disk class and sets disk constants.

3.4.2 disk.cc

3.5 Interrupt

3.5.1 interrupt.h

Defines machine states and interrupt types. Declares Interrupt and Pending- Interrupt classes.

3.5.2 interrupt.cc

Maintains structures to represent interrupts, manages simulated time, and defines interrupt levels.

3.5.3 Questions

1. When does time advance in the simulated machine?

2. The machine currently has only two interrupt states (on/off). Describe how you could modify the machine to have many different interrupt levels. As you do later assignments, think about places where having different interrupt levels might be useful.

3. Explain the purpose of having both ChangeLevel() and SetLevel().

4. Why is OneTick() a function of Interrupt instead of Machine?

5. What kind of time accounting is performed?

6. When can interrupt levels actually change?

7. When do context switches happen?

8. How is the clock advanced in CheckIfDue()?

9. Why is DelayedLoad() called in CheckIfDue()?

3.6 Network

3.6.1 network.h

Defines the PacketHeader and Network classes which simulate a physical network.

3.6.2 network.cc

3.7 Stats

3.7.1 stats.h

Defines the statistics used to measure Nachos performance. Keeps track of ticks (system, user, total), disk/console reads and writes, page faults, etc.

3.7.2 stats.cc

Routines for printing the current values of all statistics.

3.8 Sysdep

3.8.1 sysdep.h

Defines the system-dependent routines that Nachos requires.

3.8.2 sysdep.cc

Code for system-dependent routines. These are merely wrapper functions which make calls to the Unix library.

3.9 Timer

3.9.1 timer.h

Defines the Timer class.

3.9.2 timer.cc

Simulates a hardware timer by generating CPU interrupts every TimerTicks.

3.9.3 Questions

1. Briefly trace through the generation of a timer interrupt.

2. What command-line flag causes the boolean, doRandom, to be set to TRUE?

3. Why isn't TimerHandler() a member function?

3.10 Translate

3.10.1 translate.h

Defines the TranslationEntry class (used for page table and TLB entries).

3.10.2 translate.cc

Functions that translate virtual addresses to physical ones using either a page table or a TLB.

4. C++ Programming Excercise

4.1 Introduction

This is a small excercise designed to give you some experience reading and writing in the subset of C++ that we will use for this class.

4.2 Getting Started

In the directory /c/cs422/as0, you will find the source code for a List class, and a small test program. This implementation of lists was copied from the List class used in the Nachos threads system. The source code for the two versions of List are essentially identical; the version you will use here was only modified to allow it to be compiled without the rest of Nachos.

To try out the program, do the following:

  1. Create a working directory, and copy the source files.

    $ cd ~/cs422
    $ mkdir as0
    $ cd as0
    $ cp /c/cs422/as0/* .
    
    These commands create a working directory, ~/cs422/as0 in which you can work on this assignment, and copy the source files from the class directory.

  2. Type 'make'.

    This will build a program, test1, from two C++ source files:

    list.cc
    implementation of List class
    test1.cc
    simple test of the List class.

  3. Run 'test1':

    You should be able to run the program test1, which should give the following output:

    $ ./test1
    this is a test
    $
    

4.3 Your Mission

If you read the source code to test1.cc, you will notice that it first adds some data to the list (a bunch of strings), and then prints the contents of the list by removing each element from the list.

If you study the code that prints the contents of the list, you might notice that the design of this List class is somewhat limited, in that the only way to examine the contents of a list is to remove all the elements from the list! That is, there is no way to simply iterate through the contents of the list without destroying the list in the process.

To remedy this deficiency, we can introduce another class, ListIterator. A ListIterator allows code outside of the List class to iterate over the contents of a list without destroying the list. The ListIterator class is defined in the file listiterator.h, and is used in test2.cc. You should start by reading the code in test2.cc to understand how the ListIterator class is used, and how a ListIterator it is obtained from a List.

In the supplied Makefile, there is already a target for test2. If you type make test2, make will attempt to build test2. But this will elicit compilation errors, because iterators have not been implemented yet.

You should do the following:

Note: When you modify existing source files, you must mark changes using the commenting convention described in Assignment Mechanics!

4.4 One Last Thing

The whole point of the previous excercise was to implement a non-destructive iterator class, which would not destroy a list in the process of iterating over the elements.

Joe Dimwit isn't a very clever programmer, and doesn't read too closely. He implemented a version of the ListIterator class that simply returns the result of a call to List::Remove() every time that ListIterator::GetNext() is called.

Unfortunately, Joe Dimwit's version of test2 works, and produces the same output as your version! Why?

You should modify the test case test2.cc in such a way that it will fail with Joe Dimwit's implementation of ListIterator, but will work with your version. If you wish, you may change the output that test2 produces. The description of this test, along with sample output, should be placed in your TESTCASES file.

5. What to turn in

Your submission for this assignment should include the following:

You should submit your answers to section 3 along with a printout of your README for section 4 to the TA's mailbox.

You should submit your sources to this assignment using the standard submit script. The easiest way to do this is to submit all source files (including Makefile, README and TESTCASES) in your working directory. I recommend simply doing a 'make clean' to remove all object files, and then submit'ing all files, as follows:

$ make clean
$ /c/cs422/bin/submit 0 *

Don't forget that no late submissions will be accepted for this assignment!