Skip to content

Commit

Permalink
Merge pull request #9 from weijiew/lab8-plic
Browse files Browse the repository at this point in the history
add plic and tests.
  • Loading branch information
jieway committed Apr 2, 2024
2 parents 0b21bc0 + a913a4d commit aaef5a1
Show file tree
Hide file tree
Showing 5 changed files with 171 additions and 0 deletions.
3 changes: 3 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ set(COMMON_SOURCES
src/csr.cpp
src/exception.cpp
src/exception.h
src/plic.cpp
src/plic.h
)

add_library(common_library ${COMMON_SOURCES})
Expand All @@ -46,6 +48,7 @@ add_executable(unit_test
tests/unitest/cpu_test.cpp
tests/unitest/csr_test.cpp
tests/unitest/exception.cpp
tests/unitest/plic_test.cpp
)

# 将库链接到 unit_test 可执行文件
Expand Down
22 changes: 22 additions & 0 deletions src/param.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,4 +85,26 @@ constexpr Mode Supervisor = 0b01;
// 定义 Machine 模式,二进制表示为 11
constexpr Mode Machine = 0b11;

// PLIC的基地址,所有的PLIC寄存器都从这个地址开始映射到内存中。
constexpr uint64_t PLIC_BASE = 0xc000000;

// PLIC的大小,表示PLIC寄存器在内存中的映射区域的大小。这个大小是0x4000000。
constexpr uint64_t PLIC_SIZE = 0x4000000;

// PLIC的结束地址,表示PLIC寄存器在内存中的映射区域的结束地址。
constexpr uint64_t PLIC_END = PLIC_BASE + PLIC_SIZE - 1;

// PLIC的挂起寄存器的地址,当有中断挂起时,对应的位会被设置为1。
constexpr uint64_t PLIC_PENDING = PLIC_BASE + 0x1000;

// PLIC的使能寄存器的地址,可以通过设置这个寄存器来使能或禁止中断。
constexpr uint64_t PLIC_SENABLE = PLIC_BASE + 0x2000;

// PLIC的优先级寄存器的地址,可以通过设置这个寄存器来改变中断的优先级。
constexpr uint64_t PLIC_SPRIORITY = PLIC_BASE + 0x201000;

// PLIC的确认寄存器的地址,当处理器处理完一个中断后,
// 会写这个寄存器来通知PLIC中断已经被处理。
constexpr uint64_t PLIC_SCLAIM = PLIC_BASE + 0x201004;

}
54 changes: 54 additions & 0 deletions src/plic.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
//
// Created by Jie Wei on 2024/4/2.
//

#include <cstdint>
#include "exception.h"
#include "plic.h"
#include "param.h"

namespace crvemu {

uint64_t Plic::load(uint64_t addr, uint64_t size) {
if (size != 32) {
throw Exception(ExceptionType::LoadAccessFault, addr);
}
switch (addr) {
case PLIC_PENDING:
return pending;
case PLIC_SENABLE:
return senable;
case PLIC_SPRIORITY:
return spriority;
case PLIC_SCLAIM:
return sclaim;
default:
return 0;
}
}


void Plic::store(uint64_t addr, uint64_t size, uint64_t value) {
if (size != 32) {
throw Exception(ExceptionType::StoreAMOAccessFault, addr);
}
switch (addr) {
case PLIC_PENDING:
pending = value;
break;
case PLIC_SENABLE:
senable = value;
break;
case PLIC_SPRIORITY:
spriority = value;
break;
case PLIC_SCLAIM:
sclaim = value;
break;
default:
break;
}
}

}

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

#pragma once
#include <cstdint>
#include "exception.h"

namespace crvemu {

// 这个类的设计是为了模拟PLIC的功能,使得在模拟器中可以像在真实硬件中一样处理中断。
// 这个类的方法提供了对PLIC寄存器的读写操作,这些操作在处理中断时是必需的。
class Plic {
public:
Plic() : pending(0), senable(0), spriority(0), sclaim(0) {}

// 读取和写入PLIC的寄存器
uint64_t load(uint64_t addr, uint64_t size);
void store(uint64_t addr, uint64_t size, uint64_t value);

private:
uint64_t pending; // 对应PLIC的挂起寄存器
uint64_t senable; // 对应PLIC的使能寄存器
uint64_t spriority; // 对应PLIC的优先级寄存器
uint64_t sclaim; // 对应PLIC的索引寄存器
};

}

63 changes: 63 additions & 0 deletions tests/unitest/plic_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
//
// Created by Jie Wei on 2024/4/2.
//

#include "gtest/gtest.h"
#include "../../src/plic.h"
#include "../../src/param.h"

namespace crvemu {

class PlicTest : public ::testing::Test {
protected:
Plic plic;
};

TEST_F(PlicTest, LoadStoreTest) {
uint64_t test_value = 123;

// Test store and load for each register
plic.store(PLIC_PENDING, 32, test_value);
EXPECT_EQ(plic.load(PLIC_PENDING, 32), test_value);

plic.store(PLIC_SENABLE, 32, test_value);
EXPECT_EQ(plic.load(PLIC_SENABLE, 32), test_value);

plic.store(PLIC_SPRIORITY, 32, test_value);
EXPECT_EQ(plic.load(PLIC_SPRIORITY, 32), test_value);

plic.store(PLIC_SCLAIM, 32, test_value);
EXPECT_EQ(plic.load(PLIC_SCLAIM, 32), test_value);
}

// Test exception throwing when size is not 32
TEST_F(PlicTest, ExceptionTest) {
EXPECT_THROW(plic.load(PLIC_PENDING, 64), Exception);
EXPECT_THROW(plic.store(PLIC_PENDING, 64, 123), Exception);
}

// 测试未知寄存器地址的行为
TEST_F(PlicTest, UnknownAddressTest) {
uint64_t unknown_address = 0xdeadbeef;
EXPECT_NO_THROW(plic.store(unknown_address, 32, 123));
EXPECT_EQ(plic.load(unknown_address, 32), 0);
}

//// 测试处理多个中断请求的行为
//TEST_F(PlicTest, MultipleInterruptsTest) {
// plic.store(PLIC_PENDING, 32, 1);
// plic.store(PLIC_PENDING, 32, 2);
// EXPECT_EQ(plic.load(PLIC_SCLAIM, 32), 1);
// EXPECT_EQ(plic.load(PLIC_SCLAIM, 32), 2);
//}

//// 测试处理优先级不同的中断请求的行为
//TEST_F(PlicTest, PriorityTest) {
// plic.store(PLIC_PENDING, 32, 1);
// plic.store(PLIC_SPRIORITY, 32, 1);
// plic.store(PLIC_PENDING, 32, 2);
// plic.store(PLIC_SPRIORITY, 32, 2);
// EXPECT_EQ(plic.load(PLIC_SCLAIM, 32), 2);
// EXPECT_EQ(plic.load(PLIC_SCLAIM, 32), 1);
//}
} // namespace crvemu

0 comments on commit aaef5a1

Please sign in to comment.