Skip to content

Commit

Permalink
Machine: CSR: basic exceptions support functional for external interr…
Browse files Browse the repository at this point in the history
…upts

Signed-off-by: Pavel Pisa <pisa@cmp.felk.cvut.cz>
  • Loading branch information
ppisa committed Nov 25, 2023
1 parent f44a205 commit 589f210
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 35 deletions.
28 changes: 21 additions & 7 deletions src/machine/core.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ bool Core::handle_exception(
control_state->update_exception_cause(excause);
if (control_state->read_internal(CSR::Id::MTVEC) != 0
&& !get_step_over_exception(excause)) {
control_state->set_status_exl(true);
control_state->exception_initiate(CSR::PrivilegeLevel::MACHINE, CSR::PrivilegeLevel::MACHINE);
regs->write_pc(control_state->exception_pc_address());
}
}
Expand Down Expand Up @@ -297,6 +297,7 @@ DecodeState Core::decode(const FetchInterstage &dt) {
.csr = bool(flags & IMF_CSR),
.csr_to_alu = bool(flags & IMF_CSR_TO_ALU),
.csr_write = csr_write,
.xret = bool(flags & IMF_XRET),
.insert_stall_before = bool(flags & IMF_CSR) } };
}

Expand Down Expand Up @@ -365,6 +366,7 @@ ExecuteState Core::execute(const DecodeInterstage &dt) {
.alu_zero = alu_val == 0,
.csr = dt.csr,
.csr_write = dt.csr_write,
.xret = dt.xret,
} };
}

Expand All @@ -374,6 +376,7 @@ MemoryState Core::memory(const ExecuteInterstage &dt) {
bool memread = dt.memread;
bool memwrite = dt.memwrite;
bool regwrite = dt.regwrite;
Address computed_next_inst_addr;

enum ExceptionCause excause = dt.excause;
if (excause == EXCAUSE_NONE) {
Expand All @@ -395,20 +398,30 @@ MemoryState Core::memory(const ExecuteInterstage &dt) {
regwrite = false;
}

// Conditional branch (BXX = BEQ | BNE...) is executed and should be taken.
const bool branch_bxx_taken = dt.branch_bxx && (!dt.branch_val ^ !dt.alu_zero);
// Unconditional jump should be taken (JALX = JAL | JALR).
const bool branch_jalx = dt.branch_jalr || dt.branch_jal;

computed_next_inst_addr = compute_next_inst_addr(dt, branch_bxx_taken);

bool csr_written = false;
if (control_state != nullptr && dt.is_valid && dt.excause == EXCAUSE_NONE) {
control_state->increment_internal(CSR::Id::MINSTRET, 1);
if (dt.csr_write) {
control_state->write(dt.csr_address, dt.alu_val);
csr_written = true;
}
if (dt.xret) {
control_state->exception_return(CSR::PrivilegeLevel::MACHINE);
if (this->xlen == Xlen::_32)
computed_next_inst_addr = Address(control_state->read_internal(CSR::Id::MEPC).as_u32());
else
computed_next_inst_addr = Address(control_state->read_internal(CSR::Id::MEPC).as_u64());
csr_written = true;
}
}

// Conditional branch (BXX = BEQ | BNE...) is executed and should be taken.
const bool branch_bxx_taken = dt.branch_bxx && (!dt.branch_val ^ !dt.alu_zero);
// Unconditional jump should be taken (JALX = JAL | JALR).
const bool branch_jalx = dt.branch_jalr || dt.branch_jal;

return { MemoryInternalState {
.mem_read_val = towrite_val,
.mem_write_val = dt.val_rt,
Expand All @@ -422,13 +435,14 @@ MemoryState Core::memory(const ExecuteInterstage &dt) {
.branch_outcome = branch_bxx_taken || branch_jalx,
.branch_jalx = branch_jalx,
.branch_jalr = dt.branch_jalr,
.xret = dt.xret,
},
MemoryInterstage {
.inst = dt.inst,
.inst_addr = dt.inst_addr,
.next_inst_addr = dt.next_inst_addr,
.predicted_next_inst_addr = dt.predicted_next_inst_addr,
.computed_next_inst_addr = compute_next_inst_addr(dt, branch_bxx_taken),
.computed_next_inst_addr = computed_next_inst_addr,
.mem_addr = mem_addr,
.towrite_val = [=]() -> RegisterValue {
if (dt.csr) return dt.csr_read_val;
Expand Down
76 changes: 49 additions & 27 deletions src/machine/csr/controlstate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,6 @@ LOG_CATEGORY("machine.csr.control_state");

namespace machine { namespace CSR {

// TODO this is mips
enum StatusReg {
Status_IE = 0x00000001,
Status_EXL = 0x00000002,
Status_ERL = 0x00000004,
Status_IntMask = 0x0000ff00,
};

ControlState::ControlState() {
reset();
}
Expand Down Expand Up @@ -100,20 +92,34 @@ namespace machine { namespace CSR {

void ControlState::update_exception_cause(enum ExceptionCause excause) {
RegisterValue &value = register_data[Id::MCAUSE];
value = value.as_u32() & ~0x80000000 & ~0x0000007f;
if (excause != EXCAUSE_INT) {
value = value.as_u32() | static_cast<unsigned>(excause) << 2;
value = static_cast<unsigned>(excause);
} else {
RegisterValue mie = register_data[Id::MIE];
RegisterValue mip = register_data[Id::MIP];
int irq_to_signal = 0;

uint64_t irqs = mie.as_u64() & mip.as_u64() & 0xffffffff;

// use ffs or __builtin_ffsl where available
for (int i = 0; i < 32; i++) {
if (irqs & (1UL << i)) {
irq_to_signal = i;
break;
}
}

value = (uint64_t)(irq_to_signal |
((uint64_t)1 << ((xlen == Xlen::_32)? 31: 63)));
}
// TODO: this is known ahead of time
emit write_signal(Id::MCAUSE, value);
}

// TODO this is mips
void ControlState::set_interrupt_signal(uint irq_num, bool active) {
if (irq_num >= 8) { return; }
if (irq_num >= 32) { return; }
uint64_t mask = 1 << irq_num;
size_t reg_id = Id::MIP;
RegisterValue value = register_data[reg_id];
RegisterValue &value = register_data[reg_id];
if (active) {
value = value.as_xlen(xlen) | mask;
} else {
Expand All @@ -122,29 +128,45 @@ namespace machine { namespace CSR {
emit write_signal(reg_id, value);
}

// TODO this is mips
bool ControlState::core_interrupt_request() {
RegisterValue mstatus = register_data[Id::MSTATUS];
RegisterValue mcause = register_data[Id::MCAUSE];
RegisterValue mie = register_data[Id::MIE];
RegisterValue mip = register_data[Id::MIP];

uint64_t irqs = mstatus.as_u64() & mcause.as_u64() & Status_IntMask;
uint64_t irqs = mie.as_u64() & mip.as_u64() & 0xffffffff;

return irqs && mstatus.as_u64() & Status_IntMask && !(mstatus.as_u64() & Status_EXL)
&& !(mstatus.as_u64() & Status_ERL);
return irqs && read_field(Field::mstatus::MIE).as_u64();
}

// TODO this is mips
void ControlState::set_status_exl(bool value) {
void ControlState::exception_initiate(PrivilegeLevel act_privlev, PrivilegeLevel to_privlev) {
size_t reg_id = Id::MSTATUS;
RegisterValue &reg = register_data[reg_id];
if (value) {
reg = reg.as_xlen(xlen) & Status_EXL;
} else {
reg = reg.as_xlen(xlen) & ~Status_EXL;
}
Q_UNUSED(act_privlev)
Q_UNUSED(to_privlev)

write_field(Field::mstatus::MPIE, read_field(Field::mstatus::MIE).as_u32());
write_field(Field::mstatus::MIE, (uint64_t)0);

write_field(Field::mstatus::MPP, static_cast<uint64_t>(act_privlev));

emit write_signal(reg_id, reg);
}

PrivilegeLevel ControlState::exception_return(enum PrivilegeLevel act_privlev) {
size_t reg_id = Id::MSTATUS;
RegisterValue &reg = register_data[reg_id];
PrivilegeLevel restored_privlev;
Q_UNUSED(act_privlev)

write_field(Field::mstatus::MIE, read_field(Field::mstatus::MPIE).as_u32());

restored_privlev = static_cast<PrivilegeLevel>(read_field(Field::mstatus::MPP).as_u32());
write_field(Field::mstatus::MPP, (uint64_t)0);

emit write_signal(reg_id, reg);

return restored_privlev;
}

machine::Address ControlState::exception_pc_address() {
return machine::Address(register_data[Id::MTVEC].as_u64());
}
Expand Down
3 changes: 2 additions & 1 deletion src/machine/csr/controlstate.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,8 @@ namespace machine { namespace CSR {

public slots:
void set_interrupt_signal(uint irq_num, bool active);
void set_status_exl(bool value);
void exception_initiate(PrivilegeLevel act_privlev, PrivilegeLevel to_privlev);
PrivilegeLevel exception_return(enum PrivilegeLevel act_privlev);

private:
static size_t get_register_internal_id(Address address);
Expand Down
3 changes: 3 additions & 0 deletions src/machine/pipeline.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ struct DecodeInterstage {
bool csr = false; // Zicsr, implies csr read and csr write
bool csr_to_alu = false;
bool csr_write = false;
bool xret = false; // Return from exception, MRET and SRET
bool insert_stall_before = false;

public:
Expand Down Expand Up @@ -177,6 +178,7 @@ struct ExecuteInterstage {
bool alu_zero = false;
bool csr = false;
bool csr_write = false;
bool xret = false;

public:
/** Reset to value corresponding to NOP. */
Expand Down Expand Up @@ -261,6 +263,7 @@ struct MemoryInternalState {
bool branch_outcome = false;
bool branch_jalx = false;
bool branch_jalr = false;
bool xret = false;
};

struct MemoryState {
Expand Down

0 comments on commit 589f210

Please sign in to comment.