Before embarking on an enjoyable PA journey

PA is a whole new kind of training

We compare different assignments/experiments/problems in terms of:

FundamentalsCourse of actionRisk of correctnessExamples
DocumentedClearMostly CorrectHigh School Physics Lab
DocumentedClearMight go wrongProgramming assignments
DocumentedNeed researchMostly CorrectMathematical proof/algorithm design questions
DocumentedNeed researchMight go wrongPA, OSlab
Need researchNeed researchMight go wrongReal world issue in industry / academia

The ultimate goal of PA is to gain a deeper understanding of how programs work on computers by building a simple and complete computer system. Unlike programming assignments that "recursively implement Hannover Towers", computer systems are much more complex than Hannover Towers. This means that training through programming assignments is not enough to complete PA, and that the only way to complete PA is to try to understand and master every detail of the computer system, step by step.

So don't complain about the lack of clarity in the PA handouts in the style of a programming assignment. The reason why the handouts are so brief is to force you to make sense of every detail of the computer system and the relationships between the modules, and to build up enough understanding of the system to face the unknown bugs.

This may be an unprecedented way for you to train, so you need to take on a new challenge with a new attitude.

The right way to do PA - start today, don't be lazy (this is a bowl of chicken soup, when you feel lost in the future, come back here to read it)

Let's list some mistakes.

  • If you have a problem, try to fix it blindly, maybe it will pass.
  • If you can't pass the test with blindly trying to fix it, crying for an TA to fix the problem for you.
  • Don't want to spend time and effort following How-To-Ask-Questions-The-Smart-Wayopen in new window and Stop-Ask-Questions-The-Stupid-Waysopen in new window.
  • This function/file/command is not understandable, anyway, I didn't write it, forget about it
  • I'd rather waste my life comfortably in Baidu than use Google to solve a problem quickly.
  • The blue box questions don't count, it's okay if you don't read them.
  • Anyway, there is a month for the big stage, start doing it in the last week, you should still be able to catch up.

If you adopt the above approach, you may be able to complete the pre-experimentation content really quickly, but this is at the cost of giving up training opportunities. As the experiment progresses, you will feel that PA is becoming more and more of a challenge for you.

The right thing to do is:

  • Think more about why
    • It's also good to start with a problem to understand the system
  • Solve problems independently.
    • Even if it's to fix a stupid bug, you'll learn more than you think.
    • In other words, if you choose to rely others, you're missing out on more opportunities than you realize
  • Try to understand every detail
    • when it comes to bug fixing, those details are a powerful tool in your hand
    • In other words, when you feel at a loss when tweaking a bug, it's because you don't understand the details
  • Doing things with the right tools
    • That's the science of saving time, not being lazy
  • Read the handouts. There are a lot of easter eggs.
    • There are a lot of out-of-place hints in the handouts, and some of them take more than one reading to understand.
    • One more question in the blue box may save you a few days of bug fixing.
  • Finish on time, don't procrastinate
    • So that you have time to do all of the above

In fact, these practices are the most essential training in PA, and such training has already started in PA0: the reason why PA0 let people install the machine from scratch is to let them gain experience in solving small problems, which can be used to solve bigger problems; at the same time, it also spreads the original belief that "I can solve problems independently by STFW and RTFM", and this belief can help people dispel the fear of the unknown.

The mentality you use to cope with your programming assignments will not work here at PA, and problems will be exposed much faster than you think. So, starting today, don't be lazy.

What is NEMU?

PA aims to implement NEMU, a simplified system-wide emulator. But what is an emulator?

When you were a kid, you probably played NES, Super Mario, Tanks, Contra... Do you still remember their graphics? (I hope there's no generation gap between us...) With the development of time, you can hardly find NES machines in the market. While you are feeling frustrated, the emergence of emulators has awakened your childhood memories. NES Emulator can simulate all the NES game for you. With it, it's like you have a real NES, and you can play your favorite NES games. We ported a NES emulator project FCEUXopen in new window, which you have cloned in PA0. It's amazing that you can relive your childhood days again in this emulator in the post NES days!

Aren't you going to play?

We have provided ROMs of some games for testing at hereopen in new window (may need to be accessed from within the campus network), read and follow fceux-am/README.md to run Super Mario in a pop-up

You can also put in other ROM files that you have obtained from STFW, so that you can run other games.

Check the screen, buttons and sound

While running the game, you need to check that you can see the screen, respond to button presses and hear the sound. Super Mario doesn't play sound in the initial screen, but it will play sound when you enter a level. If there is no sound, it will affect the optional part of the PA, but will not affect the grade; however, if the screen does not display properly, it may affect the mandatory part of the PA, so please search for a solution yourself.

cIn order to check the buttons, you need to clone a new sub-project am-kernels, which contains some test programs:

cd ics2023
bash init.sh am-kernels

Then run one of the button test programs.

cd am-kernels/tests/am-tests
make ARCH=native mainargs=k run

After running the program, a new window will pop up, press a key in the new window, you will see the program output the corresponding key information in the terminal, including the key name, keyboard code, and key status. If you find that the output key information does not match the key pressed, please search for a solution by yourself (using keywords like "SDL keystroke", etc.). Some users suggest that the problem may be related to Chinese input method compatibility problemopen in new window, for reference.

I think the compilation is a bit slow?

The make program uses a single thread to compile all files sequentially by default, and with FCEUX's large number of source files, you may have to wait up to ten seconds for the compilation to complete. But nowadays CPUs are multi-core and multi-threaded, so it's a waste of computing power not to use it. To speed up the compilation process, we can have make create multiple threads to compile the files in parallel.

To do this, first you need to query how many CPUs are on your system with the lscpu command. Then run make with -j? parameter, where ? is the number of CPUs you queried. For example, -j4 means to create 4 threads to compile in parallel, if the number of CPUs in the system is greater than or equal to 4, then the operating system can schedule these 4 threads to execute on 4 CPUs at the same time to achieve the acceleration effect; however, if there are only 2 CPUs in the system, then the operating system can at most schedule 2 threads to execute on 2 CPUs at the same time, and the acceleration effect is similar to that of -j2.

To see how the compilation speedup affects you, you can add the time command to the front of the compilation command, which will count the execution time of the commands that follow it, so all you need to do is look at the total column. You can clear all the results with make clean, then recompile and count the times, comparing single-threaded compilation to multi-threaded compilation; you can also try compiling with a different number of threads and compare the speedups.

Still too slow?

After we clear all the compilation results and recompile, the source files have not changed at all, so it is reasonable that the compiled target files should be exactly the same as the last compilation results. In that case, can we save the target files in some way, so that the next time we compile, if we find that the source files have not changed, we can just take out the target files as the result of the compilation, thus skipping the compilation step?

There really is a tool to do this! It's called ccache.

apt-get install ccache

If you read the ccache manual through man, you will see that ccache is a compiler cache. ccache is a term used in the computer field, and you will learn about it in a subsequent ICS course.

In order to use ccache, you need to do some configuration work. First, run the following command to see where a command is located.

which gcc

By default, it outputs /usr/bin/gcc, which means that when you run gcc, you are actually running /usr/bin/gcc. As an exercise in RTFM, you need to read the contents of man ccache and set an environment variable in the .bashrc file according to the manual. If you set it correctly and it takes effect, re-run which gcc, and you will see that the output becomes /usr/lib/ccache/gcc. If you don't know about environment variables and .bashrc, STFW.

Now it's time to experience the effects of ccache. First make clean to clear the result, then recompile and count the time. You'll notice that this time it takes a bit longer than before, because ccache takes the time to save the target file in addition to doing the normal compilation work. If you clear the results again, recompile and count the times, you will see that the second compilation is much faster! This means that ccache is indeed speeding up the process by skipping a completely repetitive compilation. If used in conjunction with multi-threaded compilation, the compilation can be accelerated even further!

In the process of developing a project, sometimes you do need to do a fresh build after make clean the compilation results. In the later stages of a PA, you may be compiling libraries containing hundreds of files several times, and in these cases, ccache can save you a lot of compilation time, thus improving the efficiency of your project.

You are overwhelmed by the power of computers, and you wonder, how does this happen? You've taken a basic programming course, but you still can't find the answer you're looking for. But you're sure that the NES emulator is just an ordinary program, because you still need to run it like a Hello World program. But at the same time, you think, NES emulator is not like a normal program, how does it emulate the world of NES, so that NES games can run in this world?

In fact, NEMU does something similar! It simulates a hardware world in which you can execute programs. In other words, you'll be writing a program that executes other programs in PA! In order to better understand the functionality of NEMU, here are some of the things you can do with it

  • Run Hello World programs in GNU/Linux.
  • Play Super Mario in GNU/Linux through the NES emulator.
  • Run the Hello World program through NEMU in GNU/Linux.

Compare these three scenarios.

                         +---------------------+  +---------------------+
                         |     Super Mario     |  |    "Hello World"    |
                         +---------------------+  +---------------------+
                         |    Simulated NES    |  |      Simulated      |
                         |       hardware      |  |       hardware      |
+---------------------+  +---------------------+  +---------------------+
|    "Hello World"    |  |     NES Emulator    |  |        NEMU         |
+---------------------+  +---------------------+  +---------------------+
|      GNU/Linux      |  |      GNU/Linux      |  |      GNU/Linux      |
+---------------------+  +---------------------+  +---------------------+
|    Real hardware    |  |    Real hardware    |  |    Real hardware    |
+---------------------+  +---------------------+  +---------------------+
          (a)                      (b)                     (c)

Figure (a) illustrates the "Hello World in GNU/Linux" scenario. The GNU/Linux operating system runs directly on real computer hardware, abstracts the underlying computer hardware, and provides interfaces and services to the higher-level user programs. When the Hello World program outputs information, it needs to use the interface provided by the operating system, so the Hello World program does not run directly on the real computer hardware, but on the operating system (in this case, GNU/Linux).

Figure (b) shows "playing Super Mario on NES emulator in GNU/Linux". To GNU/Linux, the NES Emulator running on it is nothing more than a user program, just like the Hello World program mentioned above. The amazing thing is that the NES Emulator is responsible for simulating a complete set of NES hardware on which Super Mario can run. The fact that Super Mario can't tell whether it's running on real NES hardware or simulated NES hardware is a blindfold for the "emulator".

Figure (c) illustrates "Hello World in GNU/Linux via NEMU". To GNU/Linux, the NEMU running on it is just a user program like the Hello World program mentioned above. However, NEMU is responsible for emulating a set of computer hardware on which programs can run. In fact, the above figure only gives a basic understanding of NEMU, more details will be added in the following PA.

What is NEMU?

The above description may seem a bit obscure to you, so let's look at an example of an ATM machine.

An ATM is a physically existing machine, and its function is supported by physical circuitry and mechanical modules. For example, when we make a deposit at an ATM machine, the ATM machine will make a loud noise to make us believe that it is a real machine. On the other hand, third-party payment platforms are also very popular nowadays, such as Alipay. In fact, we can consider Alipay App as a simulated ATM machine, in which all the functions of a real ATM machine, including depositing, withdrawing, checking balance, transferring, etc., are implemented by the Alipay App program.

Similarly, NEMU is a simulated computer system, the basic functions of a physical computer are implemented in NEMU through the program. To simulate a computer system is not as difficult as you think. We can think of a computer as consisting of a number of hardware components that help each other to "run the program". In NEMU, each hardware component is modeled by a program-related data object, such as a variable, an array, a structure, etc.; and operations on these components are modeled by operations on the corresponding data objects. For example, NEMU uses an array to simulate memory, so reading or writing to this array is equivalent to reading or writing to memory.

We can think of the process of implementing NEMU as developing an Alipay app. The difference is that Alipay has the functionality of a real ATM, which is used for transactions, while NEMU has the functionality of a physical computer system, which is used to execute programs. Therefore, we say that NEMU is a program that executes other programs.

The power of NEMU will surprise you! Not only can it run small programs like Hello World, but later in PA, you'll be able to run the classic RPG Chinese Paladinopen in new window(cool! %>_<%). If you complete all the optional programming content, you can even run the modern text adventure game CLANNADopen in new window in NEMU! After completing PA, your knowledge of programming in your programming class will be turned upside down, you will feel that computers are no longer a mysterious black box, and you may even find that creating your own computer is no longer out of reach!

Select your character

New Feature - Multiple Main Lines

PA has a multi-mainline feature. Specifically, you need to start from one of the three x86open in new window / mips32open in new window / riscv32(64)open in new window Instruction Set Architecture (ISA)open in new window to achieve the dream of "creating your own computer".

But no matter which ISA you choose, you'll eventually realize the mechanics of "hardware and software working together to support the execution of a program": the so-called tradeoff is simply deciding whether to leave something to the hardware or to the software. However, each of the three ISAs has its own characteristics, and the difficulty level of the different chapters is shown in the table below (5 stars - easy, 1 star - hard).

x86mips32riscv32(64)
PA1 - Simple DebuggerNot very relevant for ISA selection
PA2 - Von Neumann Computer Systems
PA3 - Batch Processing Systems
PA4 - Time-sharing multitasking

What's an ISA?

Most textbooks will say something like "ISA is the interface between software and hardware", but for those of you who don't yet understand how software and hardware work together, the word "interface" is still too abstract.

To understand ISA, let's use a real-life example: a screw and a nut are two common objects that need to be paired. Given a screw, you need to find a nut that meets the same size specification, and vice versa.

It is similar in the computer world: computers (or hardware) of different architectures are like screws of different sizes, programs (or software) of different architectures are like nuts of different sizes, and if a program is to run on a computer of a particular architecture, the program and the computer must conform to the same set of specifications.

Therefore, the essence of ISA is something like this specification. So ISA exists not as hardware circuitry, nor as software code, but as a manual of specifications.

Similar to the production of nuts and bolts, computer hardware is constructed according to the ISA specification manual, and programs are written (or generated) according to the ISA specification manual. As to what is in the ISA specification, how should we construct a computer that conforms to the specification, and how should a program comply with the specification to run on a computer, answering these questions is one of the goals of doing a PA.

How do I choose?

If you're going to go for familiarity, then go for x86, after all ICS theory classes are largely centered around x86. But you'll probably die from the complexity of the x86 instructions, and the ultimate performance of x86 isn't really high enough to show a game running smoothly.

If you're going for simplicity, go for riscv32, and you'll realize what "elegant ISA design" means. Because of the simplicity of riscv32, you can easily get almost twice the performance of x86.

If you're going to design a riscv64 hardware processor next, go for the riscv64, and you'll see how DiffTest can help you dramatically improve your hardware development efficiency, and eliminate tedious waveform debugging.

If you want to push the boundaries, go for mips32: compared to the above two, mips32 requires a lot more detail to properly build a complete computer system. Therefore, the mips32 is only for those who like a challenge, or for those who want to take a second look at the program.

However, no matter which ISA you choose, one thing is common, and that is RTFM, because ISA is essentially a specification manual. Also, the NEMU program itself is x86 (x64 to be exact), and does not change depending on which ISA you choose, only the computer emulated in NEMU.

If you are a student enrolled in this program (Computer Systems Fundamentals), you have no choice!

You must select riscv32, otherwise your code will not work correctly when submitted to OJ. We ask you to do this because

  • riscv is modular, and choosing riscv32 involves implementing very few instructions.
  • You have already studied riscv32 in the "Digital Logic and Computer Composition" course in your second semester of college, so you will be more familiar with riscv32 than with other ISAs.
  • the infrastructure of the framework code has better support for riscv.

All of these reasons will help you to complete your PA more smoothly, so that you can devote more time to your final.

For convenience, the handout will use $ISA to denote the ISA you choose, for example, for nemu/src/isa/$ISA/reg.c, if you choose x86, it will denote nemu/src/isa/x86/reg.c; if you choose riscv32, it will denote nemu/src/isa/riscv32/reg.c. Unless the handout explicitly states otherwise, $ISA always indicates the ISA you chose, not the four characters $ISA.

NEMU's framework code uses riscv32 as the default ISA, if you wish to select a different ISA, you need to run make menuconfig in NEMU's project directory, and then switch to the ISA of your choice in the Base ISA menu, then save the configuration and exit the menu.

Finally, you will need to pick up the Beginner's Packet - ISA Related Survival Manuals (some non-ISA related manuals can be found at Handouts Home.

ISABeginner's Packet
x86Intel 80386 Programmer's Reference Manual (简称i386手册) (PDFopen in new window)(HTMLopen in new window)
System V ABI for i386open in new window
mips32MIPS32 Architecture For Programmers (Volume Iopen in new window, Volume IIopen in new window, Volume IIIopen in new window)
System V ABI for mips32open in new window
riscv32(64)The RISC-V Instruction Set Manual (Volume Iopen in new window, Volume IIopen in new window)
ABI for riscvopen in new window

riscv32 and riscv64

In fact, the differences between riscv32 and riscv64 are so small that their ISA manuals are identical. Therefore, most of the descriptions in the handouts for riscv32 are also applicable to riscv64. Where the descriptions do not apply to riscv64, we have added additional information. Therefore, if you choose riscv64, you can refer to the riscv32 handout if it does not contain additional information about riscv64.

What are you waiting for?

Let's get this exciting journey started!

Be a qualified CSer!

In addition to the ultimate goal of showing you how a program executes in a computer, PA has added a lot of scientific principles to the mix. PA tries to create scenarios to make you realize the importance of these principles, which is also a must for a qualified CSer. If you're just looking at PA as a big programming mission, we believe you're missing out.

PA is a game that deserves a second playthrough, during which you will gain a deeper understanding of these principles. The multi-mainline nature of the game also keeps it from getting too boring, and the handout has some good questions for you to think about in the second week, so we hope you have fun!

Record your experiments every day

We have seen many times in the lab reports of your seniors the regret of not keeping track of your lab experience and forgetting the details of your experience when writing the lab report. In order to share your experiences with your TAs, we suggest that you keep a record of what you learned during the experiment, such as a big pit you stepped on, or a retarded bug you found after a week of tweaking, etc. We believe that when you finish the experiment, you will have a good idea of what you have learned and what you have learned.

We believe that when you come back to read these notes after your PA, you will realize that they are a valuable asset to you.