arch-riscv,dev: Update the PLIC implementation (#886)
Update the PLIC based on the [riscv-plic-spec](https://github.com/riscv/riscv-plic-spec) in the PR: - Support customized PLIC hardID and privilege mode configuration - Backward compatable with the n_contexts parameter, will generate the config like {0,M}, {0,S}, {1,M} ... Change-Id: Ibff736827edb7c97921e01fa27f503574a27a562
This commit is contained in:
@@ -221,10 +221,10 @@ class HiFive(HiFiveBase):
|
||||
self.plic.n_src = max(plic_srcs) + 1
|
||||
|
||||
def setNumCores(self, num_cpu):
|
||||
"""Sets the PLIC and CLINT to have the right number of threads and
|
||||
contexts. Assumes that the cores have a single hardware thread.
|
||||
"""Sets the CLINT to number of threads and the PLIC hartID/pmode for
|
||||
each contexts. Assumes that the cores have a single hardware thread.
|
||||
"""
|
||||
self.plic.n_contexts = num_cpu * 2
|
||||
self.plic.hart_config = ",".join(["MS" for _ in range(num_cpu)])
|
||||
self.clint.num_threads = num_cpu
|
||||
|
||||
def generateDeviceTree(self, state):
|
||||
|
||||
@@ -58,10 +58,8 @@ class PlicBase(BasicPioDevice):
|
||||
class Plic(PlicBase):
|
||||
"""
|
||||
This implementation of PLIC is based on
|
||||
the SiFive U54MC datasheet:
|
||||
https://sifive.cdn.prismic.io/sifive/fab000f6-
|
||||
0e07-48d0-9602-e437d5367806_sifive_U54MC_rtl_
|
||||
full_20G1.03.00_manual.pdf
|
||||
the riscv-plic-spec repository:
|
||||
https://github.com/riscv/riscv-plic-spec/releases/tag/1.0.0
|
||||
"""
|
||||
|
||||
type = "Plic"
|
||||
@@ -69,9 +67,20 @@ class Plic(PlicBase):
|
||||
cxx_class = "gem5::Plic"
|
||||
pio_size = 0x4000000
|
||||
n_src = Param.Int("Number of interrupt sources")
|
||||
# Ref: https://github.com/qemu/qemu/blob/760b4dc/hw/intc/sifive_plic.c#L285
|
||||
hart_config = Param.String(
|
||||
"",
|
||||
"String represent for PLIC hart/pmode config like QEMU plic"
|
||||
"Ex."
|
||||
"'M' 1 hart with M mode"
|
||||
"'MS,MS' 2 harts, 0-1 with M and S mode"
|
||||
"'M,MS,MS,MS,MS' 5 harts, 0 with M mode, 1-5 with M and S mode",
|
||||
)
|
||||
n_contexts = Param.Int(
|
||||
0,
|
||||
"Deprecated, use `hart_config` instead. "
|
||||
"Number of interrupt contexts. Usually the number "
|
||||
"of threads * 2. One for M mode, one for S mode"
|
||||
"of threads * 2. One for M mode, one for S mode",
|
||||
)
|
||||
|
||||
def generateDeviceTree(self, state):
|
||||
@@ -89,12 +98,26 @@ class Plic(PlicBase):
|
||||
|
||||
cpus = self.system.unproxy(self).cpu
|
||||
int_extended = list()
|
||||
for cpu in cpus:
|
||||
phandle = int_state.phandle(cpu)
|
||||
int_extended.append(phandle)
|
||||
int_extended.append(0xB)
|
||||
int_extended.append(phandle)
|
||||
int_extended.append(0x9)
|
||||
if self.n_contexts != 0:
|
||||
for cpu in cpus:
|
||||
phandle = int_state.phandle(cpu)
|
||||
int_extended.append(phandle)
|
||||
int_extended.append(0xB)
|
||||
int_extended.append(phandle)
|
||||
int_extended.append(0x9)
|
||||
elif self.hart_config != "":
|
||||
cpu_id = 0
|
||||
phandle = int_state.phandle(cpus[cpu_id])
|
||||
for c in self.hart_config:
|
||||
if c == ",":
|
||||
cpu_id += 1
|
||||
phandle = int_state.phandle(cpus[cpu_id])
|
||||
elif c == "S":
|
||||
int_extended.append(phandle)
|
||||
int_extended.append(0x9)
|
||||
elif c == "M":
|
||||
int_extended.append(phandle)
|
||||
int_extended.append(0xB)
|
||||
|
||||
node.append(FdtPropertyWords("interrupts-extended", int_extended))
|
||||
node.append(FdtProperty("interrupt-controller"))
|
||||
|
||||
@@ -57,10 +57,18 @@ Plic::Plic(const Params ¶ms) :
|
||||
PlicBase(params),
|
||||
system(params.system),
|
||||
nSrc(params.n_src),
|
||||
nContext(params.n_contexts),
|
||||
registers(params.name, pioAddr, this),
|
||||
update([this]{updateOutput();}, name() + ".update")
|
||||
{
|
||||
fatal_if(params.hart_config != "" && params.n_contexts != 0,
|
||||
"the hart_config and n_contexts can't be set simultaneously");
|
||||
|
||||
if (params.n_contexts != 0) {
|
||||
initContextFromNContexts(params.n_contexts);
|
||||
}
|
||||
if (params.hart_config != "") {
|
||||
initContextFromHartConfig(params.hart_config);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@@ -80,7 +88,7 @@ Plic::post(int src_id)
|
||||
|
||||
// Update states
|
||||
pendingPriority[src_id] = registers.priority[src_id].get();
|
||||
for (int i = 0; i < nContext; i++) {
|
||||
for (int i = 0; i < contextConfigs.size(); i++) {
|
||||
bool enabled = bits(registers.enable[i][src_index].get(), src_offset);
|
||||
effPriority[i][src_id] = enabled ? pendingPriority[src_id] : 0;
|
||||
}
|
||||
@@ -109,7 +117,7 @@ Plic::clear(int src_id)
|
||||
|
||||
// Update states
|
||||
pendingPriority[src_id] = 0;
|
||||
for (int i = 0; i < nContext; i++) {
|
||||
for (int i = 0; i < contextConfigs.size(); i++) {
|
||||
effPriority[i][src_id] = 0;
|
||||
}
|
||||
DPRINTF(Plic,
|
||||
@@ -174,20 +182,20 @@ Plic::init()
|
||||
|
||||
// Setup internal states
|
||||
pendingPriority.resize(nSrc, 0x0);
|
||||
for (int i = 0; i < nContext; i++) {
|
||||
for (int i = 0; i < contextConfigs.size(); i++) {
|
||||
std::vector<uint32_t> context_priority(nSrc, 0x0);
|
||||
effPriority.push_back(context_priority);
|
||||
}
|
||||
lastID.resize(nContext, 0x0);
|
||||
lastID.resize(contextConfigs.size(), 0x0);
|
||||
|
||||
// Setup outputs
|
||||
output = PlicOutput{
|
||||
std::vector<uint32_t>(nContext, 0x0),
|
||||
std::vector<uint32_t>(nContext, 0x0)};
|
||||
std::vector<uint32_t>(contextConfigs.size(), 0x0),
|
||||
std::vector<uint32_t>(contextConfigs.size(), 0x0)};
|
||||
|
||||
DPRINTF(Plic,
|
||||
"Device init - %d contexts, %d sources, %d pending registers\n",
|
||||
nContext, nSrc, nSrc32);
|
||||
contextConfigs.size(), nSrc, nSrc32);
|
||||
|
||||
BasicPioDevice::init();
|
||||
}
|
||||
@@ -204,15 +212,15 @@ Plic::PlicRegisters::init()
|
||||
- plic->nSrc32 * 4;
|
||||
reserved.emplace_back("reserved1", reserve1_size);
|
||||
const size_t reserve2_size = thresholdStart - enableStart
|
||||
- plic->nContext * enablePadding;
|
||||
- plic->contextConfigs.size() * enablePadding;
|
||||
reserved.emplace_back("reserved2", reserve2_size);
|
||||
const size_t reserve3_size = plic->pioSize - thresholdStart
|
||||
- plic->nContext * thresholdPadding;
|
||||
- plic->contextConfigs.size() * thresholdPadding;
|
||||
reserved.emplace_back("reserved3", reserve3_size);
|
||||
|
||||
// Sanity check
|
||||
assert(plic->pioSize >= thresholdStart
|
||||
+ plic->nContext * thresholdPadding);
|
||||
+ plic->contextConfigs.size() * thresholdPadding);
|
||||
assert((int) plic->pioSize <= maxBankSize);
|
||||
|
||||
// Calculate hole sizes
|
||||
@@ -228,7 +236,7 @@ Plic::PlicRegisters::init()
|
||||
pending.emplace_back(
|
||||
std::string("pending") + std::to_string(i), 0);
|
||||
}
|
||||
for (int i = 0; i < plic->nContext; i++) {
|
||||
for (int i = 0; i < plic->contextConfigs.size(); i++) {
|
||||
|
||||
enable.push_back(std::vector<Register32>());
|
||||
for (int j = 0; j < plic->nSrc32; j++) {
|
||||
@@ -264,7 +272,7 @@ Plic::PlicRegisters::init()
|
||||
addRegister(reserved[1]);
|
||||
|
||||
// Enable
|
||||
for (int i = 0; i < plic->nContext; i++) {
|
||||
for (int i = 0; i < plic->contextConfigs.size(); i++) {
|
||||
for (int j = 0; j < plic->nSrc32; j++) {
|
||||
auto write_cb = std::bind(&Plic::writeEnable, plic, _1, _2, j, i);
|
||||
enable[i][j].writer(write_cb);
|
||||
@@ -275,7 +283,7 @@ Plic::PlicRegisters::init()
|
||||
addRegister(reserved[2]);
|
||||
|
||||
// Threshold and claim
|
||||
for (int i = 0; i < plic->nContext; i++) {
|
||||
for (int i = 0; i < plic->contextConfigs.size(); i++) {
|
||||
auto threshold_cb = std::bind(&Plic::writeThreshold, plic, _1, _2, i);
|
||||
threshold[i].writer(threshold_cb);
|
||||
auto read_cb = std::bind(&Plic::readClaim, plic, _1, i);
|
||||
@@ -301,7 +309,7 @@ Plic::writePriority(Register32& reg, const uint32_t& data, const int src_id)
|
||||
// Update states
|
||||
bool pending = bits(registers.pending[src_index].get(), src_offset);
|
||||
pendingPriority[src_id] = pending ? reg.get() : 0;
|
||||
for (int i = 0; i < nContext; i++) {
|
||||
for (int i = 0; i < contextConfigs.size(); i++) {
|
||||
bool enabled = bits(
|
||||
registers.enable[i][src_index].get(), src_offset);
|
||||
effPriority[i][src_id] = enabled ? pendingPriority[src_id] : 0;
|
||||
@@ -394,11 +402,11 @@ Plic::propagateOutput()
|
||||
{
|
||||
// Calculate new output
|
||||
PlicOutput new_output{
|
||||
std::vector<uint32_t>(nContext, 0x0),
|
||||
std::vector<uint32_t>(nContext, 0x0)};
|
||||
std::vector<uint32_t>(contextConfigs.size(), 0x0),
|
||||
std::vector<uint32_t>(contextConfigs.size(), 0x0)};
|
||||
uint32_t max_id;
|
||||
uint32_t max_priority;
|
||||
for (int i = 0; i < nContext; i++) {
|
||||
for (int i = 0; i < contextConfigs.size(); i++) {
|
||||
max_id = max_element(effPriority[i].begin(),
|
||||
effPriority[i].end()) - effPriority[i].begin();
|
||||
max_priority = effPriority[i][max_id];
|
||||
@@ -421,6 +429,39 @@ Plic::propagateOutput()
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Plic::initContextFromNContexts(int n_contexts)
|
||||
{
|
||||
contextConfigs.reserve(n_contexts);
|
||||
for (uint32_t i = 0; i < (uint32_t)n_contexts; i += 2) {
|
||||
contextConfigs.emplace_back((i >> 1), ExceptionCode::INT_EXT_MACHINE);
|
||||
contextConfigs.emplace_back((i >> 1), ExceptionCode::INT_EXT_SUPER);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Plic::initContextFromHartConfig(const std::string& hart_config)
|
||||
{
|
||||
contextConfigs.reserve(hart_config.size());
|
||||
uint32_t hart_id = 0;
|
||||
for (char c: hart_config) {
|
||||
switch (c) {
|
||||
case ',':
|
||||
hart_id++;
|
||||
break;
|
||||
case 'M':
|
||||
contextConfigs.emplace_back(hart_id, ExceptionCode::INT_EXT_MACHINE);
|
||||
break;
|
||||
case 'S':
|
||||
contextConfigs.emplace_back(hart_id, ExceptionCode::INT_EXT_SUPER);
|
||||
break;
|
||||
default:
|
||||
fatal("hart_config should not contains the value: %c", c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Plic::updateOutput()
|
||||
{
|
||||
@@ -443,10 +484,8 @@ void
|
||||
Plic::updateInt()
|
||||
{
|
||||
// Update xEIP lines
|
||||
for (int i = 0; i < nContext; i++) {
|
||||
int thread_id = i >> 1;
|
||||
int int_id = (i & 1) ?
|
||||
ExceptionCode::INT_EXT_SUPER : ExceptionCode::INT_EXT_MACHINE;
|
||||
for (int i = 0; i < contextConfigs.size(); i++) {
|
||||
auto [thread_id, int_id] = contextConfigs[i];
|
||||
|
||||
auto tc = system->threads[thread_id];
|
||||
uint32_t max_id = output.maxID[i];
|
||||
|
||||
@@ -57,11 +57,9 @@ namespace gem5
|
||||
using namespace RiscvISA;
|
||||
/**
|
||||
* NOTE:
|
||||
* This implementation of CLINT is based on
|
||||
* the SiFive U54MC datasheet:
|
||||
* https://sifive.cdn.prismic.io/sifive/fab000f6-
|
||||
* 0e07-48d0-9602-e437d5367806_sifive_U54MC_rtl_
|
||||
* full_20G1.03.00_manual.pdf
|
||||
* This implementation of PLIC is based on
|
||||
* he riscv-plic-spec repository:
|
||||
* https://github.com/riscv/riscv-plic-spec/releases/tag/1.0.0
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -124,13 +122,9 @@ class Plic : public PlicBase
|
||||
*/
|
||||
int nSrc32;
|
||||
/**
|
||||
* Number of interrupt contexts
|
||||
* = nThread * 2
|
||||
* e.g. context 0 => thread 0 M mode
|
||||
* context 1 => thread 0 S mode
|
||||
* This is based on SiFive U54MC datasheet
|
||||
* PLIC hart/pmode address configs, stored in the format {hartID, pmode}
|
||||
*/
|
||||
int nContext;
|
||||
std::vector<std::pair<uint32_t, ExceptionCode>> contextConfigs;
|
||||
|
||||
public:
|
||||
typedef PlicParams Params;
|
||||
@@ -261,6 +255,12 @@ class Plic : public PlicBase
|
||||
std::vector<uint32_t> lastID;
|
||||
PlicOutput output;
|
||||
|
||||
/**
|
||||
* The function for handling context config from params
|
||||
*/
|
||||
void initContextFromNContexts(int n_contexts);
|
||||
void initContextFromHartConfig(const std::string& hart_config);
|
||||
|
||||
/**
|
||||
* Trigger:
|
||||
* - Plic::post
|
||||
|
||||
@@ -185,7 +185,7 @@ class LupvBoard(AbstractSystemBoard, KernelDiskWorkload):
|
||||
# point for our bbl to use upon startup, and will
|
||||
# remain unused during the simulation
|
||||
self.pic.n_src = 0
|
||||
self.pic.n_contexts = 0
|
||||
self.pic.hart_config = ""
|
||||
self.lupio_pic.n_src = max(pic_srcs) + 1
|
||||
self.lupio_pic.num_threads = self.processor.get_num_cores()
|
||||
|
||||
@@ -403,10 +403,19 @@ class LupvBoard(AbstractSystemBoard, KernelDiskWorkload):
|
||||
plic_node.append(FdtPropertyWords("riscv,ndev", 0))
|
||||
|
||||
int_extended = list()
|
||||
for i, core in enumerate(self.get_processor().get_cores()):
|
||||
phandle = state.phandle(f"cpu@{i}.int_state")
|
||||
int_extended.append(phandle)
|
||||
int_extended.append(self._excep_code["INT_EXT_MACHINE"])
|
||||
cpu_id = 0
|
||||
phandle = int_state.phandle(f"cpu@{cpu_id}.int_state")
|
||||
for c in plic.hart_config:
|
||||
if c == ",":
|
||||
cpu_id += 1
|
||||
assert cpu_id < self.get_processor().get_num_cores()
|
||||
phandle = int_state.phandle(f"cpu@{cpu_id}.int_state")
|
||||
elif c == "S":
|
||||
int_extended.append(phandle)
|
||||
int_extended.append(self._excep_code["INT_SOFT_SUPER"])
|
||||
elif c == "M":
|
||||
int_extended.append(phandle)
|
||||
int_extended.append(self._excep_code["INT_EXT_MACHINE"])
|
||||
|
||||
plic_node.append(FdtPropertyWords("interrupts-extended", int_extended))
|
||||
plic_node.append(FdtProperty("interrupt-controller"))
|
||||
|
||||
@@ -102,7 +102,9 @@ class RiscvBoard(AbstractSystemBoard, KernelDiskWorkload):
|
||||
# Contains a CLINT, PLIC, UART, and some functions for the dtb, etc.
|
||||
self.platform = HiFive()
|
||||
# Note: This only works with single threaded cores.
|
||||
self.platform.plic.n_contexts = self.processor.get_num_cores() * 2
|
||||
self.platform.plic.hart_config = ",".join(
|
||||
["MS" for _ in range(self.processor.get_num_cores())]
|
||||
)
|
||||
self.platform.attachPlic()
|
||||
self.platform.clint.num_threads = self.processor.get_num_cores()
|
||||
|
||||
@@ -353,12 +355,19 @@ class RiscvBoard(AbstractSystemBoard, KernelDiskWorkload):
|
||||
plic_node.append(FdtPropertyWords("riscv,ndev", [plic.n_src - 1]))
|
||||
|
||||
int_extended = list()
|
||||
for i, core in enumerate(self.get_processor().get_cores()):
|
||||
phandle = state.phandle(f"cpu@{i}.int_state")
|
||||
int_extended.append(phandle)
|
||||
int_extended.append(0xB)
|
||||
int_extended.append(phandle)
|
||||
int_extended.append(0x9)
|
||||
cpu_id = 0
|
||||
phandle = int_state.phandle(f"cpu@{cpu_id}.int_state")
|
||||
for c in plic.hart_config:
|
||||
if c == ",":
|
||||
cpu_id += 1
|
||||
assert cpu_id < self.get_processor().get_num_cores()
|
||||
phandle = int_state.phandle(f"cpu@{cpu_id}.int_state")
|
||||
elif c == "S":
|
||||
int_extended.append(phandle)
|
||||
int_extended.append(0x9)
|
||||
elif c == "M":
|
||||
int_extended.append(phandle)
|
||||
int_extended.append(0xB)
|
||||
|
||||
plic_node.append(FdtPropertyWords("interrupts-extended", int_extended))
|
||||
plic_node.append(FdtProperty("interrupt-controller"))
|
||||
|
||||
@@ -149,7 +149,9 @@ class RISCVMatchedBoard(
|
||||
# Contains a CLINT, PLIC, UART, and some functions for the dtb, etc.
|
||||
self.platform = HiFive()
|
||||
# Note: This only works with single threaded cores.
|
||||
self.platform.plic.n_contexts = self.processor.get_num_cores() * 2
|
||||
self.platform.plic.hart_config = ",".join(
|
||||
["MS" for _ in range(self.processor.get_num_cores())]
|
||||
)
|
||||
self.platform.attachPlic()
|
||||
self.platform.clint.num_threads = self.processor.get_num_cores()
|
||||
|
||||
@@ -433,12 +435,19 @@ class RISCVMatchedBoard(
|
||||
plic_node.append(FdtPropertyWords("riscv,ndev", [plic.n_src - 1]))
|
||||
|
||||
int_extended = list()
|
||||
for i, core in enumerate(self.get_processor().get_cores()):
|
||||
phandle = state.phandle(f"cpu@{i}.int_state")
|
||||
int_extended.append(phandle)
|
||||
int_extended.append(0xB)
|
||||
int_extended.append(phandle)
|
||||
int_extended.append(0x9)
|
||||
cpu_id = 0
|
||||
phandle = int_state.phandle(f"cpu@{cpu_id}.int_state")
|
||||
for c in plic.hart_config:
|
||||
if c == ",":
|
||||
cpu_id += 1
|
||||
assert cpu_id < self.get_processor().get_num_cores()
|
||||
phandle = int_state.phandle(f"cpu@{cpu_id}.int_state")
|
||||
elif c == "S":
|
||||
int_extended.append(phandle)
|
||||
int_extended.append(0x9)
|
||||
elif c == "M":
|
||||
int_extended.append(phandle)
|
||||
int_extended.append(0xB)
|
||||
|
||||
plic_node.append(FdtPropertyWords("interrupts-extended", int_extended))
|
||||
plic_node.append(FdtProperty("interrupt-controller"))
|
||||
|
||||
Reference in New Issue
Block a user