ECS 50: Programming Assignment #6
Spring 2021
Contents
1 Changelog 1
2 General Submission Details 1
3 Grading Breakdown 1
4 Submitting on Gradescope 2
5 RV32EM 2
6 RISC-V Simulator 2
6.1 Accessing My CSIF Installation of the Simulator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
6.2 Installing the Simulator Yourself . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
7 Simulator Example Program 3
8 Relevant I/O Concepts in the Example Code 3
9 Your Assignment 4
9.1 Other Notes Regarding Use of the Simulator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
1 Changelog
You should always refer to the latest version of this document.
• v.1: Initial version.
• v.2: Removed mention of Windows Subsystem for Linux. To Windows users, I’d recommend MobaXTerm.
2 General Submission Details
Partnering on this assignment is prohibited. If you have not already, you should read the section on
academic misconduct in the syllabus.
This assignment is due the night of Tuesday, 06/08. Gradescope will say 12:30 AM on Wednesday, 06/09, due to the
“grace period” (as described in the syllabus). Be careful about relying on the grace period for extra time; this could be risky.
3 Grading Breakdown
As stated in the updated syllabus, this assignment is worth 8% of your final grade.
∗This content is protected and may not be shared, uploaded, or distributed.
1
4 Submitting on Gradescope
Files to submit:
• main.c
You may be penalized for submitting unnecessary files.
There is no autograder for this assignment. You must simply submit your code to Gradescope, and – after the
deadline – I will grade the submissions. (Make sure your file’s name is correct!) I will do this on the CSIF, so the CSIF is
still the reference environment.
Your output must match mine exactly.
5 RV32EM
Since you will write C code in this assignment, the exact details on RV32EM are not too important, but I include them
here for your own edification.
While introducing RISC-V during lecture, I very briefly talked about different extensions to RISC-V. Such extensions
include, for instance, the M extension for multiplication/division instructions and the FD extension for single/double floatingpoint
instructions.
In this assignment, you will write C code that can be run on a RV32EM processor. The “32” means that the processor
is a 32-bit processor instead of a 64-bit processor, so addresses are 32 bits. The “M” refers to the M extension mentioned
earlier. The “E” refers to the E extension, which helps to support low-end cores / embedded systems. Low-end cores are
cheap; consequently, an RV32EM processor only has 16 registers, x0 through x15. (Where applicable, registers still maintain
their special meaning. For instance, x0 is still hard-wired to always be zero, and x2 is the stack pointer.)
6 RISC-V Simulator
In this assignment, you will use Professor Chris Nitta’s RISC-V simulator that can be found here. You should skim the
readme to get a glance at what you’ll be dealing with.
There are two ways that you can use the simulator, and I talk about both ways below. The first way should be much
easier than the second way.
• Accessing my CSIF installation of the simulator.
• Installing the simulator yourself.
6.1 Accessing My CSIF Installation of the Simulator
Note on ssh Command: Since the simulator is a graphical application, you will need to enable something called X11
forwarding. I have personally confirmed that on a Linux machine and on a Windows machine (with a Linux command line
like MobaXTerm), this can be done by using the -X flag1
in the ssh command that you use for logging on to the CSIF. I
imagine it would be similar on a Mac. I don’t know how to enable X11 forwarding on Putty on Windows; to Windows users,
I would recommend MobaXTerm.
Running the Simulator: I have already installed the simulator in my CSIF files. You can run the simulator with the
following command2
.
1 / home / aaron123 / riscv - console / runsim . sh
This will open the simulator. You can run the simulator as a background task (with &) if you want to continue using the
same terminal that you used to open the simulator.
At this point, you can follow along with Professor Nitta’s example here. Note the following:
• Ignore launching the simulator with /code/runsim.sh.
• Presumably, the example files will not be in the same place on your end that they are in his walkthrough. You can find
the example files here or on Canvas in the riscv-example folder. (I included a zipped version too, in case it’s convenient.)
1Someone once mentioned to me the -Y flag as an alternative; I’ve never tried this flag.
2Note that if you copy-and-paste the below line from this PDF, there may be unexpected spaces or strange characters in the result, as this
tends to occur when one copies-and-pastes from a PDF.
2
As stated in Professor Nitta’s documentation for the simulator, you can use the -d flag to enable debug mode; just pass
it as a command-line argument to the script.
Regarding compilation (of your code): As mentioned below, you will use a provided makefile in order to compile
your code. You will need to add the path to the RV32EM C compiler (that I’ve installed) to your PATH environment variable.
You can do that with a line like the below3
.
1 export PATH = $PATH :/ home / aaron123 / opt / riscv32 / bin
I believe that you would have to type the above line on the command line each type you log in to the CSIF. If you want
to avoid having to do this, then I would recommend adding the above line to a .bash_aliases file (in your home directory on
the CSIF) and putting the following line in the .bashrc file (that should already be in your home directory on the CSIF):
source ~/.bash_aliases. Each time that you open a new session on the CSIF, the .bashrc file will be checked, which in turn
means that the .bash_aliases file will be checked.
6.2 Installing the Simulator Yourself
I would not recommend this way. I would recommend using the simulator on the CSIF in order to save yourself time.
Follow the directions that Professor Nitta provides here. Expect this process to take a few hours.
7 Simulator Example Program
As mentioned above, the example code can be found here, and it is also provided on Canvas. These files are described
below. You need all of these files for what you are going to be doing in this assignment, because – as mentioned
below – you will be modifying main.c. Note, however, that you do not need to understand much of what is in
the files, except for main.c and (maybe4
) a bit of what’s in src/startup.c.
• Makefile: for compilation.
• riscv32-console.ld: linker file that is also for compilation.
• src/crt0.s: The code in this file helps set up an interrupt handler (and other things). This code contains the _start
label, which is the true starting point of the program. (Notice that main() is called at the bottom.)
• src/interrupt.s: This file contains the interrupt handler, which preserves registers, calls another function called c_interrupt_handler
() to do most of the work, and returns with mret. (This mret instruction is similar to iret in x86 in that it is an instruction
specifically used for returning from an interrupt handler.)
• src/main.c: main() is defined here. This is where much of the action occurs; see below for more details.
• src/startup.c: This file has code for helping with certain things related to I/O and interrupts, including the definition
of the c_interrupt_handler() function that is called by the interrupt handler.
You should make sure that you can run the simulator and that you use the example on the simulator as Professor Nitta
shows in the documentation. The rest of what I say here won’t make much sense if you have not even tried the example yet
or at least seen what the example is supposed to do.
8 Relevant I/O Concepts in the Example Code
As you know, there are two categories of approaches for interacting with I/O ports:

  1. The I/O address space approach, which is what x86 does.
  2. The memory-mapped I/O approach, which is what RISC-V does.
    In the memory-mapped I/O approach, certain memory addresses correspond to I/O ports. You can find what those
    addresses are (for Professor Nitta’s RV32EM simulator) if you look at the documentation here. As an example, according
    to here, the text data of the video controller (controlling what text shows up on the screen) starts at address 500F E80016.
    This is why you see – in the example code’s main.c – that VIDEO_MEMORY has a starting address of 500F E80016. This address is
    mapped to the top-left corner of the screen, meaning that if we do VIDEO_MEMORY[0] = ’a’, then a lowercase ‘a’ will appear at
    the top-left of the screen. The following address, 500F E80116, is mapped to the spot immediately to the right of the top-left
    corner, and so on for 500F E80216. You should be able to understand how the example code gets “Hello, World!” to show
    up on the screen.
    As stated here, the screen is 64 x 36 characters.
    3See my earlier footnote about what can go wrong if you copy-and-paste from a PDF.
    4
    i.e. insofar as it is relevant to the final exam concepts
    3
    The example code uses an infinite loop, since there’s no reason for the program to end. Within that infinite loop, some
    stuff is done with the global and last_global variables in order to prevent the example from being overly responsive to inputs.
    Once we check the value of controller_status, things become interesting again. Here, we are checking if any button has
    been pressed. This is done by checking the multi-button controller status register5
    , which – as stated here can be accessed
    by reading the value that is at address 4000001816. The code in startup.c set things up so that reading the controller_status
    variable will get what’s at address 4000001816. When you read from the multi-button controller status register, you get a
    4-byte value in which certain bits have special meaning. You can read more here. As examples of how to interpret the bits,
    you can check if the left direction button is pressed by checking if bit #0 is set, and you can check if the up direction button
    is pressed by checking if bit #1 is set. You should be able to understand how the buttons are checked in main.c.
    For More Information: There are many other concepts related to RISC-V’s handling of I/O and interrupts that we will
    not go into here. If you want more information, you may find Chapter 10 of The RISC-V Reader: An Open Architecture
    Atlas by David Patterson and Andrew Waterman to be useful.
  3. Your Assignment
    For this assignment, you must make the following modifications to main.c:
    • No longer print “Hello, World!”.
    • The top row and bottom row of the screen should be equal signs.
    • The left and right columns of the screen should be vertical bars.
    • The user (the “X”) should no longer be allowed to move to the top row, bottom row, left column, or right column.
    • The user’s icon (the “X”) should start at the top-left most point that it is allowed to be at.
    • Any other spot on the screen should contain a “.” at the start.
    • When the user moves, the user should consume/remove any “.” that are touched.
    • Instead of moving with the WASD keys/buttons, the user should now move with the UIJK keys/buttons. Specifically:
    – U button: leftward movement.
    – J button: downward movement.
    – K button: rightward movement.
    – I button: upward movement.
    Below is an example of what compilation looks like. You do not need to do the export line each time, just once per CSIF
    session. (If you don’t do it, then you should get a compiler error message complaining that riscv32-unknown-elf-gcc does not
    exist.)
  4. $ ls
  5. Makefile riscv32 - console . ld src
  6. $ ls src
  7. crt0 .s interrupt . s main .c startup .c
  8. $ export PATH = $PATH :/ home / aaron123 / opt / riscv32 / bin
  9. $ make
  10. mkdir -p ./ obj
  11. mkdir -p ./ bin
  12. riscv32 - unknown - elf - gcc -O0 -g - ggdb - ffreestanding - nostartfiles - nostdlib - nodefaultlibs - DDEBUG -I ./
    include -c src / main .c -o obj / main . o
  13. riscv32 - unknown - elf - gcc -O0 -g - ggdb - ffreestanding - nostartfiles - nostdlib - nodefaultlibs - DDEBUG -I ./
    include -c src / crt0 .s -o obj / crt0 . o
  14. riscv32 - unknown - elf - gcc -O0 -g - ggdb - ffreestanding - nostartfiles - nostdlib - nodefaultlibs - DDEBUG -I ./
    include -c src / interrupt .s -o obj / interrupt .o
  15. riscv32 - unknown - elf - gcc -O0 -g - ggdb - ffreestanding - nostartfiles - nostdlib - nodefaultlibs - DDEBUG -I ./
    include -c src / startup .c -o obj / startup .o
  16. riscv32 - unknown - elf - gcc ./ obj / main .o ./ obj / crt0 .o ./ obj / interrupt . o ./ obj / startup .o -o ./ bin / riscv - console
  17. example -O0 -g - ggdb - ffreestanding - nostartfiles - nostdlib - nodefaultlibs - DDEBUG -Wl , --gc -
    sections -Wl ,-T , riscv32 - console . ld
  18. / home / aaron123 / opt / riscv32 / lib / gcc / riscv32 - unknown - elf /10.2.0/../../../../ riscv32 - unknown - elf / bin / ld :
    cannot find default versions of the ISA extension ‘i ’
  19. / home / aaron123 / opt / riscv32 / lib / gcc / riscv32 - unknown - elf /10.2.0/../../../../ riscv32 - unknown - elf / bin / ld :
    cannot find default versions of the ISA extension ‘i ’
  20. / home / aaron123 / opt / riscv32 / lib / gcc / riscv32 - unknown - elf /10.2.0/../../../../ riscv32 - unknown - elf / bin / ld :
    cannot find default versions of the ISA extension ‘i ’
  21. / home / aaron123 / opt / riscv32 / lib / gcc / riscv32 - unknown - elf /10.2.0/../../../../ riscv32 - unknown - elf / bin / ld :
    cannot find default versions of the ISA extension ‘i ’
  22. / home / aaron123 / opt / riscv32 / lib / gcc / riscv32 - unknown - elf /10.2.0/../../../../ riscv32 - unknown - elf / bin / ld :
    cannot find default versions of the ISA extension ‘i ’
    5Do not confuse this kind of “register” with the kinds of general-purpose registers like a0 and s1 that you can (for the most part) freely access
    and use in RISC-V assembly code. “Register” is a bit of an overloaded term.
    4
  23. / home / aaron123 / opt / riscv32 / lib / gcc / riscv32 - unknown - elf /10.2.0/../../../../ riscv32 - unknown - elf / bin / ld :
    cannot find default versions of the ISA extension ‘i ’
  24. riscv32 - unknown - elf - strip ./ bin / riscv - console - example -o ./ bin / riscv - console - example . strip
  25. $ ls
  26. bin Makefile obj riscv32 - console . ld src
  27. $ ls bin
  28. riscv - console - example riscv - console - example . strip
    Below, I show some screenshots of my running my own solution in the simulator.
    • This image shows what the screen should look like at the start.
    • If I press the K button (or – as I prefer – “k” on the keyboard), then the “X” moves right, consuming any “.” marks
    that are on the way. At this point, pressing “i” (the I button) does nothing, since I cannot move any further up.
    • Pressing “j” (the J button) causes the “X” to move down.
    5
    • In the below image, I am as far down as I can go; pressing “j” will do nothing.
    • In the below image, I am as far to the right as I can go; pressing “k” will do nothing.
    6
    You should not have to modify the while loop or either of the outermost if statements in main(). As stated previously,
    you are only submitting main.c, so you should not bother modifying any other file in the setup.
    9.1 Other Notes Regarding Use of the Simulator
    When I SSH onto the CSIF from a Ubuntu computer and use the file explorer that pops up when I try to choose firmware,
    I cannot seem to double-click folders to open them and instead have to click Open at the top right. This is not an issue when
    I SSH onto the CSIF from a Windows computer or when I run the simulator directly on my Ubuntu computer. I only point
    this issue out because I think that it could trick students into thinking that their connection to the CSIF suddenly failed or
    that they’re having internet issues.
    In general, I prefer to use the keyboard for pressing the buttons, e.g. pressing “u” instead of clicking the “u” button. I
    find that sometimes, when I click the buttons, they get stuck in a pushed position, as if they’re always clicked.
    I’m not quite sure how helpful the debug mode of the simulator will be in this assignment, since you are not writing
    assembly code. However, I am acquainted with the debug mode, so if you have questions about it, feel free to ask me.
    WX:codehelp

位错梦的寐
1 声望0 粉丝