Line 5... |
Line 5... |
* @brief Interrupt controller functional model.
|
* @brief Interrupt controller functional model.
|
*/
|
*/
|
|
|
#include "api_core.h"
|
#include "api_core.h"
|
#include "irqctrl.h"
|
#include "irqctrl.h"
|
|
#include <riscv-isa.h>
|
|
#include "coreservices/icpuriscv.h"
|
|
|
namespace debugger {
|
namespace debugger {
|
|
|
|
IrqPort::IrqPort(IService *parent, const char *portname, int idx) {
|
|
parent_ = parent;
|
|
parent->registerPortInterface(portname, static_cast<IWire *>(this));
|
|
idx_ = idx;
|
|
level_ = false;
|
|
};
|
|
|
|
void IrqPort::raiseLine() {
|
|
level_ = true;
|
|
static_cast<IrqController *>(parent_)->requestInterrupt(idx_);
|
|
}
|
|
|
|
void IrqPort::setLevel(bool level) {
|
|
if (!level_ && level) {
|
|
raiseLine();
|
|
} else if (level_ && !level) {
|
|
lowerLine();
|
|
}
|
|
}
|
|
|
IrqController::IrqController(const char *name) : IService(name) {
|
IrqController::IrqController(const char *name) : IService(name) {
|
registerInterface(static_cast<IMemoryOperation *>(this));
|
registerInterface(static_cast<IMemoryOperation *>(this));
|
registerInterface(static_cast<IWire *>(this));
|
registerInterface(static_cast<IClockListener *>(this));
|
registerAttribute("BaseAddress", &baseAddress_);
|
|
registerAttribute("Length", &length_);
|
|
registerAttribute("CPU", &cpu_);
|
registerAttribute("CPU", &cpu_);
|
registerAttribute("CSR_MIPI", &mipi_);
|
registerAttribute("CSR_MIPI", &mipi_);
|
registerAttribute("IrqTotal", &irqTotal_);
|
registerAttribute("IrqTotal", &irqTotal_);
|
|
|
baseAddress_.make_uint64(0);
|
char portname[256];
|
|
for (int i = 1; i < IRQ_MAX; i++) {
|
|
RISCV_sprintf(portname, sizeof(portname), "irq%d", i);
|
|
irqlines_[i] = new IrqPort(this, portname, i);
|
|
}
|
|
|
mipi_.make_uint64(0x783);
|
mipi_.make_uint64(0x783);
|
length_.make_uint64(0);
|
|
cpu_.make_string("");
|
cpu_.make_string("");
|
irqTotal_.make_uint64(4);
|
irqTotal_.make_uint64(4);
|
|
|
memset(®s_, 0, sizeof(regs_));
|
memset(®s_, 0, sizeof(regs_));
|
regs_.irq_mask = ~0;
|
regs_.irq_mask = ~0;
|
regs_.irq_lock = 1;
|
regs_.irq_lock = 1;
|
irq_wait_unlock = 0;
|
|
}
|
}
|
|
|
IrqController::~IrqController() {
|
IrqController::~IrqController() {
|
}
|
}
|
|
|
void IrqController::postinitService() {
|
void IrqController::postinitService() {
|
icpu_ = static_cast<ICpuRiscV *>(
|
iclk_ = static_cast<IClock *>(
|
RISCV_get_service_iface(cpu_.to_string(), IFACE_CPU_RISCV));
|
RISCV_get_service_iface(cpu_.to_string(), IFACE_CLOCK));
|
|
if (!iclk_) {
|
|
RISCV_error("Can't find IClock interface %s", cpu_.to_string());
|
|
return;
|
|
}
|
|
|
|
icpu_ = static_cast<ICpuGeneric *>(
|
|
RISCV_get_service_iface(cpu_.to_string(), IFACE_CPU_GENERIC));
|
if (!icpu_) {
|
if (!icpu_) {
|
RISCV_error("Can't find ICpuRiscV interface %s", cpu_.to_string());
|
RISCV_error("Can't find ICpuRiscV interface %s", cpu_.to_string());
|
|
return;
|
}
|
}
|
|
uint64_t t = iclk_->getStepCounter();
|
|
iclk_->registerStepCallback(static_cast<IClockListener *>(this), t + 1);
|
}
|
}
|
|
|
void IrqController::b_transport(Axi4TransactionType *trans) {
|
ETransStatus IrqController::b_transport(Axi4TransactionType *trans) {
|
uint64_t mask = (length_.to_uint64() - 1);
|
uint64_t mask = (length_.to_uint64() - 1);
|
uint64_t off = ((trans->addr - getBaseAddress()) & mask) / 4;
|
uint64_t off = ((trans->addr - getBaseAddress()) & mask) / 4;
|
uint32_t t1;
|
uint32_t t1;
|
trans->response = MemResp_Valid;
|
trans->response = MemResp_Valid;
|
if (trans->action == MemAction_Write) {
|
if (trans->action == MemAction_Write) {
|
Line 64... |
Line 97... |
break;
|
break;
|
case 2:
|
case 2:
|
t1 = regs_.irq_pending;
|
t1 = regs_.irq_pending;
|
regs_.irq_pending &= ~trans->wpayload.b32[i];
|
regs_.irq_pending &= ~trans->wpayload.b32[i];
|
if (t1 && !regs_.irq_pending) {
|
if (t1 && !regs_.irq_pending) {
|
icpu_->lowerSignal(CPU_SIGNAL_EXT_IRQ);
|
icpu_->lowerSignal(INTERRUPT_MExternal);
|
}
|
}
|
RISCV_info("Set irq_clear = %08x", trans->wpayload.b32[i]);
|
RISCV_info("Set irq_clear = %08x", trans->wpayload.b32[i]);
|
break;
|
break;
|
case 3:
|
case 3:
|
regs_.irq_pending |= trans->wpayload.b32[i];
|
regs_.irq_pending |= trans->wpayload.b32[i];
|
Line 113... |
Line 146... |
trans->wpayload.b32[i]);
|
trans->wpayload.b32[i]);
|
break;
|
break;
|
case 10:
|
case 10:
|
regs_.irq_lock = trans->wpayload.b32[i];
|
regs_.irq_lock = trans->wpayload.b32[i];
|
RISCV_info("Set irq_ena = %08x", trans->wpayload.b32[i]);
|
RISCV_info("Set irq_ena = %08x", trans->wpayload.b32[i]);
|
if (regs_.irq_lock == 0 && (regs_.irq_pending ||irq_wait_unlock)) {
|
if (regs_.irq_lock == 0 && regs_.irq_pending) {
|
regs_.irq_pending |= irq_wait_unlock;
|
icpu_->lowerSignal(INTERRUPT_MExternal);
|
icpu_->raiseSignal(CPU_SIGNAL_EXT_IRQ);
|
|
irq_wait_unlock = 0;
|
|
} else if (regs_.irq_lock == 1 && regs_.irq_pending) {
|
|
icpu_->lowerSignal(CPU_SIGNAL_EXT_IRQ);
|
|
}
|
}
|
break;
|
break;
|
case 11:
|
case 11:
|
regs_.irq_cause_idx = trans->wpayload.b32[i];
|
regs_.irq_cause_idx = trans->wpayload.b32[i];
|
RISCV_info("Set irq_cause_idx = %08x", trans->wpayload.b32[i]);
|
RISCV_info("Set irq_cause_idx = %08x", trans->wpayload.b32[i]);
|
Line 197... |
Line 226... |
default:
|
default:
|
trans->rpayload.b32[i] = ~0;
|
trans->rpayload.b32[i] = ~0;
|
}
|
}
|
}
|
}
|
}
|
}
|
|
return TRANS_OK;
|
}
|
}
|
|
|
void IrqController::raiseLine(int idx) {
|
void IrqController::stepCallback(uint64_t t) {
|
if (regs_.irq_lock) {
|
iclk_->registerStepCallback(static_cast<IClockListener *>(this), t + 1);
|
irq_wait_unlock |= (~regs_.irq_mask & (1 << idx));
|
if (regs_.irq_lock == 1) {
|
return;
|
return;
|
}
|
}
|
if ((regs_.irq_mask & (0x1 << idx)) == 0) {
|
if (~regs_.irq_mask & regs_.irq_pending) {
|
regs_.irq_pending |= (0x1 << idx);
|
icpu_->raiseSignal(INTERRUPT_MExternal); // PLIC interrupt (external)
|
icpu_->raiseSignal(CPU_SIGNAL_EXT_IRQ); // PLIC interrupt (external)
|
RISCV_debug("Raise interrupt", NULL);
|
RISCV_info("Raise interrupt", NULL);
|
|
}
|
}
|
}
|
}
|
|
|
|
void IrqController::requestInterrupt(int idx) {
|
|
regs_.irq_pending |= (0x1 << idx);
|
|
RISCV_info("request Interrupt %d", idx);
|
|
}
|
|
|
} // namespace debugger
|
} // namespace debugger
|
|
|
|
|
No newline at end of file
|
No newline at end of file
|