DarrenHuang0411
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Versions and GitHub Sync Note Insights Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       owned this note    owned this note      
    Published Linked with GitHub
    Subscribed
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    Subscribe
    # Final Project: Extend Lab3 to comply with RV32IM and CSR Status: In progress > Contributed by <[Yu Jui Huang](https://github.com/DarrenHuang0411/RiscV-Single-Cycle-CPU-with-CSR.git)> > > Real-time Update in Notion <[Link](https://www.notion.so/Final-Project-Extend-Lab3-to-comply-with-RV32IM-and-CSR-38ce64073a214521bb8067b06b645ec9?pvs=21)> > # ****1. RISC-V Information**** ## 1.1 **RV32I Instruction Format** 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 | ## 1.2 **M standard extension** ### 1.2.1 **Integer Multiplication Instructions:** - **`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] = (x[rs1](u) × x[rs2](s)) ≫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. ### 1.2.2 **Integer Division Instructions:** - **`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. ### 1.2.3 The Instruction Decoder of M Extension | | 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 | ## 1.3 **Control and Status Register(CSR) & Core Local Interrupts(CLINT) Concept** ### 1.3.1 CSR **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** - **Machine Status (mstatus) Register** Use to record various control and status related to “Machine state”. It is a machine-level CSR that holds various status and control information about the machine mode. ![mstatus](https://hackmd.io/_uploads/r1oexFbYa.png) **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: - Update MIE (Machine Interrupt Enable) with the value of MPIE. - Update the MPIE field's value to 1. ### 1.3.2 Core Local Interrupt (CLINT) **Purpose** CLINT provides a centralized facility for handling interrupts that are local to each processor core in a multi-core system. **Interrupt Handling:** - Manages local interrupts, which are specific to a particular core. - Coordinates interrupt requests from various sources within the core. **Timer Facilities:** - Includes programmable timers for each core. - Often used for implementing time-related functionalities, such as context switching and scheduling. **Key Components:** 1. **Timer Registers:** - The CLINT contains a timer that generates periodic interrupts. - This timer, often referred to as the mtime (machine time) or mtimecmp (machine time compare), can be configured to generate interrupts at specified intervals. 2. **Interrupt Registers:** - **`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`**. 3. **Software Interrupts:** - The CLINT also supports software-generated interrupts. Software running on the RISC-V processor can trigger these interrupts by writing to specific registers in the CLINT. 4. **Memory-Mapped Registers:** - The CLINT exposes a set of memory-mapped registers that allow software and peripherals to interact with it. The most common registers include: - *mtime:* Holds the current machine time. - *mtimecmp:* Used to set the compare value for the timer interrupt. 5. **Interrupt Handling:** - When a timer interrupt occurs or a software-generated interrupt is triggered, the CLINT signals the core by raising an interrupt. The processor then follows the standard interrupt handling procedure, which involves saving the current context and transferring control to the interrupt service routine (ISR). 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:** 1. **Interrupt Generation:** - External devices, software, or timers can generate interrupts specific to a core. - Timer interrupts are generated when the machine time (**`mtime`**) surpasses the value set in **`mtimecmp`**. 2. **Interrupt Handling:** - When an interrupt occurs, the core suspends its current execution and transfers control to the corresponding interrupt service routine (ISR). - The ISR is a specific piece of code designed to handle the interrupt and perform necessary actions. 3. **Timer Functionality:** - The programmable timer facilities assist in managing time-related events. - Context switches, task scheduling, and other time-sensitive operations can be synchronized using CLINT's timer capabilities. 4. **Global Interrupt Controller:** - Interacting with a global interrupt controller that manages interrupts across all cores. # 2. Recap Lab3: Single cycle CPU > lab 3 Link: [Assignment3: single-cycle RISC-V CPU - HackMD](https://hackmd.io/zCc-wifJRyOTjTD5DHOkhQ) > > Github Link: [DarrenHuang0411/NCKU_CA_2023 at Assignment-3 (github.com)](https://github.com/DarrenHuang0411/NCKU_CA_2023/tree/Assignment-3) # 3. Single cycle CPU comply with RV32IM and CSR ## 3.1 Single cycle CPU Diagram ![Single_cycle_with_CSR](https://hackmd.io/_uploads/Hk2RyFbKT.png) **Refer to [https://yatcpu.sysu.tech/tutorial/interrupt-and-exception/](https://yatcpu.sysu.tech/tutorial/interrupt-and-exception/)** ## 3.2 Revise the version including CSR ### 3.2.1 **Instruction Fetch** 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`. ![IF](https://hackmd.io/_uploads/Hyo1xtbK6.png) - **interrupt_assert**: This parameter signifies the assertion of an interrupt signal. When set, it indicates that an interrupt has occurred and needs attention. Proper handling of this signal is crucial for interrupt-driven processes. - **interrupt_handler_address**: This parameter denotes the address where the interrupt handler is located. Upon the assertion of an interrupt, the program counter is redirected to this address, initiating the execution of the corresponding interrupt handler routine. It plays a vital role in managing the flow of execution during interrupt scenarios. ```scala class InstructionFetch extends Module { val io = IO(new Bundle { val jump_flag_id = Input(Bool()) val jump_address_id = Input(UInt(Parameters.AddrWidth)) val instruction_read_data = Input(UInt(Parameters.DataWidth)) val instruction_valid = Input(Bool()) val interrupt_assert = Input(Bool()) val interrupt_handler_address = Input(UInt(Parameters.AddrWidth)) val instruction_address = Output(UInt(Parameters.AddrWidth)) val instruction = Output(UInt(Parameters.InstructionWidth)) }) val pc = RegInit(ProgramCounter.EntryAddress) when(io.instruction_valid) { io.instruction := io.instruction_read_data // Final project(InstructionFetch) begin when(io.interrupt_assert){ pc := io.interrupt_handler_address } .elsewhen(io.jump_flag_id){ pc := io.jump_address_id } .otherwise{ pc := pc + 4.U } // lab3(InstructionFetch) end }.otherwise { pc := pc io.instruction := 0x00000013.U } io.instruction_address := pc ``` ### **3.2.2 Instruction Decoder** ![ID](https://hackmd.io/_uploads/SyRQeFbKp.png) - For M-extension ```scala ``` - **For CSR Control** **`io.ex_csr_address`:** - CSR-related instructions assigns the bits [31:20] of the input instruction (**`io.instruction`**) to the **`ex_csr_address`** signal. **`io.ex_csr_write_enable`:** - Write operation to a CSR should is enabled based on the opcode and funct3 field of the instruction. - The condition **`(opcode === Instructions.csr)`** checks if the opcode corresponds to the CSR instruction, indicating a CSR operation is being performed. - The second part of the condition checks the funct3 field against various CSR-related instruction types (**`csrrw`**, **`csrrs`**, **`csrrc`**, **`csrrwi`**, **`csrrsi`**, **`csrrci`**). If the funct3 matches any of these values, the condition evaluates to true. - If both conditions are true, **`io.ex_csr_write_enable`** is set to true, indicating that the CSR write operation is enabled. ```scala val ex_csr_write_enable = Output(Bool()) val ex_csr_address = Output(UInt(Parameters.CSRRegisterAddrWidth)) ``` ```scala io.ex_csr_address := io.instruction(31, 20) io.ex_csr_write_enable := (opcode === Instructions.csr) && (funct3 === InstructionsTypeCSR.csrrw || funct3 === InstructionsTypeCSR.csrrs || funct3 === InstructionsTypeCSR.csrrc || funct3 === InstructionsTypeCSR.csrwri || funct3 === InstructionsTypeCSR.csrrsi || funct3 === InstructionsTypeCSR.csrrci ) ``` ### 3.2.3 **Execute** **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:** - The **`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:** - For each CSR instruction type (**`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`**: Write the data from register 1 (**`io.reg1_data`**) to the CSR. - **`InstructionsTypeCSR.csrrs`**: Write the result of a bitwise OR between the data read from the CSR and the data from register 1. - **`InstructionsTypeCSR.csrrc`**: Write the result of a bitwise AND between the complement of the data from register 1 and the data read from the CSR. - **`InstructionsTypeCSR.csrrwi`**: Write the immediate value to the CSR. - **`InstructionsTypeCSR.csrrsi`**: Write the result of a bitwise OR between the data read from the CSR and the immediate value. - **`InstructionsTypeCSR.csrrci`**: Write the result of a bitwise AND between the complement of the immediate value and the data read from the CSR. **Result:** - The selected value based on the CSR instruction type is assigned to **`io.csr_write_data_exe`**. This data will be used for writing to the specified CSR in the subsequent stages of the processor pipeline. ```scala io.csr_write_data_exe := MuxLookup( funct3, 0.U, IndexedSeq( InstructionsTypeCSR.csrrw -> io.reg1_data, InstructionsTypeCSR.csrrs -> (io.exe_read_data_csr | io.reg1_data), InstructionsTypeCSR.csrrc -> (io.exe_read_data_csr & (~io.reg1_data)), InstructionsTypeCSR.csrrwi -> io.immediate, InstructionsTypeCSR.csrrsi -> (io.exe_read_data_csr | io.immediate), InstructionsTypeCSR.csrrci -> (io.exe_read_data_csr & (~io.immediate)) ) ) ``` ### 3.2.4 **Write Back (WB)** - **Usage of `csr_read_data` in `InstructionDecode`:** - The `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`). - The `MuxLookup` construct selects the appropriate data source based on the value of `io.regs_write_source`. If `io.regs_write_source` corresponds to `RegWriteSource.CSR`, the value of `io.csr_read_data` is chosen as the `regs_write_data`. ```scala package riscv.core import chisel3._ import chisel3.util._ import riscv.Parameters class WriteBack extends Module { val io = IO(new Bundle() { ... //final project val csr_read_data = Input(UInt(Parameters.DataWidth)) //final end }) io.regs_write_data := MuxLookup( io.regs_write_source, io.alu_result, IndexedSeq( RegWriteSource.Memory -> io.memory_read_data, //final project (object in InstructionDecode) RegWriteSource.CSR -> io.csr_read_data, //final end RegWriteSource.NextInstructionAddress -> (io.instruction_address + 4.U) ) ) } ``` ### 3.2.5 CSR (New) ```scala package riscv.core import chisel3._ import chisel3.util._ import riscv.Parameters // CSRRegister get object CSRRegister{ val MSTATUS = 0x300.U(Parameters.CSRRegisterAddrWidth) val MIE = 0x304.U(Parameters.CSRRegisterAddrWidth) val MTVEC = 0x305.U(Parameters.CSRRegisterAddrWidth) val MSCRATCH = 0x340.U(Parameters.CSRRegisterAddrWidth) val MEPC = 0x341.U(Parameters.CSRRegisterAddrWidth) val MCAUSE = 0x342.U(Parameters.CSRRegisterAddrWidth) val CycleL = 0xC00.U(Parameters.CSRRegisterAddrWidth) val CycleH = 0XC80.U(Parameters.CSRRegisterAddrWidth) } class CSR extends Module { val io = IO(new Bundle() { val read_address_id = Input(UInt(Parameters.CSRRegisterAddrWidth)) val write_address_id = Input(UInt(Parameters.CSRRegisterAddrWidth)) val write_enable_id = Input(Bool()) val write_data_exe = Input(UInt(Parameters.DataWidth)) val exe_csrrd_csr = Output(UInt(Parameters.DataWidth)) val clint_csr_bundle = Flipped(new CSRDirectAccessBundle) val debug_reg_read_address = Input(UInt(Parameters.CSRRegisterAddrWidth)) val debug_reg_read_data = Output(UInt(Parameters.DataWidth)) }) //initialization val mstatus = RegInit(UInt(Parameters.DataWidth), 0.U) val mie = RegInit(UInt(Parameters.DataWidth), 0.U) val mtvec = RegInit(UInt(Parameters.DataWidth), 0.U) val mscratch = RegInit(UInt(Parameters.DataWidth), 0.U) val mepc = RegInit(UInt(Parameters.DataWidth), 0.U) val mcause = RegInit(UInt(Parameters.DataWidth), 0.U) val cycles = RegInit(UInt(64.W), 0.U) // connect to preset register val regLUT = IndexedSeq( CSRRegister.MSTATUS -> mstatus, CSRRegister.MIE -> mie, CSRRegister.MTVEC -> mtvec, CSRRegister.MSCRATCH-> mscratch, CSRRegister.MEPC -> mepc, CSRRegister.MCAUSE -> mcause, CSRRegister.CycleL -> cycles(31, 0), CSRRegister.CycleH -> cycles(63, 32) ) cycles := cycles+ 1.U // If the pipeline and the CLINT are going to read and write the CSR at the same time, let the pipeline write first. // This is implemented in a single cycle by passing (write_data_exe) to clint and writing the data from the CLINT to the CSR. io.exe_csrrd_csr := MuxLookup(io.read_address_id, 0.U)(regLUT) io.debug_reg_read_data := MuxLookup(io.debug_reg_read_address, 0.U)(regLUT) io.clint_csr_bundle.mstatus := mstatus io.clint_csr_bundle.mtvec := mtvec io.clint_csr_bundle.mcause := mcause io.clint_csr_bundle.mepc := mepc when(io.clint_csr_bundle.direct_write_enable) { mstatus := io.clint_csr_bundle.mstatus_write_data mepc := io.clint_csr_bundle.mepc_write_data mcause := io.clint_csr_bundle.mcause_write_data } .elsewhen(io.write_enable_id) { when(io.write_address_id === CSRRegister.MSTATUS) { mstatus := io.write_data_exe } .elsewhen(io.write_address_id === CSRRegister.MEPC) { mepc := io.write_data_exe } .elsewhen(io.write_address_id === CSRRegister.MCAUSE) { mcause := io.write_data_exe } } when(io.write_enable_id) { when(io.write_address_id === CSRRegister.MIE) { mie := io.write_data_exe } .elsewhen(io.write_address_id === CSRRegister.MTVEC){ mtvec := io.write_data_exe } .elsewhen(io.write_address_id === CSRRegister.MSCRATCH) { mscratch := io.write_data_exe } } } ``` ### 3.2.6 CLINT (New) **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. ```scala package riscv.core import chisel3._ import chisel3.util._ import riscv.Parameters object InterruptStatus{ val None = 0x0.U(8.W) val Timer0 = 0x1.U(8.W) val Ret = 0xF.U(8.W) } object InterruptEntry{ val Timer0 = 0x4.U(8.W) } object InterruptState{ val Idle = 0x0.U val SyncAssert = 0x1.U val AsyncAssert = 0x2.U val MRET = 0x3.U } object CSRState { val Idle = 0x0.U val Traping = 0x1.U val Mret = 0x2.U } class CSRDirectAccessBundle extends Bundle{ val mstatus = Input(UInt(Parameters.DataWidth)) val mepc = Input(UInt(Parameters.DataWidth)) val mcause = Input(UInt(Parameters.DataWidth)) val mtvec = Input(UInt(Parameters.DataWidth)) val mstatus_write_data= Output(UInt(Parameters.DataWidth)) val mepc_write_data= Output(UInt(Parameters.DataWidth)) val mcause_write_data= Output(UInt(Parameters.DataWidth)) val direct_write_enable = Output(Bool()) } class CLINT extends Module{ val io = IO(new Bundle { val Interrupt_Flag = Input(UInt(Parameters.InterruptFlagWidth)) val Instruction = Input(UInt(Parameters.InstructionWidth)) val IF_Instruction_Address = Input(UInt(Parameters.AddrWidth)) val jump_flag = Input(Bool()) val jump_address = Input(UInt(Parameters.AddrWidth)) val interrupt_handler_address = Output(UInt(Parameters.AddrWidth)) val interrupt_assert = Output(Bool()) val csr_bundle = new CSRDirectAccessBundle }) // mstatus(3) ==> MIE val interrupt_enable = io.csr_bundle.mstatus(3) // Trap: choose Sync/Async val instruction_address = Mux(io.jump_flag, io.jump_address, io.IF_Instruction_Address + 4.U) when(io.Interrupt_Flag =/= InterruptStatus.None && interrupt_enable){ io.csr_bundle.mstatus_write_data := io.csr_bundle.mstatus(31, 4) ## 0.U(1.W) ## io.csr_bundle.mstatus(2, 0) io.csr_bundle.mepc_write_data := io.IF_Instruction_Address + 4.U io.csr_bundle.mcause_write_data := Mux(io.Interrupt_Flag(0), 0x80000007L.U, 0x8000000BL.U) io.csr_bundle.direct_write_enable := true.B io.interrupt_assert := true.B io.interrupt_handler_address := io.csr_bundle.mtvec } .elsewhen(io.Instruction === InstructionsRet.mret){ io.csr_bundle.mstatus_write_data := io.csr_bundle.mstatus(31, 4) ## io.csr_bundle.mstatus(7) ## io.csr_bundle.mstatus(2, 0) io.csr_bundle.mepc_write_data := io.csr_bundle.mepc io.csr_bundle.mcause_write_data := io.csr_bundle.mcause io.csr_bundle.direct_write_enable := true.B io.interrupt_assert := true.B io.interrupt_handler_address := io.csr_bundle.mepc } .otherwise{ io.csr_bundle.mstatus_write_data := io.csr_bundle.mstatus io.csr_bundle.mepc_write_data := io.csr_bundle.mepc io.csr_bundle.mcause_write_data := io.csr_bundle.mcause io.csr_bundle.direct_write_enable := false.B io.interrupt_assert := false.B io.interrupt_handler_address := 0.U } } ``` - The CLINT module monitors interrupt flags, handles traps and MRET instructions, and updates relevant CSRs accordingly. - It provides information about the interrupt handler address and whether an interrupt is currently asserted. - The **`direct_write_enable`** signal indicates whether a direct write to the CSRs is required based on the executed instruction. - This design allows for interrupt handling and CSR updates in a RISC-V processor. ### 3.2.7 Timer (New) **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:** - Three registers (`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:** - The timer logic is enclosed within the `when` and `otherwise` blocks. - When the timer is enabled (`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. - If the timer is not enabled, `Timer_interrupt_Flag` is set to false. ```scala package peripheral import chisel3._ import chisel3.util._ import riscv.Parameters class Timer extends Module { val io = IO(new Bundle { val bundle = new RAMBundle val Timer_interrupt_Flag = Output(Bool()) val debug_limit = Output(UInt(Parameters.DataWidth)) val debug_enabled = Output(Bool()) }) val count = RegInit(0.U(32.W)) val limit = RegInit(100000000.U(32.W)) val enabled = RegInit(true.B) io.debug_limit := limit io.debug_enabled := enabled //final //finish the read-write for count,limit,enabled. And produce appropriate Timer_interrupt_Flag when(enabled){ count := count + 1.U when(count === limit){ count := 0.U io.Timer_interrupt_Flag := true.B } .otherwise{ io.Timer_interrupt_Flag := false.B } } .otherwise{ io.Timer_interrupt_Flag := false.B } } ``` ### 3.2.8 CPU ```bash //final project(csr i/o) val csr_regs = Module(new CSR) val clint = Module(new CLINT) //final end .... //final project(clint interrupt assert) IF.io.interrupt_assert := clint.io.interrupt_assert IF.io.interrupt_handler_address := clint.io.interrupt_handler_address //final end .... //final project csr() csr_regs.io.read_address_id := id.io.ex_csr_address csr_regs.io.write_address_id := id.io.ex_csr_address csr_regs.io.write_enable_id := id.io.ex_csr_write_enable csr_regs.io.write_data_exe := ex.io.csr_write_data_exe //csr_regs.io.exe_csrrd_csr := csr_regs.io.clint_csr_bundle <> clint.io.csr_bundle //final end //final project clint clint.io.Interrupt_Flag := io.Interrupt_Flag clint.io.IF_Instruction_Address := IF.io.instruction_address clint.io.Instruction := IF.io.instruction clint.io.jump_address := ex.io.if_jump_address clint.io.jump_flag := ex.io.if_jump_flag //final end ``` ### 3.2.9 CPUBundle 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:** - The `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:** - Within the `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:** - The term "peripheral devices" encompasses a broad range of external components, such as memory units, storage devices, and other interfaces. The `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. ```scala package riscv import chisel3._ import peripheral.RAMBundle // CPUBundle serves as the communication interface for data exchange between // the CPU and peripheral devices, such as memory. class CPUBundle extends Bundle { val instruction_address = Output(UInt(Parameters.AddrWidth)) val instruction = Input(UInt(Parameters.DataWidth)) val instruction_valid = Input(Bool()) val Interrupt_Flag = Input(UInt(Parameters.InterruptFlagWidth)) val memory_bundle = Flipped(new RAMBundle) val deviceSelect = Output(UInt(Parameters.SlaveDeviceCountBits.W)) val regs_debug_read_address = Input(UInt(Parameters.PhysicalRegisterAddrWidth)) val regs_debug_read_data = Output(UInt(Parameters.DataWidth)) val csr_regs_debug_read_address = Input(UInt(Parameters.CSRRegisterAddrWidth)) val csr_regs_debug_read_data = Output(UInt(Parameters.DataWidth)) } ``` # 4. Validation > 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 “" ## 4.1 CPU Validation ### 4.1.1 Testing Step The ```bash $ cd Final_Project/ $ sbt test ``` ### 4.1.2 Testing Result - **********Pass********** ```bash FibonacciTest: [info] Single Cycle CPU with CSR and CLINT [info] - should calculate recursively fibonacci(10) [info] QuicksortTest: [info] Single Cycle CPU with CSR and CLINT [info] - should quicksort 10 numbers [info] InstructionDecoderTest: [info] InstructionDecoder of Single Cycle CPU [info] - should produce correct control signal ... [info] InstructionFetchTest: [info] InstructionFetch of Single Cycle CPU [info] - should fetch instruction [info] ByteAccessTest: [info] Single Cycle CPU with CSR and CLINT [info] - should store and load single byte [info] ExecuteTest: [info] Execution of Single Cycle CPU [info] - should execute correctly [info] RegisterFileTest: [info] Register File of Single Cycle CPU [info] - should read the written content [info] - should x0 always be zero [info] - should read the writing content [info] Run completed in 46 seconds, 932 milliseconds. [info] Total number of tests run: 10 [info] Suites: completed 8, aborted 0 [info] Tests: succeeded 9, failed 1, canceled 0, ignored 0, pending 0 [info] *** 1 TEST FAILED *** [error] Failed tests: [error] riscv.singlecycle.SimpleTrapTest [error] (Test / test) sbt.TestsFailedException: Tests unsuccessful [error] Total time: 60 s, completed Jan 13, 2024, 6:17:58 PM ``` - **********Wrong (Need to find)********** ```bash [info] SimpleTrapTest: [info] Single Cycle CPU with CSR and CLINT [info] - should jump to trap handler and then return *** FAILED *** [info] java.lang.NullPointerException: [info] at ... () [info] at peripheral.InstructionROM.readAsmBinary(InstructionROM.scala:42) [info] at peripheral.InstructionROM.<init>(InstructionROM.scala:25) [info] at riscv.singlecycle.TestTopModule.$anonfun$instruction_rom$2(CPUTest.scala:30) [info] at chisel3.Module$.do_apply(Module.scala:53) [info] at riscv.singlecycle.TestTopModule.$anonfun$instruction_rom$1(CPUTest.scala:30) [info] at chisel3.internal.plugin.package$.autoNameRecursively(package.scala:33) [info] at riscv.singlecycle.TestTopModule.<init>(CPUTest.scala:30) [info] at riscv.singlecycle.SimpleTrapTest.$anonfun$new$42(CPUTest.scala:125) [info] at ... () [info] ... ``` ## 4.2 GTKWave - **FibonacciTest (10):** The expect result is 55 ![Untitled 1](https://hackmd.io/_uploads/rkTfeY-K6.png) # 5. Reference 1. [RISC-V 指令集架構介紹 - M Standard Extension](https://tclin914.github.io/f37f836/) 2. [中斷和異常 - YatCPU 實驗文件 (sysu.tech)](https://yatcpu.sysu.tech/tutorial/interrupt-and-exception/) 3. [Specifications – RISC-V International (riscv.org)](https://riscv.org/technical/specifications/) 4. [riscv-privileged-20211203.pdf - Google Drive](https://drive.google.com/file/d/1EMip5dZlnypTk7pt4WWUKmtjUKTOkBqh/view) 5. [從零開始的RISC-V SoC架構設計與Linux核心運行 - 硬體篇 - HackMD](https://hackmd.io/@w4K9apQGS8-NFtsnFXutfg/B1Re5uGa5) 6. [RISC V::中斷與異常處理 -- 異常篇 - iT 邦幫忙::一起幫忙解決難題,拯救 IT 人的一天 (ithome.com.tw)](https://ithelp.ithome.com.tw/articles/10268967) 7. [RV32M, RV64M Instructions — riscv-isa-pages documentation (msyksphinz-self.github.io)](https://msyksphinz-self.github.io/riscv-isadoc/html/rvm.html)

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully