Skip to content

Commit

Permalink
Merge pull request #6 from weijiew/lab5-csr
Browse files Browse the repository at this point in the history
add csr.
  • Loading branch information
jieway committed Feb 16, 2024
2 parents 5e09ced + 398176f commit 2f8705d
Show file tree
Hide file tree
Showing 15 changed files with 749 additions and 54 deletions.
8 changes: 7 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ set(COMMON_SOURCES
src/instructions.h
src/instructions.cpp
src/log.h
src/csr.h
src/csr.cpp
)

add_library(common_library ${COMMON_SOURCES})
Expand All @@ -34,9 +36,13 @@ enable_testing()
add_subdirectory("third_party/googletest")

add_executable(unit_test
tests/instructions_test.cpp
tests/unitest/instructions_test.cpp
tests/test_util.h
tests/test_util.cpp
tests/unitest/dram_test.cpp
tests/unitest/bus_test.cpp
tests/unitest/cpu_test.cpp
tests/unitest/csr_test.cpp
)

# 将库链接到 unit_test 可执行文件
Expand Down
4 changes: 2 additions & 2 deletions src/bus.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ std::optional<uint64_t> Bus::load(uint64_t addr, uint64_t size) {
LOG(INFO, "Bus loading from DRAM address ", std::hex, addr, " with size ", size, " bytes.");
return dram.load(addr, size);
}
LOG(ERROR, "Invalid address for load operation: ", std::hex, addr, ". Valid address range is [", DRAM_BASE, ", ", DRAM_END, "]");
LOG(WARNING, "Invalid address for load operation: ", std::hex, addr, ". Valid address range is [", DRAM_BASE, ", ", DRAM_END, "]");
return std::nullopt;
}

Expand All @@ -22,7 +22,7 @@ bool Bus::store(uint64_t addr, uint64_t size, uint64_t value) {
LOG(INFO, "Bus storing value ", std::hex, value, " at DRAM address ", addr, " with size ", size, " bytes.");
return dram.store(addr, size, value);
} else {
LOG(ERROR, "Invalid address for store operation: ", std::hex, addr, ". Valid address range is [", DRAM_BASE, ", ", DRAM_END, "]");
LOG(WARNING, "Invalid address for store operation: ", std::hex, addr, ". Valid address range is [", DRAM_BASE, ", ", DRAM_END, "]");
return false;
}
}
Expand Down
116 changes: 116 additions & 0 deletions src/csr.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
//
// Created by Jie Wei on 2024/2/13.
//

#include "csr.h"

namespace crvemu {

/**
* @brief Constructor for the Csr class.
*
* This constructor initializes all CSR (Control Status Registers) to 0.
*/
Csr::Csr() {
csrs.fill(0); // 初始化所有CSR为0
}


/**
* @brief Prints the current state of the control status registers.
*
* This function prints the current state of the control status registers in a formatted manner.
* It prints the values of MSTATUS, MTVEC, MEPC, MCAUSE, SSTATUS, STVEC, SEPC, and SCAUSE registers.
*/
void Csr::dump_csrs() const {
std::cout << std::setw(80) << std::setfill('-') << "control status registers" << std::setfill(' ') << "\n";
std::cout << "mstatus = " << std::hex << std::setw(18) << load(MSTATUS)
<< " mtvec = " << std::setw(18) << load(MTVEC)
<< " mepc = " << std::setw(18) << load(MEPC)
<< " mcause = " << std::setw(18) << load(MCAUSE) << "\n";
std::cout << "sstatus = " << std::setw(18) << load(SSTATUS)
<< " stvec = " << std::setw(18) << load(STVEC)
<< " sepc = " << std::setw(18) << load(SEPC)
<< " scause = " << std::setw(18) << load(SCAUSE) << "\n";
}

/**
* @brief Loads the value of a specific CSR.
*
* This function loads the value of a specific CSR from the array of CSRs.
* It returns the value of the CSR at the specified address.
*
* @param addr The address of the CSR to load.
* @return The value of the CSR at the specified address.
*/
uint64_t Csr::load(size_t addr) const {
switch (addr) {
case SIE:
return csrs[MIE] & csrs[MIDELEG];
case SIP:
return csrs[MIP] & csrs[MIDELEG];
case SSTATUS:
return csrs[MSTATUS] & MASK_SSTATUS;
default:
return csrs[addr];
}
}

/**
* @brief Stores a value into a specific CSR.
*
* This function stores a value into a specific CSR at the given address.
* Depending on the address, the function performs different operations:
* - If the address is SIE, it stores the value into the MIE register, taking into account the MIDELEG register.
* - If the address is SIP, it stores the value into the MIP register, taking into account the MIDELEG register.
* - If the address is SSTATUS, it stores the value into the MSTATUS register, taking into account the MASK_SSTATUS.
* - For any other address, it directly stores the value into the CSR at the given address.
*
* @param addr The address of the CSR to store the value into.
* @param value The value to store into the CSR.
*/
void Csr::store(size_t addr, uint64_t value) {
switch (addr) {
case SIE:
csrs[MIE] = (csrs[MIE] & ~csrs[MIDELEG]) | (value & csrs[MIDELEG]);
break;
case SIP:
csrs[MIP] = (csrs[MIE] & ~csrs[MIDELEG]) | (value & csrs[MIDELEG]);
break;
case SSTATUS:
csrs[MSTATUS] = (csrs[MSTATUS] & ~MASK_SSTATUS) | (value & MASK_SSTATUS);
break;
default:
csrs[addr] = value;
}
}

/**
* @brief Checks if a specific bit in the MEDELEG register is set.
*
* This function checks if the bit at the position specified by 'val' in the MEDELEG register is set.
* The MEDELEG register is used to delegate some exceptions from M-mode to S-mode.
* If the bit is set, it means that the corresponding exception is delegated.
*
* @param val The position of the bit to check in the MEDELEG register.
* @return true if the bit at position 'val' is set, false otherwise.
*/
bool Csr::is_medelegated(uint64_t val) const {
return (csrs[MEDELEG] >> val & 1) == 1;
}

/**
* @brief Checks if a specific bit in the MIDELEG register is set.
*
* This function checks if the bit at the position specified by 'val' in the MIDELEG register is set.
* The MIDELEG register is used to delegate some interrupts from M-mode to S-mode.
* If the bit is set, it means that the corresponding interrupt is delegated.
*
* @param val The position of the bit to check in the MIDELEG register.
* @return true if the bit at position 'val' is set, false otherwise.
*/
bool Csr::is_midelegated(uint64_t cause) const {
return (csrs[MIDELEG] >> cause & 1) == 1;
}

}
28 changes: 28 additions & 0 deletions src/csr.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//
// Created by Jie Wei on 2024/2/13.
//

#ifndef CSR_H
#define CSR_H
#include <iostream>
#include <iomanip>
#include <array>
#include "param.h"

namespace crvemu {

class Csr {
public:
Csr(); // 构造函数
void dump_csrs() const; // 打印所有的CSR
uint64_t load(size_t addr) const; // 加载指定地址的CSR
void store(size_t addr, uint64_t value); // 存储值到指定地址的CSR
bool is_medelegated(uint64_t cause) const; // 检查是否有机器异常委托
bool is_midelegated(uint64_t cause) const; // 检查是否有机器中断委托

private:
std::array<uint64_t, NUM_CSRS> csrs; // 存储CSR的数组
};

}
#endif //CSR_H
60 changes: 50 additions & 10 deletions src/cup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ std::optional<uint64_t> Cpu::load(uint64_t addr, uint64_t size) {
return val;
}

LOG(ERROR, "Load failed. Invalid address: ", std::hex, addr);
LOG(WARNING, "Load failed. Invalid address: ", std::hex, addr);
return std::nullopt;
}

Expand All @@ -31,7 +31,7 @@ bool Cpu::store(uint64_t addr, uint64_t size, uint64_t value) {
if (result) {
LOG(INFO, "Store successful.");
} else {
LOG(ERROR, "Store failed.");
LOG(WARNING, "Store failed.");
}

return result;
Expand All @@ -43,7 +43,7 @@ std::optional<uint32_t> Cpu::fetch() {
LOG(INFO, "Instruction fetched: ", std::hex, inst.value(), std::dec);
return inst.value();
}
LOG(ERROR, "Fetch failed. Invalid PC: ", std::hex, pc);
LOG(WARNING, "Fetch failed. Invalid PC: ", std::hex, pc);
return std::nullopt;
}

Expand All @@ -53,7 +53,7 @@ std::optional<uint64_t> Cpu::execute(uint32_t inst) {
LOG(INFO, "Execution successful. Result: ", std::hex, exe.value());
return exe;
}
LOG(ERROR, "Execution failed.");
LOG(WARNING, "Execution failed.");
return std::nullopt;
}

Expand All @@ -75,15 +75,55 @@ void Cpu::dump_pc() const {
LOG(INFO, "PC = 0x", std::hex, pc, std::dec);
}


uint64_t Cpu::getRegValueByName(const std::string& regName) {
auto it = std::find(RVABI.begin(), RVABI.end(), regName);
std::optional<uint64_t> Cpu::getRegValueByName(const std::string& name) {
// 尝试在寄存器中查找
auto it = std::find(RVABI.begin(), RVABI.end(), name);
if (it != RVABI.end()) {
int index = std::distance(RVABI.begin(), it);
return regs[index];
} else {
throw std::invalid_argument("Invalid register name: " + regName);
}
}

// 尝试在CSR寄存器中查找
if (name == "mhartid") {
return csr.load(MHARTID);
} else if (name == "mstatus") {
return csr.load(MSTATUS);
} else if (name == "mtvec") {
return csr.load(MTVEC);
} else if (name == "mepc") {
return csr.load(MEPC);
} else if (name == "mcause") {
return csr.load(MCAUSE);
} else if (name == "mtval") {
return csr.load(MTVAL);
} else if (name == "medeleg") {
return csr.load(MEDELEG);
} else if (name == "mscratch") {
return csr.load(MSCRATCH);
} else if (name == "MIP") {
return csr.load(MIP);
} else if (name == "mcounteren") {
return csr.load(MCOUNTEREN);
} else if (name == "sstatus") {
return csr.load(SSTATUS);
} else if (name == "stvec") {
return csr.load(STVEC);
} else if (name == "sepc") {
return csr.load(SEPC);
} else if (name == "scause") {
return csr.load(SCAUSE);
} else if (name == "stval") {
return csr.load(STVAL);
} else if (name == "sscratch") {
return csr.load(SSCRATCH);
} else if (name == "SIP") {
return csr.load(SIP);
} else if (name == "SATP") {
return csr.load(SATP);
}

// 如果在寄存器和CSR寄存器中都找不到,返回std::nullopt
LOG(WARNING, "Invalid name: ", name);
return std::nullopt;
}
}
40 changes: 27 additions & 13 deletions src/cup.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,17 @@
#ifndef CPU_H
#define CPU_H

#include <vector>
#include <array>
#include <cstdint>
#include <string>
#include <optional>
#include "param.h"
#include <string>
#include <vector>

#include "bus.h"
#include "csr.h"

namespace crvemu {

class Cpu {
public:

Expand All @@ -26,14 +28,16 @@ class Cpu {

Bus bus;

Cpu(const std::vector<uint8_t>& code) : pc(DRAM_BASE), bus(code), RVABI{
"zero", "ra", "sp", "gp", "tp", "t0", "t1", "t2",
"s0", "s1", "a0", "a1", "a2", "a3", "a4", "a5",
"a6", "a7", "s2", "s3", "s4", "s5", "s6", "s7",
"s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6"
} {
regs.fill(0); // 初始化寄存器为0
regs[2] = DRAM_END; // 设置堆栈指针寄存器的初始值
// 控制和状态寄存器。RISC-V ISA为最多4096个CSR预留了一个12位的编码空间(csr[11:0])。
Csr csr;

Cpu(const std::vector<uint8_t>& code)
: pc(DRAM_BASE),
bus(code),
csr() // 初始化 Csr
{
regs.fill(0); // 初始化寄存器为0
regs[2] = DRAM_END; // 设置堆栈指针寄存器的初始值
}

std::optional<uint64_t> load(uint64_t addr, uint64_t size);
Expand All @@ -47,14 +51,24 @@ class Cpu {
}

std::optional<uint64_t> execute(uint32_t inst);

void dump_registers();

void dump_pc() const;

uint64_t getRegValueByName(const std::string& regName);
std::optional<uint64_t> getRegValueByName(const std::string& name);

private:
const std::array<std::string, 32> RVABI; // RISC-V 寄存器名称
// 在类外初始化静态成员
const std::array<std::string, 32> RVABI = {
"zero", "ra", "sp", "gp", "tp", "t0", "t1", "t2",
"s0", "s1", "a0", "a1", "a2", "a3", "a4", "a5",
"a6", "a7", "s2", "s3", "s4", "s5", "s6", "s7",
"s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6"
};

};

}

#endif // CPU_H
6 changes: 3 additions & 3 deletions src/dram.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ Dram::Dram(const std::vector<uint8_t>& code) {

std::optional<uint64_t> Dram::load(uint64_t addr, uint64_t size) {
if (size != 8 && size != 16 && size != 32 && size != 64) {
LOG(ERROR, "Invalid size for load operation: ", size, " bytes.");
LOG(WARNING, "Invalid size for load operation: ", size, " bytes.");
return std::nullopt;
}
uint64_t nbytes = size / 8;
std::size_t index = (addr - DRAM_BASE);
if (index + nbytes > dram.size()) {
LOG(ERROR, "Invalid address range for load operation at DRAM address ", std::hex, addr);
LOG(WARNING, "Invalid address range for load operation at DRAM address ", std::hex, addr);
return std::nullopt;
}

Expand All @@ -35,7 +35,7 @@ std::optional<uint64_t> Dram::load(uint64_t addr, uint64_t size) {

bool Dram::store(uint64_t addr, uint64_t size, uint64_t value) {
if (size != 8 && size != 16 && size != 32 && size != 64) {
LOG(ERROR, "Invalid size for store operation: ", size, " bytes.");
LOG(WARNING, "Invalid size for store operation: ", size, " bytes.");
return false;
}

Expand Down
Loading

0 comments on commit 2f8705d

Please sign in to comment.