Some Programming/Reference Manuals
- Volume 1, Unprivileged Specification version 20240411 PDF GitHub
- Volume 2, Privileged Specification version 20240411 PDF GitHub
- PLIC Specs v1.0.0
For newest PLIC manual please refer to https://riscv.org/technical/specifications/ and https://github.com/riscv/riscv-plic-spec/releases - NS16550 UART(Texus Instrument)
cf. Section 8.6 for register specification.Note on CSR instructions
CSR can't be accessed directly, thus those instructions are needed.
Only 6 instructions, CSR[RS,RC,RW,RSI,RCI,RWI],I is immediate.
S for set, C for clear, W for write, other mnemonic(e.g. CSRR/CSRW) are pseudo-instructions with eitherrs1=x0
ords=x0
.
For both CSRRS and CSRRC, ifrs1=x0
, then the instruction will not write to the CSR at all
For both CSRRSI and CSRRCI, ifuimm[4:0] field is zero
, then the instruction will not write to the CSR at all
But CAVEAT LECTOR!, ifrs1=x0
oruimm[4:0]=0
forCSRRW or CSRRWI
, then csr will be CLEAREDIRQ number(PLIC source no./id) and MMAP(Memory Mapping) in ECE391 FA24
It is modified based on https://github.com/qemu/qemu/blob/master/hw/riscv/virt.c
7 uarts are added and IRQ number of RTC is moved to 9
Ext ASM in C code
- Do not expect a sequence of asm statements to remain perfectly consecutive after compilation, even when you are using the volatile qualifier. If certain instructions need to remain consecutive in the output, put them in a single multi-instruction asm statement.
\n\t
to seperate assembly instructions in a single Assembly Template
Input: using,
delimiter[ [asmSymbolicName] ] constraint (cexpression)
Output:
[ [asmSymbolicName] ] constraint (cvariablename)
- asmSymbolicName
Specifies a symbolic name for the operand. Reference the name in theassembler template
by enclosing it in square brackets (i.e. %[Value]). The scope of the name is the asm statement that contains the definition. Any valid C variable name is acceptable, including names already defined in the surrounding code. No two operands within the same asm statement can use the same symbolic name.
When not using an asmSymbolicName, use the (zero-based
) position of the operand in the list of operands in the assembler template. For example if there aretwo output operands
andthree inputs
, use%2
in the template to refer to thefirst input operand
, %3 for the second, and %4 for the third.
For example
uint32_t Mask = 1234;
uint32_t Index;
asm ("bsfl %[aMask], %[aIndex]"
: [aIndex] "=r" (Index)
: [aMask] "r" (Mask)
: "cc");
if no asmSymbolicName
__asm__ ("btsl %2,%1\n\t" // Turn on zero-based bit #Offset in Base.
"sbb %0,%0" // Use the CF to calculate old.
: "=r" (old), "+rm" (*Base)
: "Ir" (Offset)
: "cc");
return old;
output registers begin with 0, the number of input regs are after output regs.
If using I
(immediate) as constraint, the input value must be known at assembly time or later.
Control Status Registers(CSR)
mstatus:
mip:
mie:
mtvec:
mcause:
mepc:
PLIC
Each source has a priority(0 is disabled, higher for high prio).
destination is a contex, which is a HART combined with mode(M/S)
every context (e.g. context 0) has a source enable(not prio).
PLIC Indicates which interrupt source raised the interrupt by
Trap entry
- Places current PC into mepc CSR
- Sets mstatus.MPP to previous privilege mode (current privilege mode is decided by path)
- Sets mstatus.MPIE to mstatus.MIE
- Sets mstatus.MIE to 0 (interrupts disabled on entry)
- Sets PC to mtvec.BASE (if mode 0) or mtvec.BASE + 4×cause
Trap exit
- Sets mstatus.mie to mstatus.MPP ; sets MPIE to 1
- Changes privilege mode to mstatus.MPP; sets MPP to 0
- Set PC to mepc
You will get to the vector addr of Externel M-Mode Interrupt(mtvec[1:0]==2b'01) or just BASE(mtvec[1:0]==2b'00), then check which source issued the interrupt, then go to the corresponding ISR(interrupt service routine) or what so-called interrupt handler.
A CPU claims the interrupt to identify source - CPU reads special per-context claim register on PLIC
- PLIC returns highest priority source number on read
- PLIC will not offer the interrupt source to other CPUs
- CPU has committed to servicing it
CPU can always read claim register to poll for highest priority interruptEnd procedure for PLIC(Interrupt Completion)
When CPU is finished servicing the itnerrupt, it signals completion to the PLIC
- CPU writes source number to its claim register on PLIC
- This indicates CPU is done servicing the interrupt source