Status: In progress
Contributed by <Yu Jui Huang>
Real-time Update in Notion <Link>
In the foundational RV32I Instruction Set Architecture (ISA), there exist four fundamental instruction formats denoted as R, I, S, and U. These formats are consistently 32 bits in length and necessitate alignment on a four-byte boundary within memory. If a branch or unconditional jump is executed and the target address is not aligned to a four-byte boundary, an instruction-address-misaligned exception is triggered. Notably, this exception is associated with the branch or jump instruction itself and not the target instruction. It's essential to emphasize that a conditional branch, when not taken, does not result in the generation of an instruction-address-misaligned exception.
The three formats are shown below:
R-Type (Register) Format:
funt7 | rs2 | rs1 | funct3 | rd | opcode |
---|---|---|---|---|---|
funt7 | rs2 | rs1 | funct3 | rd | 0110011 |
I-Type (Immediate) Format:
imm[11:0] | rs1 | funct3 | rd | opcode |
---|---|---|---|---|
imm[11:0] | rs1 | funct3 | rd | 0110011 |
S**-Type (Register) Format:**
imm[11:5] | rs2 | rs1 | funct3 | rd | opcode |
---|---|---|---|---|---|
imm[11:5] | rs2 | rs1 | funct3 | rd | 0110011 |
MUL rd, rs1, rs2
: x[rd] = x[rs1] × x[rs2]
Multiplies the values in registers rs1 and rs2 and stores the result in register rd.
MULH rd, rs1, rs2
: x[rd] = (x[rs1] × x[rs2]) ≫XLEN (signed)
Computes the high bits of the signed product of the values in registers rs1 and rs2 and stores the result in register rd.
MULHSU rd, rs1, rs2
: x[rd] = (xrs1 × xrs2) ≫XLEN(s)
Computes the high bits of the signed product of rs1 and the absolute value of rs2, storing the result in rd.
MULHU rd, rs1, rs2
: x[rd] = (x[rs1] × x[rs2]) ≫XLEN (unsigned)
Computes the high bits of the unsigned product of the values in registers rs1 and rs2 and stores the result in register rd.
DIV rd, rs1, rs2
: x[rd] = x[rs1] ÷(s) x[rs2]
Divides the signed value in register rs1 by the signed value in register rs2 and stores the quotient in register rd.
DIVU rd, rs1, rs2
: x[rd] = x[rs1] ÷(u) x[rs2]
Divides the unsigned value in register rs1 by the unsigned value in register rs2, storing the quotient in register rd.
REM rd, rs1, rs2
: x[rd] = x[rs1] % (s) x[rs2]
Computes the remainder of the signed division of rs1 by rs2 and stores the result in rd.
REMU rd, rs1, rs2
: x[rd] = x[rs1] % (u) x[rs2]
Computes the remainder of the unsigned division of rs1 by rs2, storing the result in rd.
funct7 | rs2 | rs1 | funct3 | rd | opcode | |
---|---|---|---|---|---|---|
(R Type) | 31-25 | 24-20 | 19-15 | 14-12 | 11-7 | 6-0 |
MUL | 0000001 | - | - | 000 | - | 0110011 |
MULH | 0000001 | - | - | 001 | - | 0110011 |
MULHU | 0000001 | - | - | 011 | 0110011 | |
MULHSU | 0000001 | - | - | 010 | - | 0110011 |
DIV | 0000001 | - | - | 100 | - | 0110011 |
DIVU | 0000001 | - | - | 101 | - | 0110011 |
REM | 0000001 | - | - | 110 | - | 0110011 |
REMU | 0000001 | - | - | 111 | - | 0110011 |
Introduction
Control and Status Registers (CSRs) are essential components in computer architecture that play a crucial role in managing and monitoring the behavior of a processor or a system.
Purpose
The primary purpose of CSRs is to provide a mechanism for the processor to communicate and interact with the rest of the system. They act as a bridge between the processor's internal components and external devices or the operating system. CSRs are used for configuration, control, and monitoring of various aspects of the processor's operation.
In the RISC-V architecture, the machine-level interrupt handling is a critical aspect of system design. This involves the careful design of Control and Status Registers (CSRs) and the Core Local Interruptor (CLINT) to efficiently manage interrupts and exceptions at the machine level. This section explores the key considerations and design principles when creating a CSR and CLINT focused on machine-level operations.
CSR Register
The Machine-mode status register (mstatus) for RV32.
Machine Exception Program Counter(mepc) Register
Use to ****hold the program counter value at the time of an exception or trap in machine mode.
Machine Cause(mcause) Register
Use to hold a code or identifier that indicates the cause of an exception or interrupt.
“mtvec” Register
Use to specify the base address of the trap vector table for machine-level interrupts.
Relative CSR Address extracted from Spec. Vol.II Page 8-10
Number | Privilege | Name | Description |
---|---|---|---|
0x300 | MRW | mstatus | |
0x305 | MRW | mtvec | Machine trap-handler base address. |
0x341 | MRW | mepc | Machine exception program counter. |
0x342 | MRW | mcause | |
0xC00 | MRW | CycleL | |
0XC80 | MRW | CycleH | only in RV32 |
CSR Operation
CSRRW/CSRRWI:
Read the value from a Control and Status Register (CSR) and write the contents of a general-purpose register into the CSR.
CSRRS/CSRRSI:
Read the value from a CSR, perform a bitwise OR operation with the value in register rs1, and write the result back into the CSR.
CSRRC/CSRRCI:
Read the value from a CSR, perform a bitwise AND operation with the complement (~) of the value in register rs1, and write the result back into the CSR.
MERT (Machine Exception Return):
This instruction is used to return from an exception, updating the mstatus register:
Purpose
CLINT provides a centralized facility for handling interrupts that are local to each processor core in a multi-core system.
Interrupt Handling:
Timer Facilities:
Key Components:
msip
(Machine Software Interrupt Pending): Indicates whether a software interrupt is pending for the core.mtime
and mtimecmp
interrupts: Triggered when the machine time (mtime
) exceeds the value in mtimecmp
.The Core Local Interrupter (CLINT) is a part of the memory-mapped I/O (MMIO) space in RISC-V processors. It provides a mechanism for handling timer interrupts and software-generated interrupts at the core level. CLINT is typically used in systems with multiple RISC-V cores, and each core has its own instance of the CLINT.
Operation:
mtime
) surpasses the value set in mtimecmp
.lab 3 Link: Assignment3: single-cycle RISC-V CPU - HackMD
Github Link: DarrenHuang0411/NCKU_CA_2023 at Assignment-3 (github.com)
Refer to https://yatcpu.sysu.tech/tutorial/interrupt-and-exception/
Compared to Assignment 3, the Instruction Fetch needs to be enhanced to handle interrupt signals received in CSR. This involves the introduction of two key conditions: interrupt_assert
and interrupt_handler_address
.
For M-extension
For CSR Control
io.ex_csr_address
:
io.instruction
) to the ex_csr_address
signal.io.ex_csr_write_enable
:
(opcode === Instructions.csr)
checks if the opcode corresponds to the CSR instruction, indicating a CSR operation is being performed.csrrw
, csrrs
, csrrc
, csrrwi
, csrrsi
, csrrci
).io.ex_csr_write_enable
is set to true, indicating that the CSR write operation is enabled.Inputs:
funct3
: The instruction that specifies the CSR operation (e.g., csrrw
, csrrs
, etc.).io.reg1_data
: The data from register 1 (specified by rs1
in the instruction).io.exe_read_data_csr
: The data read from the CSR specified by the instruction.io.immediate
: An immediate value from the instruction (if applicable).MuxLookup
Function:
MuxLookup
function is used to perform a conditional selection based on the value of funct3
. It acts like a multiplexer (Mux
), selecting a value based on the given conditions.Conditions and Values:
csrrw
, csrrs
, etc.), there is a corresponding condition in the IndexedSeq
. The selected value is determined based on the type of CSR instruction.
InstructionsTypeCSR.csrrw
:io.reg1_data
) to the CSR.InstructionsTypeCSR.csrrs
:InstructionsTypeCSR.csrrc
:InstructionsTypeCSR.csrrwi
:InstructionsTypeCSR.csrrsi
:InstructionsTypeCSR.csrrci
:Result:
io.csr_write_data_exe
. This data will be used for writing to the specified CSR in the subsequent stages of the processor pipeline.csr_read_data
in InstructionDecode
:
csr_read_data
signal is utilized in the InstructionDecode
module as one of the potential sources for writing data to the registers (regs_write_data
).MuxLookup
construct selects the appropriate data source based on the value of io.regs_write_source
.io.regs_write_source
corresponds to RegWriteSource.CSR
, the value of io.csr_read_data
is chosen as the regs_write_data
.How to operation
interrupt_enable
:
Extracts the MIE (Machine Interrupt Enable) bit from the mstatus
CSR.
Trap Handling:
Checks if there is a pending interrupt (Interrupt_Flag
is not None) and if interrupts are enabled.
If true, updates relevant CSR values (mstatus
, mepc
, mcause
) based on the type of interrupt.
Sets direct_write_enable
to true, asserts interrupt_assert
, and sets interrupt_handler_address
to mtvec
from the CSR.
MRET Handling:
Checks if the current instruction is an MRET instruction.
If true, updates mstatus
, mepc
, and mcause
using values from the CSR.
Sets direct_write_enable
to true, asserts interrupt_assert
, and sets interrupt_handler_address
to mepc
from the CSR.**Default Behavior:**If no interrupt or MRET, preserves the current CSR values.
Sets direct_write_enable
to false, interrupt_assert
to false, and interrupt_handler_address
to 0.
direct_write_enable
signal indicates whether a direct write to the CSRs is required based on the executed instruction.I/O Port Definition:
Timer_interrupt_Flag
: An output indicating whether a timer interrupt is asserted.debug_limit
: An output providing the current value of the timer limit for debugging purposes.debug_enabled
: An output indicating whether the timer is currently enabled for debugging.Register Declarations:
count
, limit
, and enabled
) are declared to maintain the state of the timer.
count
: Maintains the current count of the timer.limit
: Represents the limit at which the timer resets.enabled
: Indicates whether the timer is currently enabled.Debug Outputs:
debug_limit
and debug_enabled
are set to the values of limit
and enabled
, respectively. These are provided for debugging purposes.Timer Logic:
when
and otherwise
blocks.enabled
is true), the count
is incremented. If the count reaches the limit
, the count is reset to 0, and the Timer_interrupt_Flag
is asserted.Timer_interrupt_Flag
is set to false.The CPUBundle
plays a crucial role in establishing a communication interface between the central processing unit (CPU) and peripheral devices, with a primary focus on memory interactions. This interface serves as the conduit for the exchange of data, allowing the CPU to interact seamlessly with various external components.
Communication Interface:
CPUBundle
serves as the bridge that facilitates the communication flow between the CPU and peripheral devices, especially memory modules. It defines the signals and connections required for data transfer, enabling efficient interaction between the CPU and external components.Data Exchange:
CPUBundle
, various signals are defined to support bidirectional data exchange. These signals may include inputs and outputs for addresses, data, control signals, and other relevant information. The well-defined structure of the bundle ensures a standardized and organized approach to communication.Peripheral Devices:
CPUBundle
accommodates the specific needs of these peripheral devices, allowing the CPU to read from and write to external memory and interact with other connected devices.Environment: Linux Ubuntu 22.04
Tool: GTKwave
The first to test =⇒ Single cycle CPU with CSR
we new folder "Final_Project" including the testing data “"
The
Pass
Wrong (Need to find)
FibonacciTest (10):
The expect result is 55