CS计算机代考程序代写 RISC-V chain compiler concurrency assembly Project 2

Project 2

ECS150 FQ21 October 18, 2021

This content is protected and may not be shared, uploaded, or distributed.

Project 2

1 of 19

Project 2
Due October 25, 2021 at 9:00 PM

You will be working with a partner for this project. This specification is subject to change at

anytime for additional clarification.

Desired Outcomes

• Exposure to low level RISC-V programming

• An understanding of how system calls are implemented

• Exposure to concurrency and non-determinism
Project Description

For this project, you will be writing the beginnings of a simple operating system designed to run

on a RISC-V based game console called RVCOS. Your OS must be written in C and RISC-V

assembly. You may use the C standard library newlib that is built into the environment, this will

be particularly helpful for malloc and free. You will want to begin by getting the simulation

environment downloaded and up and running. The tools you will need for this project are in a git

repository at https://github.com/UCDClassNitta/riscv-console. There are directions for getting up

and running on multiple systems assuming you already have Docker installed. We may be adding

more features to help debugging as time goes on, and will update as that occurs. Note that the build

of gcc will take a long time, so you should get the tools up and running ASAP.

The RISC-V gcc version necessary has been built and runs on the CSIF. It is currently in

/home/cjnitta/riscv32/bin You can add this to your path with the following command

and will be able to make the example as if compiling it within the Docker container.
export PATH=”$PATH:/home/cjnitta/riscv32/bin”

The simulator is on the CSIF at /home/cjnitta/ecs150/riscv-console-sim. You can

do X11 forwarding to execute the simulator remotely. See directions for X11 forwarding on CSIF

docs here. Running through X11 from the CSIF will be slow and likely problematic if desiring to

run full speed; however, for debugging and stepping through the code it should be fine.

The simulated hardware you will be developing your operating system for has a RISC-V RV32EM

processor with only machine mode enabled. This means that only the first 16 registers are valid,

and the integer multiply/divide instructions are supported. The game console is designed to support

cartridges that are inserted, so only one “application” will ever be running at a time. Since there is

only a single mode, the memory space is accessible to both the OS and the game application. The

memory map is shown in Table 1. The current version of RVCOS dedicates the low 2MiB of RAM

to OS and provides the upper 14MiB for the application. Figure 1shows the layout of the RAM for

the OS and the application, remember that the Text section will be in the Flash/ROM section.

Table 1. RISC-V Console Memory Map

Base Address Size Description

0x00000000 16MiB Firmware Flash

0x20000000 16MiB Cartridge ROM

0x40000000 72B Chipset Registers

0x50000000 1MiB Video Controller Memory

0x70000000 16MiB RAM

https://github.com/UCDClassNitta/riscv-console
http://csifdocs.cs.ucdavis.edu/about-us/csif-general-faq#TOC-How-do-I-allow-SSH-to-do-X11-Forwarding-for-forwarding-GUI-application-windows-

ECS150 FQ21 October 18, 2021

This content is protected and may not be shared, uploaded, or distributed.

Project 2

2 of 19

Figure 1. RAM Layout

The RVCOS API that you will mainly be developing for this this project are the thread APIs.

Figure 2 shows the possible states a RVCOS thread can be in as well as the transitions between

them. The threading support in RVCOS is designed for potentially short run threads that can

reactivated as needed. The reactivation allows for the rerunning of a thread without the overhead

of allocating resources.

Figure 2. RVCOS Thread States and Transitions

1. Thread created
2. Thread activated
3. Thread selected to run
4. Thread quantum expired or higher priority thread selected
5. Thread terminated
6. Thread unblocked due to I/O, other thread, or timeout
7. Thread blocked waiting for time, I/O or another thread

App

OS
0x70000000

0x70200000

0x71000000

Stack

Data

Heap

Stack

Data

Heap

gp for OS

gp for App

ECS150 FQ21 October 18, 2021

This content is protected and may not be shared, uploaded, or distributed.

Project 2

3 of 19

Threads have one of three priority levels (high, normal, and low), which is statically assigned at

creation. The main thread has normal thread priority. The highest priority ready thread always

runs, if a thread is preempted it is put to the end of its priority queue. If multiple threads are ready

at the same priority level, they each receive one quantum of time that is equivalent to one tick of

the timer. The current design is targeted to have one tick every two milliseconds.

Currently RVCOS will not support beyond 256 threads including the idle and main thread;

therefore, a maximum of 254 threads can be created through calls to RVCThreadCreate.

Directions for submitting will be posted later. The following sections describe the API in more

detail. A working compiled binary and working application examples will be posted soon.

You should avoid using existing source code as a primer that is currently available on the Internet.

You must specify in your readme file any sources of code that you have viewed to help you

complete this project. Any copied code snippets from online sources must have the URL source

in comments next to its use. All class projects will be submitted to MOSS to determine if pairs of

students have excessively collaborated with other pairs. Excessive collaboration, or failure to list

external code sources will result in the matter being transferred to Student Judicial Affairs.

ECS150 FQ21 October 18, 2021

This content is protected and may not be shared, uploaded, or distributed.

Project 2

4 of 19

Name

RVCOS – Initializes cartridge main thread in RVCOS

Synopsys
#include “RVCOS.h”

TStatus RVCInitalize(uint32_t *gp);

Description

RVCInitialize() initializes the cartridges main thread and sets the cartridges global pointer through

the gp variable. This system call be invoked as part of the cartridge startup code.

Return Value

Upon successful initialization of the main thread, RVCInitialize() will return

RVCOS_STATUS_SUCCESS. If RVCInitialize() function is called after the initialization it will

return RVCOS_STATUS_ ERROR_INVALID_STATE.

ECS150 FQ21 October 18, 2021

This content is protected and may not be shared, uploaded, or distributed.

Project 2

5 of 19

Name

RVCThreadCreate – Creates a thread in the RVCOS.

Synopsys
#include “RVCOS.H”

typedef TThreadReturn (*TThreadEntry)(void *);

TStatus RVCThreadCreate(TThreadEntry entry, void *param, TMemorySize memsize,

TThreadPriority prio, TThreadIDRef tid);

Description

RVCThreadCreate() creates a thread in the RVCOS. Once created the thread is in the created state

RVCOS_THREAD_STATE_CREATED. The entry parameter specifies the function of the

thread, and param specifies the parameter that is passed to the function. The size of the threads

stack is specified by memsize, and the priority is specified by prio. The thread identifier is put into

the location specified by the tid parameter.

Return Value

Upon successful creation of the thread RVCThreadCreate() returns

RVCOS_STATUS_SUCCESS. If either entry or tid is NULL, RVCThreadCreate() returns

RVCOS_STATUS_ERROR_INVALID_PARAMETER.

ECS150 FQ21 October 18, 2021

This content is protected and may not be shared, uploaded, or distributed.

Project 2

6 of 19

Name

RVCThreadDelete – Deletes a dead thread from the RVCOS.

Synopsys
#include “RVCOS.H”

TStatus RVCThreadDelete(TThreadID thread);

Description

RVCThreadDelete() deletes the dead thread specified by thread parameter from the RVCOS.

Return Value

Upon successful deletion of the thread from the RVCOS, RVCThreadDelete() returns

RVCOS_STATUS_SUCCESS. If the thread specified by the thread identifier thread does not

exist, RVCOS_STATUS_ERROR_INVALID_ID is returned. If the thread does exist but is not in

the RVCOS_THREAD_STATE_DEAD state, RVCOS_STATUS_ERROR_INVALID_STATE

is returned.

ECS150 FQ21 October 18, 2021

This content is protected and may not be shared, uploaded, or distributed.

Project 2

7 of 19

Name

RVCThreadActivate – Activates a newly created or dead thread in the RVCOS.

Synopsys
#include “RVCOS.H”

TStatus RVCThreadActivate(TThreadID thread);

Description

RVCThreadActivate() activates the newly created or dead thread specified by thread parameter in

the RVCOS. After activation the thread enters the RVCOS_THREAD_STATE_READY state,

and must begin at the entry function specified.

Return Value

Upon successful activation of the thread in the RVCOS, RVCThreadActivate() returns

RVCOS_STATUS_SUCCESS. If the thread specified by the thread identifier thread does not

exist, RVCOS_STATUS_ERROR_INVALID_ID is returned. If the thread does exist but is not in

the newly created or dead sates, RVCOS_THREAD_STATE_CREATED or

RVCOS_THREAD_STATE_DEAD, RVCOS_STATUS_ERROR_INVALID_STATE is

returned.

ECS150 FQ21 October 18, 2021

This content is protected and may not be shared, uploaded, or distributed.

Project 2

8 of 19

Name

RVCThreadTerminate – Terminates a thread in the RVCOS.

Synopsys
#include “RVCOS.H”

TStatus RVCThreadTerminate(TThreadID thread, TThreadReturn returnval);

Description

RVCThreadTerminate() terminates the thread specified by thread parameter in the RVCOS. After

termination the thread enters the state RVCOS_THREAD_STATE_DEAD, and the thread return

value returnval is stored for return values from RVCThreadWait(). The termination of a thread

can trigger another thread to be scheduled.

Return Value

Upon successful termination of the thread in the RVCOS, RVCThreadTerminate() returns

RVCOS_STATUS_SUCCESS. If the thread specified by the thread identifier thread does not

exist, RVCOS_STATUS_ERROR_INVALID_ID is returned. If the thread does exist but is in the

newly created or dead states, RVCOS_THREAD_STATE_CREATED or

RVCOS_THREAD_STATE_DEAD, RVCOS_STATUS_ERROR_INVALID_STATE is

returned.

ECS150 FQ21 October 18, 2021

This content is protected and may not be shared, uploaded, or distributed.

Project 2

9 of 19

Name

RVCThreadWait – Terminates a thread in the RVCOS.

Synopsys
#include “RVCOS.H”

TStatus RVCThreadWait(TThreadID thread, TThreadReturnRef returnref);

Description

RVCThreadWait() waits for the thread specified by thread parameter to terminate. The return

value passed with the associated RVCThreadTerminate() call will be placed in the location

specified by returnref. RVCThreadWait() can be called multiple times per thread.

Return Value

Upon successful termination of the thread in the RVCOS, RVCThreadWait() returns

RVCOS_STATUS_SUCCESS. If the thread specified by the thread identifier thread does not

exist, RVCOS_STATUS_ERROR_INVALID_ID is returned. If the parameter returnref is NULL,

RVCOS_STATUS_ERROR_INVALID_PARAMETER is returned.

ECS150 FQ21 October 18, 2021

This content is protected and may not be shared, uploaded, or distributed.

Project 2

10 of 19

Name

RVCThreadID – Retrieves thread identifier of the current operating thread.

Synopsys
#include “RVCOS.H”

TStatus RVCThreadID(TThreadIDRef threadref);

Description

RVCThreadID() puts the thread identifier of the currently running thread in the location specified

by threadref.

Return Value

Upon successful retrieval of the thread identifier from the RVCOS, RVCThreadID() returns

RVCOS_STATUS_SUCCESS. If the parameter threadref is NULL,

RVCOS_STATUS_ERROR_INVALID_PARAMETER is returned.

ECS150 FQ21 October 18, 2021

This content is protected and may not be shared, uploaded, or distributed.

Project 2

11 of 19

Name

RVCThreadState – Retrieves the state of a thread in the RVCOS.

Synopsys
#include “RVCOS.H”

#define RVCOS_THREAD_STATE_CREATED ((TThreadState)0x01)

#define RVCOS_THREAD_STATE_DEAD ((TThreadState)0x02)

#define RVCOS_THREAD_STATE_RUNNING ((TThreadState)0x03)

#define RVCOS_THREAD_STATE_READY ((TThreadState)0x04)

#define RVCOS_THREAD_STATE_WAITING ((TThreadState)0x05)

TStatus RVCThreadState(TThreadID thread, TThreadStateRef state);

Description

RVCThreadState() retrieves the state of the thread specified by thread and places the state in the

location specified by state.

Return Value

Upon successful retrieval of the thread state from the RVCOS, RVCThreadState() returns

RVCOS_STATUS_SUCCESS. If the thread specified by the thread identifier thread does not

exist, RVCOS_STATUS_ERROR_INVALID_ID is returned. If the parameter stateref is NULL,

RVCOS_STATUS_ERROR_INVALID_PARAMETER is returned.

ECS150 FQ21 October 18, 2021

This content is protected and may not be shared, uploaded, or distributed.

Project 2

12 of 19

Name

RVCThreadSleep – Puts the current thread in the RVCOS to sleep.

Synopsys
#include “RVCOS.H”

#define RVCOS_TIMEOUT_INFINITE ((TTick)0)

#define RVCOS_TIMEOUT_IMMEDIATE ((TTick)-1)

TStatus RVCThreadSleep(TTick tick);

Description

RVCThreadSleep() puts the currently running thread to sleep for tick ticks. If tick is specified as

RVCOS_TIMEOUT_IMMEDIATE the current process yields the remainder of its processing

quantum to the next ready process of equal priority.

Return Value

Upon successful sleep of the currently running thread, RVCThreadSleep() returns

RVCOS_STATUS_SUCCESS. If the sleep duration tick specified is

RVCOS_TIMEOUT_INFINITE, RVCOS_STATUS_ERROR_INVALID_PARAMETER is

returned.

ECS150 FQ21 October 18, 2021

This content is protected and may not be shared, uploaded, or distributed.

Project 2

13 of 19

Name

RVCWriteText – Writes text out to the RISC-V Console in text mode.

Synopsys
#include “RVCOS.H”

TStatus RVCWriteText(const TTextCharacter *buffer, TMemorySize writesize);

Description

RVCWriteText() writes writesize characters starting at the location specified by buffer to the

RISC-V Console in text mode.

Return Value

Upon successful writing of characters to the console RVCWriteText() returns

RVCOS_STATUS_SUCCESS. If the buffer parameter is NULL,

RVCOS_STATUS_ERROR_INVALID_PARAMETER is returned.

ECS150 FQ21 October 18, 2021

This content is protected and may not be shared, uploaded, or distributed.

Project 2

14 of 19

Name

RVCReadController – Reads the current status of the RISC-V Console controller.

Synopsys
#include “RVCOS.H”

typedef struct{

uint32_t DLeft:1;

uint32_t DUp:1;

uint32_t DDown:1;

uint32_t DRight:1;

uint32_t DButton1:1;

uint32_t DButton2:1;

uint32_t DButton3:1;

uint32_t DButton4:1;

uint32_t DReserved:24;

} SControllerStatus, *SControllerStatusRef;

TStatus RVCReadController(SControllerStatusRef statusref);

Description

RVCReadController() reads the current status of the RISC-V Console controller into the location

specified by statusref.

Return Value

Upon successful reading the console controller status RVCReadController() returns

RVCOS_STATUS_SUCCESS. If the statusref parameter is NULL,

RVCOS_STATUS_ERROR_INVALID_PARAMETER is returned.

ECS150 FQ21 October 18, 2021

This content is protected and may not be shared, uploaded, or distributed.

Project 2

15 of 19

RVCOS System Call Calling Convention

The system call calling convention is shown in Table 2. Notice that register a5 is used to specify

the system number, this is so that the stub function only needs to set the register and not modify

any other registers to invoke the system call. The return value for system call is through register

a0, also so that the stub does not need to modify the return value location.

Table 2. RVCOS Calling Convention

System Call a0 a1 a2 a3 a4 a5

RVCInitalize gp 0x00

RVCThreadCreate entry param memsize prio tid 0x01

RVCThreadDelete thread 0x02

RVCThreadActivate thread 0x03

RVCThreadTerminate thread returnval 0x04

RVCThreadWait thread returnref 0x05

RVCThreadID threadref 0x06

RVCThreadState thread stateref 0x07

RVCThreadSleep tick 0x08

RVCTickMS tickmsref 0x09

RVCTickCount tickref 0x0A

RVCWriteText buffer writesize 0x0B

RVCReadController statusref 0x0C

ECS150 FQ21 October 18, 2021

This content is protected and may not be shared, uploaded, or distributed.

Project 2

16 of 19

Helpful Resources

Some resources you will find helpful:

• RISC-V Console Repository – The toolchain plus hardware description

• RISC-V Unprivileged Specification – Useful for normal instruction behavior

• RISC-V Privileged Specification – Necessary for understanding exceptions

Suggested Approach

1. Get the tools up and running. Make the example from the repository and run it.
2. Create a base OS firmware project based upon the example. Modify it to limit the memory

locations as specified and add support for malloc if using newlib.

3. Modify your OS so that it can jump to the application when a cartridge is input.
4. Add support for responding to system call when an ECALL instruction occurs.
5. Implement the RVCInitalize() system call to keep track of the application global pointer.
6. Add support for writing to the console in text mode. This will aid in debugging as well.
7. Add support to read from the control. This will add support for inputting.
8. Implement your TCB and create functions to initialize a context and to switch contexts.
9. Add support for querying all of the status/IDs of the threads.
10. Implement the hardware timing support and add sleeping support for the threads.
11. Add support for waiting/terminating of the threads.

Helpful Hints

• You will want to use a skeleton/wrapper function to be the initial entry point for the thread,
and for it to call the entry from the TRVCThreadCreate. This is necessary in case the

thread doesn’t explicitly call RVCThreadTerminate.

• You may need to use the volatile keyword for variables that may get modified during

an interrupt. The volatile keyword guarantees that the compiler will generate code to

go to memory for every access of the variable.

• You will likely want an idle thread that will execute when all other threads are blocked.
Conveniently the thread priorities are set to HIGH, NORMAL, and LOW as 3, 2, 1, so a

lower priority could be used for IDLE.

• The global pointer gp register points to 0x800 above the base of data section. It will be

different for the OS and the application, so take care when switching between the two.

• The thread pointer tp register is best to use to keep track of the current running thread, it

can either hold the thread ID, or a pointer to the TCB.

• The mepc register will likely need to be saved on the stack in the interrupt handler as it is

possible that threads will be switched during the interrupt and the mepc may be rewritten

from another interrupt in the interim.

• Page 40 of the Privileged spec has important information about the ECALL instruction.
“ECALL and EBREAK cause the receiving privilege mode’s epc register to be set to the

address of the ECALL or EBREAK instruction itself, not the address of the following

instruction.” You will either need to add 4 to the mepc before calling mret, or possibly set

the mepc to what ra is at the beginning of the interrupt, this will be the return address from

the system call stub.

https://github.com/UCDClassNitta/riscv-console
https://github.com/riscv/riscv-isa-manual/releases/download/Ratified-IMAFDQC/riscv-spec-20191213.pdf
https://github.com/riscv/riscv-isa-manual/releases/download/Ratified-IMFDQC-and-Priv-v1.11/riscv-privileged-20190608.pdf

ECS150 FQ21 October 18, 2021

This content is protected and may not be shared, uploaded, or distributed.

Project 2

17 of 19

• In order to use malloc _sbrk needs to be defined. An example of what it would look like

can be found at https://sourceware.org/newlib/libc.html#Syscalls. Instead of calling the

external variable _end, something like _heapbase might be more appropriate. This

will also need to be defined in the linker script as something like:
_heapbase = MAX(_edata,MAX(_esdata,_ebss));

Grading

The point breakdown can be seen in the table below. Make sure your code compiles on the CSIF

as that is where it is expected to run. You will make an interactive grading appointment with a TA

to have your assignment graded. You must have a working webcam for the interactive grading

appointment. Project submissions received 24hr prior to the due date/time will received 10% extra

credit. The extra credit bonus will drop off at a rate of 0.5% per hour after that, with no additional

credit being received for submissions within 4hr of the due date/time.

Points Description

5 Has Makefile and submission compiles

5 Has README with sources cited

10 Jumps into cartridge application when inserted

5 Responds to system call and return control to app

5 Initializes the main thread and returns control to cartridge

10 Supports text output to console

5 Able to read input from console controller

15 Able to create threads and switch contexts

5 Supports querying of status/thread ID of threads

5 Can setup and respond to timer interrupts

10 Threads can sleep and wait on other threads

10 Full applications execute correctly

10 Student understands all code they have provided

Change Log

2021-10-11 Added information about newlib in helpful hints, added RAM figure.

2021-10-12 Added change log, removed space from PATH in description. Added description

of scheduling behavior.

2021-10-14 Added description of maximum number of threads. Added explanation of mepc

with ECALL.

2021-10-17 Modified DReserved of SControllerStatus from 28 to 24 bits.

https://sourceware.org/newlib/libc.html#Syscalls

ECS150 FQ21 October 18, 2021

This content is protected and may not be shared, uploaded, or distributed.

Project 2

18 of 19

ECS150 FQ21 October 18, 2021

This content is protected and may not be shared, uploaded, or distributed.

Project 2

19 of 19

Project 2
Name
Synopsys
Description
Return Value
Name
Synopsys
Description
Return Value
Name
Synopsys
Description
Return Value
Name
Synopsys
Description
Return Value
Name
Synopsys
Description
Return Value
Name
Synopsys
Description
Return Value
Name
Synopsys
Description
Return Value
Name
Synopsys
Description
Return Value
Name
Synopsys
Description
Return Value
Name
Synopsys
Description
Return Value
Name
Synopsys
Description
Return Value