diff --git a/README.md b/README.md
index 4e3266a6..ecb9e414 100644
--- a/README.md
+++ b/README.md
@@ -317,49 +317,44 @@ is selected.
Implemented CSR registers and their usage
-(NOTICE: Coprocessor0 will have to be replaced with RISC-V status registers)
+(NOTICE: Replacement of MIPS Coprocessor0 by RISC-V control status registers is work in progress)
List of interrupt sources:
| Irq number | Cause/Status Bit | Source |
|-----------:|-----------------:|:---------------------------------------------|
-| 2 / HW0 | 10 | Serial port ready to accept character to Tx |
-| 3 / HW1 | 11 | There is received character ready to be read |
-| 7 / HW5 | 15 | Counter reached value in Compare register |
+| 7 | 7 | Machine timer interrupt |
+| 16 / HW0 | 16 | There is received character ready to be read |
+| 17 / HW1 | 17 | Serial port ready to accept character to Tx |
-Following coprocessor 0 registers are recognized
+Following Control Status registers are recognized
| Number | Name | Description |
|-------:|:-----------|:--------------------------------------------------------------------|
-| $4,2 | UserLocal | Used as TLS base by operating system usually |
-| $8,0 | BadVAddr | Reports the address for the most recent address-related exception |
-| $9,0 | Count | Processor cycle count |
-| $11,0 | Compare | Timer interrupt control |
-| $12,0 | Status | Processor status and control |
-| $13,0 | Cause | Cause of last exception |
-| $14,0 | EPC | Program counter at last exception |
-| $15,1 | EBase | Exception vector base register |
-| $16,0 | Config | Configuration registers |
-
-`mtc0` and `mfc0` are used to copy value from/to general purpose registers to/from coprocessor 0 register.
-
-Hardware/special registers implemented:
-
-| Number | Name | Description |
-|-------:|:-----------|:---------------------------------------------------------|
-| 0 | CPUNum | CPU number, fixed to 0 |
-| 1 | SYNCI_Step | Increment required for instruction cache synchronization |
-| 2 | CC | Cycle counter |
-| 3 | CCRes | Cycle counter resolution, fixed on 1 |
-| 29 | UserLocal | Read only value of Coprocessor 0 $4,2 register |
+| 0x300 | mstatus | Machine status register. |
+| 0x304 | mie | Machine interrupt-enable register. |
+| 0x305 | mtvec | Machine trap-handler base address. |
+| 0x340 | mscratch | Scratch register for machine trap handlers. |
+| 0x341 | mepc | Machine exception program counter. |
+| 0x342 | mcause | Machine trap cause. |
+| 0x343 | mtval | Machine bad address or instruction. |
+| 0x344 | mip | Machine interrupt pending. |
+| 0x34A | mtinsr | Machine trap instruction (transformed). |
+| 0x34B | mtval2 | Machine bad guest physical address. |
+| 0xB00 | mcycle | Machine cycle counter. |
+| 0xB02 | minstret | Machine instructions-retired counter. |
+| 0xF11 | mvendorid | Vendor ID. |
+| 0xF12 | marchid | Architecture ID. |
+| 0xF13 | mimpid | Implementation ID. |
+| 0xF14 | mhardid | Hardware thread ID. |
+
+`csrr`, `csrw`, `csrrs` , `csrrs` and `csrrw` are used to copy and exchange value from/to RISC-V control status registers.
Sequence to enable serial port receive interrupt:
-Decide location of interrupt service routine the first. The default address is 0x80000180. The base can be
-changed (`EBase` register) and then PC is set to address EBase + 0x180. This is in accordance with MIPS release 1 and 2
-manuals.
+Decide location of interrupt service routine the first. The address of the common trap handler is defined by `mtvec` register and then PC is set to this address when exception or interrupt is accepted.
-Enable bit 11 (interrupt mask) in the Status register. Ensure that bit 1 (`EXL`) is zero and bit 0 (`IE`) is set to one.
+Enable bit 16 in the machine Interrupt-Enable register (`mie`). Ensure that bit 3 (`mstatus.mie` - machine global interrupt-enable) of Machine Status register is set is set to one.
Enable interrupt in the receiver status register (bit 1 of `SERP_RX_ST_REG`).
@@ -367,19 +362,6 @@ Write character to the terminal. It should be immediately consumed by the serial
in `SERP_RX_ST_REG`. CPU should report interrupt exception and when it propagates to the execution phase `PC` is set to
the interrupt routine start address.
-Some hints how to direct linker to place interrupt handler routine at appropriate address. Implement interrupt routine
-in new section
-
-```
-.section .irq_handler, "ax"
-```
-
-Use next linker option to place section start at right address
-
-```
- -Wl,--section-start=.irq_handler=0x80000180
-```
-
### System Calls Support
diff --git a/src/cli/main.cpp b/src/cli/main.cpp
index 1b49a7c9..f470f5c0 100644
--- a/src/cli/main.cpp
+++ b/src/cli/main.cpp
@@ -356,12 +356,13 @@ void configure_osemu(QCommandLineParser &p, MachineConfig &config, Machine *mach
QCoreApplication::exit(1);
}
}
+ const static machine::ExceptionCause ecall_variats[] = {machine::EXCAUSE_ECALL_ANY,
+ machine::EXCAUSE_ECALL_M, machine::EXCAUSE_ECALL_S, machine::EXCAUSE_ECALL_U};
if (config.osemu_enable()) {
auto *osemu_handler = new osemu::OsSyscallExceptionHandler(
config.osemu_known_syscall_stop(), config.osemu_unknown_syscall_stop(),
config.osemu_fs_root());
- machine->register_exception_handler(machine::EXCAUSE_SYSCALL, osemu_handler);
if (std_out) {
machine->connect(
osemu_handler, &osemu::OsSyscallExceptionHandler::char_written,
@@ -370,11 +371,16 @@ void configure_osemu(QCommandLineParser &p, MachineConfig &config, Machine *mach
/*connect(
osemu_handler, &osemu::OsSyscallExceptionHandler::rx_byte_pool, terminal,
&TerminalDock::rx_byte_pool);*/
- machine->set_step_over_exception(machine::EXCAUSE_SYSCALL, true);
- machine->set_stop_on_exception(machine::EXCAUSE_SYSCALL, false);
+ for (unsigned int i = 0; i < sizeof(ecall_variats)/sizeof(ecall_variats[0]); i++) {
+ machine->register_exception_handler(ecall_variats[i], osemu_handler);
+ machine->set_step_over_exception(ecall_variats[i], true);
+ machine->set_stop_on_exception(ecall_variats[i], false);
+ }
} else {
- machine->set_step_over_exception(machine::EXCAUSE_SYSCALL, false);
- machine->set_stop_on_exception(machine::EXCAUSE_SYSCALL, config.osemu_exception_stop());
+ for (unsigned int i = 0; i < sizeof(ecall_variats)/sizeof(ecall_variats[0]); i++) {
+ machine->set_step_over_exception(ecall_variats[i], false);
+ machine->set_stop_on_exception(ecall_variats[i], config.osemu_exception_stop());
+ }
}
}
diff --git a/src/cli/reporter.cpp b/src/cli/reporter.cpp
index 7de84efe..bf2cd3a4 100644
--- a/src/cli/reporter.cpp
+++ b/src/cli/reporter.cpp
@@ -35,17 +35,25 @@ void Reporter::machine_exit() {
constexpr const char *get_exception_name(ExceptionCause exception_cause) {
switch (exception_cause) {
case EXCAUSE_NONE: return "NONE";
- case EXCAUSE_INT: return "INT";
- case EXCAUSE_UNKNOWN: return "UNKNOWN";
- case EXCAUSE_ADDRL: return "ADDRL";
- case EXCAUSE_ADDRS: return "ADDRS";
- case EXCAUSE_IBUS: return "IBUS";
- case EXCAUSE_DBUS: return "DBUS";
- case EXCAUSE_SYSCALL: return "SYSCALL";
+ case EXCAUSE_INSN_FAULT: return "INSN_FAULT";
+ case EXCAUSE_INSN_ILLEGAL: return "INSN_ILLEGAL";
case EXCAUSE_BREAK: return "BREAK";
- case EXCAUSE_OVERFLOW: return "OVERFLOW";
- case EXCAUSE_TRAP: return "TRAP";
+ case EXCAUSE_LOAD_MISALIGNED: return "LOAD_MISALIGNED";
+ case EXCAUSE_LOAD_FAULT: return "LOAD_FAULT";
+ case EXCAUSE_STORE_MISALIGNED: return "STORE_MISALIGNED";
+ case EXCAUSE_STORE_FAULT: return "STORE_FAULT";
+ case EXCAUSE_ECALL_U: return "ECALL_U";
+ case EXCAUSE_ECALL_S: return "ECALL_S";
+ case EXCAUSE_RESERVED_10: return "RESERVED_10";
+ case EXCAUSE_ECALL_M: return "ECALL_M";
+ case EXCAUSE_INSN_PAGE_FAULT: return "INSN_PAGE_FAULT";
+ case EXCAUSE_LOAD_PAGE_FAULT: return "LOAD_PAGE_FAULT";
+ case EXCAUSE_RESERVED_14: return "RESERVED_14";
+ case EXCAUSE_STORE_PAGE_FAULT: return "STORE_PAGE_FAULT";
+ // Simulator specific exception cause codes, alliases
case EXCAUSE_HWBREAK: return "HWBREAK";
+ case EXCAUSE_ECALL_ANY: return "ECALL_ANY";
+ case EXCAUSE_INT: return "INT";
default: UNREACHABLE
}
}
diff --git a/src/gui/mainwindow/mainwindow.cpp b/src/gui/mainwindow/mainwindow.cpp
index 94c61859..887644f7 100644
--- a/src/gui/mainwindow/mainwindow.cpp
+++ b/src/gui/mainwindow/mainwindow.cpp
@@ -263,22 +263,29 @@ void MainWindow::create_core(
set_speed(); // Update machine speed to current settings
+ const static machine::ExceptionCause ecall_variats[] = {machine::EXCAUSE_ECALL_ANY,
+ machine::EXCAUSE_ECALL_M, machine::EXCAUSE_ECALL_S, machine::EXCAUSE_ECALL_U};
+
if (config.osemu_enable()) {
auto *osemu_handler = new osemu::OsSyscallExceptionHandler(
config.osemu_known_syscall_stop(), config.osemu_unknown_syscall_stop(),
config.osemu_fs_root());
- machine->register_exception_handler(machine::EXCAUSE_SYSCALL, osemu_handler);
connect(
osemu_handler, &osemu::OsSyscallExceptionHandler::char_written, terminal.data(),
QOverload::of(&TerminalDock::tx_byte));
connect(
osemu_handler, &osemu::OsSyscallExceptionHandler::rx_byte_pool, terminal.data(),
&TerminalDock::rx_byte_pool);
- machine->set_step_over_exception(machine::EXCAUSE_SYSCALL, true);
- machine->set_stop_on_exception(machine::EXCAUSE_SYSCALL, false);
+ for (unsigned int i = 0; i < sizeof(ecall_variats)/sizeof(ecall_variats[0]); i++) {
+ machine->register_exception_handler(ecall_variats[i], osemu_handler);
+ machine->set_step_over_exception(ecall_variats[i], true);
+ machine->set_stop_on_exception(ecall_variats[i], false);
+ }
} else {
- machine->set_step_over_exception(machine::EXCAUSE_SYSCALL, false);
- machine->set_stop_on_exception(machine::EXCAUSE_SYSCALL, config.osemu_exception_stop());
+ for (unsigned int i = 0; i < sizeof(ecall_variats)/sizeof(ecall_variats[0]); i++) {
+ machine->set_step_over_exception(ecall_variats[i], false);
+ machine->set_stop_on_exception(ecall_variats[i], config.osemu_exception_stop());
+ }
}
// Connect machine signals and slots
@@ -773,4 +780,4 @@ void MainWindow::build_execute_no_check() {
proc->setWorkingDirectory(work_dir);
proc->start("make", {}, QProcess::Unbuffered | QProcess::ReadOnly);
}
-}
\ No newline at end of file
+}
diff --git a/src/gui/windows/coreview/data.h b/src/gui/windows/coreview/data.h
index 52df8742..8edbd786 100644
--- a/src/gui/windows/coreview/data.h
+++ b/src/gui/windows/coreview/data.h
@@ -25,17 +25,25 @@ using machine::RegisterValue;
static const std::unordered_map EXCEPTION_NAME_TABLE = {
{ machine::EXCAUSE_NONE, QStringLiteral("NONE") },
- { machine::EXCAUSE_INT, QStringLiteral("INT") },
- { machine::EXCAUSE_ADDRL, QStringLiteral("ADDRL") },
- { machine::EXCAUSE_ADDRS, QStringLiteral("ADDRS") },
- { machine::EXCAUSE_IBUS, QStringLiteral("IBUS") },
- { machine::EXCAUSE_DBUS, QStringLiteral("DBUS") },
- { machine::EXCAUSE_SYSCALL, QStringLiteral("SYSCALL") },
+ { machine::EXCAUSE_INSN_FAULT, QStringLiteral("I_FAULT") },
+ { machine::EXCAUSE_INSN_ILLEGAL, QStringLiteral("I_ILLEGAL") },
{ machine::EXCAUSE_BREAK, QStringLiteral("BREAK") },
- { machine::EXCAUSE_OVERFLOW, QStringLiteral("OVERFLOW") },
- { machine::EXCAUSE_TRAP, QStringLiteral("TRAP") },
+ { machine::EXCAUSE_LOAD_MISALIGNED, QStringLiteral("L_MALIGN") },
+ { machine::EXCAUSE_LOAD_FAULT, QStringLiteral("L_FAULT") },
+ { machine::EXCAUSE_STORE_MISALIGNED, QStringLiteral("S_MALIGN") },
+ { machine::EXCAUSE_STORE_FAULT, QStringLiteral("S_FAULT") },
+ { machine::EXCAUSE_ECALL_U, QStringLiteral("ECALL_U") },
+ { machine::EXCAUSE_ECALL_S, QStringLiteral("ECALL_S") },
+ { machine::EXCAUSE_RESERVED_10, QStringLiteral("RES_10") },
+ { machine::EXCAUSE_ECALL_M, QStringLiteral("ECALL_M") },
+ { machine::EXCAUSE_INSN_PAGE_FAULT, QStringLiteral("I_PGFAULT") },
+ { machine::EXCAUSE_LOAD_PAGE_FAULT, QStringLiteral("L_PGFAULT") },
+ { machine::EXCAUSE_RESERVED_14, QStringLiteral("RES_14") },
+ { machine::EXCAUSE_STORE_PAGE_FAULT, QStringLiteral("S_PGFAULT") },
+ // Simulator specific exception cause codes, alliases
{ machine::EXCAUSE_HWBREAK, QStringLiteral("HWBREAK") },
- { machine::EXCAUSE_UNKNOWN, QStringLiteral("UNKNOWN") },
+ { machine::EXCAUSE_ECALL_ANY, QStringLiteral("ECALL") },
+ { machine::EXCAUSE_INT, QStringLiteral("INT") },
};
static const std::unordered_map STALL_TEXT_TABLE = {
diff --git a/src/machine/CMakeLists.txt b/src/machine/CMakeLists.txt
index 02f17fda..f44e3321 100644
--- a/src/machine/CMakeLists.txt
+++ b/src/machine/CMakeLists.txt
@@ -139,6 +139,8 @@ if(NOT ${WASM})
add_test(NAME cache COMMAND cache_test)
add_executable(instruction_test
+ csr/controlstate.cpp
+ csr/controlstate.h
instruction.cpp
instruction.h
instruction.test.cpp
@@ -151,6 +153,8 @@ if(NOT ${WASM})
add_test(NAME instruction COMMAND instruction_test)
add_executable(program_loader_test
+ csr/controlstate.cpp
+ csr/controlstate.h
instruction.cpp
instruction.h
memory/backend/backend_memory.h
diff --git a/src/machine/bitfield.h b/src/machine/bitfield.h
index 9b84c70e..ccc99763 100644
--- a/src/machine/bitfield.h
+++ b/src/machine/bitfield.h
@@ -20,11 +20,14 @@ struct BitField {
template
[[nodiscard]] T decode(T val) const {
- return (val >> offset) & ((1L << count) - 1);
+ return (val >> offset) & (((uint64_t)1 << count) - 1);
}
template
[[nodiscard]] T encode(T val) const {
- return ((val & ((1L << count) - 1)) << offset);
+ return ((val & (((uint64_t)1 << count) - 1)) << offset);
+ }
+ [[nodiscard]] uint64_t mask() const {
+ return (((uint64_t)1 << count) - 1) << offset;
}
};
diff --git a/src/machine/core.cpp b/src/machine/core.cpp
index 0e5afb07..29ae557d 100644
--- a/src/machine/core.cpp
+++ b/src/machine/core.cpp
@@ -129,7 +129,7 @@ bool Core::handle_exception(
Address next_addr,
Address jump_branch_pc,
Address mem_ref_addr) {
- if (excause == EXCAUSE_UNKNOWN) {
+ if (excause == EXCAUSE_INSN_ILLEGAL) {
throw SIMULATOR_EXCEPTION(
UnsupportedInstruction, "Instruction with following encoding is not supported",
QString::number(inst.data(), 16));
@@ -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());
}
}
@@ -224,7 +224,7 @@ DecodeState Core::decode(const FetchInterstage &dt) {
dt.inst.flags_alu_op_mem_ctl(flags, alu_op, mem_ctl);
- if (!(flags & IMF_SUPPORTED)) { excause = EXCAUSE_UNKNOWN; }
+ if (!(flags & IMF_SUPPORTED)) { excause = EXCAUSE_INSN_ILLEGAL; }
RegisterId num_rs = (flags & (IMF_ALU_REQ_RS | IMF_ALU_RS_ID)) ? dt.inst.rs() : 0;
RegisterId num_rt = (flags & IMF_ALU_REQ_RT) ? dt.inst.rt() : 0;
@@ -246,7 +246,7 @@ DecodeState Core::decode(const FetchInterstage &dt) {
if (flags & IMF_EBREAK) {
excause = EXCAUSE_BREAK;
} else if (flags & IMF_ECALL) {
- excause = EXCAUSE_SYSCALL;
+ excause = EXCAUSE_ECALL_ANY;
}
}
if (flags & IMF_FORCE_W_OP)
@@ -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) } };
}
@@ -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,
} };
}
@@ -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) {
@@ -395,6 +398,13 @@ 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);
@@ -402,13 +412,16 @@ MemoryState Core::memory(const ExecuteInterstage &dt) {
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,
@@ -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;
@@ -448,7 +462,7 @@ WritebackState Core::writeback(const MemoryInterstage &dt) {
if (dt.regwrite) { regs->write_gp(dt.num_rd, dt.towrite_val); }
return WritebackState { WritebackInternalState {
- .inst = dt.inst,
+ .inst = (dt.excause == EXCAUSE_NONE)? dt.inst: Instruction::NOP,
.inst_addr = dt.inst_addr,
.value = dt.towrite_val,
.num_rd = dt.num_rd,
diff --git a/src/machine/csr/controlstate.cpp b/src/machine/csr/controlstate.cpp
index f2134706..3ee3f0e5 100644
--- a/src/machine/csr/controlstate.cpp
+++ b/src/machine/csr/controlstate.cpp
@@ -1,3 +1,4 @@
+#include
#include "controlstate.h"
#include "common/logging.h"
@@ -8,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();
}
@@ -53,14 +46,14 @@ namespace machine { namespace CSR {
// Only machine level privilege is supported so no checking is needed.
size_t reg_id = get_register_internal_id(address);
RegisterValue value = register_data[reg_id];
- DEBUG("Read CSR[%u] == %lu", address.data, value.as_u64());
+ DEBUG("Read CSR[%u] == 0x%" PRIx64, address.data, value.as_u64());
emit read_signal(reg_id, value);
return value;
}
void ControlState::write(Address address, RegisterValue value) {
DEBUG(
- "Write CSR[%u/%lu] <== %lu", address.data, get_register_internal_id(address),
+ "Write CSR[%u/%lu] <== 0x%" PRIx64, address.data, get_register_internal_id(address),
value.as_u64());
// Attempts to write a read-only register also raise illegal instruction exceptions.
if (!address.is_writable()) {
@@ -71,6 +64,24 @@ namespace machine { namespace CSR {
write_internal(get_register_internal_id(address), value);
}
+ void ControlState::default_wlrl_write_handler(
+ const RegisterDesc &desc,
+ RegisterValue ®,
+ RegisterValue val) {
+ uint64_t u;
+ u = val.as_u64() & desc.write_mask.as_u64();
+ u |= reg.as_u64() & ~desc.write_mask.as_u64();
+ if (xlen == Xlen::_32)
+ u &= 0xffffffff;
+ reg = u;
+ }
+ void ControlState::mstatus_wlrl_write_handler(
+ const RegisterDesc &desc,
+ RegisterValue ®,
+ RegisterValue val) {
+ default_wlrl_write_handler(desc, reg, val);
+ }
+
bool ControlState::operator==(const ControlState &other) const {
return register_data == other.register_data;
}
@@ -81,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(excause) << 2;
+ value = static_cast(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 {
@@ -103,27 +128,43 @@ 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 ® = 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(act_privlev));
+
+ emit write_signal(reg_id, reg);
+ }
+
+ PrivilegeLevel ControlState::exception_return(enum PrivilegeLevel act_privlev) {
+ size_t reg_id = Id::MSTATUS;
+ RegisterValue ® = 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(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() {
@@ -136,8 +177,9 @@ namespace machine { namespace CSR {
void ControlState::write_internal(size_t internal_id, RegisterValue value) {
RegisterDesc desc = REGISTERS[internal_id];
- (this->*desc.write_handler)(desc, register_data[internal_id], value);
- write_signal(internal_id, value);
+ RegisterValue ® = register_data[internal_id];
+ (this->*desc.write_handler)(desc, reg, value);
+ write_signal(internal_id, reg);
}
void ControlState::increment_internal(size_t internal_id, uint64_t amount) {
auto value = register_data[internal_id];
diff --git a/src/machine/csr/controlstate.h b/src/machine/csr/controlstate.h
index 7f68711a..f5346643 100644
--- a/src/machine/csr/controlstate.h
+++ b/src/machine/csr/controlstate.h
@@ -6,6 +6,7 @@
#include "machinedefs.h"
#include "register_value.h"
#include "simulator_exception.h"
+#include "bitfield.h"
#include
#include
@@ -15,7 +16,7 @@
namespace machine { namespace CSR {
/** CSR register names mapping the registers to continuous locations in internal buffer */
struct Id {
- enum {
+ enum IdxType{
// Machine Information Registers
MVENDORID,
MARCHID,
@@ -48,6 +49,26 @@ namespace machine { namespace CSR {
struct RegisterDesc;
+ struct RegisterFieldDesc {
+ uint64_t decode(uint64_t val) const {
+ return field.decode(val);
+ }
+ uint64_t encode(uint64_t val) const {
+ return field.encode(val);
+ }
+ uint64_t mask() const {
+ return field.mask();
+ }
+ uint64_t update(uint64_t orig, uint64_t val) const {
+ return field.encode(val) | (orig & ~mask());
+ }
+
+ const char *name = "unknown";
+ const Id::IdxType regId;
+ const BitField field;
+ const char *description = "";
+ };
+
/**
* This class provides access to state of CSR registers.
*
@@ -86,6 +107,18 @@ namespace machine { namespace CSR {
/** Reset data to initial values */
void reset();
+ /** Read CSR register field */
+ RegisterValue read_field(const RegisterFieldDesc &field_desc) const {
+ return field_desc.decode(read_internal(field_desc.regId).as_u64());
+ }
+
+ /** Write CSR register field */
+ void write_field(const RegisterFieldDesc &field_desc, uint64_t value) {
+ uint64_t u = read_internal(field_desc.regId).as_u64();
+ u = field_desc.update(u, value);
+ write_internal(field_desc.regId, u);
+ }
+
void update_exception_cause(enum ExceptionCause excause);
bool operator==(const ControlState &other) const;
@@ -100,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);
@@ -114,13 +148,14 @@ namespace machine { namespace CSR {
std::array register_data;
public:
- void default_wlrl_write_handler( // NOLINT(readability-convert-member-functions-to-static)
+ void default_wlrl_write_handler(
const RegisterDesc &desc,
RegisterValue ®,
- RegisterValue val) {
- UNUSED(desc)
- reg = val;
- }
+ RegisterValue val);
+ void mstatus_wlrl_write_handler(
+ const RegisterDesc &desc,
+ RegisterValue ®,
+ RegisterValue val);
};
struct RegisterDesc {
@@ -131,17 +166,36 @@ namespace machine { namespace CSR {
Address address = Address(0);
const char *description = "";
RegisterValue initial_value = 0;
- RegisterValue write_mask = 0;
+ RegisterValue write_mask = (register_storage_t)0xffffffffffffffff;
WriteHandlerFn write_handler = &ControlState::default_wlrl_write_handler;
+ struct {
+ const RegisterFieldDesc * const *array;
+ const unsigned count;
+ } fields = {nullptr, 0};
};
+ namespace Field {
+ namespace mstatus {
+ static constexpr RegisterFieldDesc SIE = { "SIE", Id::MSTATUS, {1, 1}, "System global interrupt-enable"};
+ static constexpr RegisterFieldDesc MIE = { "SIE", Id::MSTATUS, {1, 3}, "Machine global interrupt-enable"};
+ static constexpr RegisterFieldDesc SPIE = { "SPIE", Id::MSTATUS, {1, 5}, "Previous SIE before the trap"};
+ static constexpr RegisterFieldDesc MPIE = { "MPIE", Id::MSTATUS, {1, 7}, "Previous MIE before the trap"};
+ static constexpr RegisterFieldDesc SPP = { "SPP", Id::MSTATUS, {1, 8}, "System previous privilege mode"};
+ static constexpr RegisterFieldDesc MPP = { "MPP", Id::MSTATUS, {2, 11}, "Machine previous privilege mode"};
+ static constexpr const RegisterFieldDesc *fields[] = { &SIE, &MIE, &SPIE, &MPIE, &SPP, &MPP};
+ static constexpr unsigned count = sizeof(fields) / sizeof(fields[0]);
+ }
+ }
+
/** Definitions of supported CSR registers */
inline constexpr std::array REGISTERS { {
[Id::MVENDORID] = { "mvendorid", 0xF11_csr, "Vendor ID." },
[Id::MARCHID] = { "marchid", 0xF12_csr, "Architecture ID." },
[Id::MIMPID] = { "mimpid", 0xF13_csr, "Implementation ID." },
[Id::MHARTID] = { "mhardid", 0xF14_csr, "Hardware thread ID." },
- [Id::MSTATUS] = { "mstatus", 0x300_csr, "Machine status register." },
+ [Id::MSTATUS] = { "mstatus", 0x300_csr, "Machine status register.",
+ 0, 0x807FFFEA, &ControlState::mstatus_wlrl_write_handler,
+ {Field::mstatus::fields, Field::mstatus::count} },
[Id::MIE] = { "mie", 0x304_csr, "Machine interrupt-enable register." },
[Id::MTVEC] = { "mtvec", 0x305_csr, "Machine trap-handler base address." },
[Id::MSCRATCH] = { "mscratch", 0x340_csr, "Scratch register for machine trap handlers." },
diff --git a/src/machine/instruction.cpp b/src/machine/instruction.cpp
index 86d2e372..05a22058 100644
--- a/src/machine/instruction.cpp
+++ b/src/machine/instruction.cpp
@@ -11,6 +11,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -205,7 +206,7 @@ static const struct InstructionMap OP_ALU_map[] = {
// RV32M
#define MUL_MAP_ITEM(NAME, OP, CODE) \
- { NAME, IT_R, { .mul_op = (OP) }, NOMEM, nullptr, {"d", "s", "t"}, (0x02000033 | (CODE)), 0xfc00707f, { .flags = (FLAGS_ALU_T_R_STD | IMF_MUL) }}
+ { NAME, IT_R, { .mul_op = (OP) }, NOMEM, nullptr, {"d", "s", "t"}, (0x02000033 | (CODE)), 0xfe00707f, { .flags = (FLAGS_ALU_T_R_STD | IMF_MUL) }}
static const struct InstructionMap OP_MUL_map[] = {
MUL_MAP_ITEM("mul", MulOp::MUL, 0x0000),
@@ -240,11 +241,48 @@ static const struct InstructionMap ENVIRONMENT_AND_BREAKPOINTS_map[] = {
{"ebreak", IT_I, NOALU, NOMEM, nullptr, {}, 0x00100073, 0xffffffff, { .flags = IMF_SUPPORTED | IMF_EXCEPTION | IMF_EBREAK }},
};
+// Priviledged system isntructions, only 5-bits (29:25) are decoded for now.
+// Full decode is should cover 128 entries (31:25) but we radly support hypervisor even in future
+static const struct InstructionMap SYSTEM_PRIV_map[] = {
+ {"environment_and_breakpoints", IT_I, NOALU, NOMEM, ENVIRONMENT_AND_BREAKPOINTS_map, {}, 0x00000073, 0xffffffff, { .subfield = {1, 20} }},
+ IM_UNKNOWN,
+ IM_UNKNOWN,
+ IM_UNKNOWN,
+ IM_UNKNOWN,
+ IM_UNKNOWN,
+ IM_UNKNOWN,
+ IM_UNKNOWN,
+ {"sret", IT_I, NOALU, NOMEM, nullptr, {}, 0x10200073, 0xffffffff, { .flags = IMF_SUPPORTED | IMF_XRET }},
+ IM_UNKNOWN,
+ IM_UNKNOWN,
+ IM_UNKNOWN,
+ IM_UNKNOWN,
+ IM_UNKNOWN,
+ IM_UNKNOWN,
+ IM_UNKNOWN,
+ IM_UNKNOWN,
+ IM_UNKNOWN,
+ IM_UNKNOWN,
+ IM_UNKNOWN,
+ IM_UNKNOWN,
+ IM_UNKNOWN,
+ IM_UNKNOWN,
+ IM_UNKNOWN,
+ {"mret", IT_I, NOALU, NOMEM, nullptr, {}, 0x30200073, 0xffffffff, { .flags = IMF_SUPPORTED | IMF_XRET }},
+ IM_UNKNOWN,
+ IM_UNKNOWN,
+ IM_UNKNOWN,
+ IM_UNKNOWN,
+ IM_UNKNOWN,
+ IM_UNKNOWN,
+ IM_UNKNOWN,
+};
+
#define CSR_MAP_ITEM(NAME, SOURCE, CODE, ALU_OP, EXTRA_FLAGS) \
- { NAME, Instruction::ZICSR, { .alu_op=AluOp::ALU_OP }, NOMEM, nullptr, {"d", "E", SOURCE}, 0x00000073 | (CODE), 0x0000003f, { .flags = IMF_SUPPORTED | IMF_CSR | IMF_REGWRITE | IMF_ALU_REQ_RS | (EXTRA_FLAGS) } }
+ { NAME, Instruction::ZICSR, { .alu_op=AluOp::ALU_OP }, NOMEM, nullptr, {"d", "E", SOURCE}, 0x00000073 | (CODE), 0x0000707f, { .flags = IMF_SUPPORTED | IMF_CSR | IMF_REGWRITE | IMF_ALU_REQ_RS | (EXTRA_FLAGS) } }
static const struct InstructionMap SYSTEM_map[] = {
- {"environment_and_breakpoints", IT_I, NOALU, NOMEM, ENVIRONMENT_AND_BREAKPOINTS_map, {}, 0x00000073, 0xffffffff, { .subfield = {1, 20} }},
+ {"system_priviledged", IT_I, NOALU, NOMEM, SYSTEM_PRIV_map, {}, 0x00000073, 0xffffffff, { .subfield = {5, 25} }},
CSR_MAP_ITEM("csrrw", "s", 0x1000, ADD, 0),
CSR_MAP_ITEM("csrrs", "s", 0x2000, OR, IMF_CSR_TO_ALU),
CSR_MAP_ITEM("csrrc", "s", 0x3000, AND, IMF_CSR_TO_ALU | IMF_ALU_MOD),
@@ -257,8 +295,8 @@ static const struct InstructionMap SYSTEM_map[] = {
#undef CSR_MAP_ITEM
static const struct InstructionMap MISC_MEM_map[] = {
- {"fence", IT_I, NOALU, AC_CACHE_OP, nullptr, {}, 0x0000000f, 0x0000703f, { .flags = IMF_SUPPORTED | IMF_MEM }},
- {"fence.i", IT_I, NOALU, AC_CACHE_OP, nullptr, {}, 0x000100f, 0x0000703f, { .flags = IMF_SUPPORTED | IMF_MEM }},
+ {"fence", IT_I, NOALU, AC_CACHE_OP, nullptr, {}, 0x0000000f, 0x0000707f, { .flags = IMF_SUPPORTED | IMF_MEM }},
+ {"fence.i", IT_I, NOALU, AC_CACHE_OP, nullptr, {}, 0x000100f, 0x0000707f, { .flags = IMF_SUPPORTED | IMF_MEM }},
IM_UNKNOWN,
IM_UNKNOWN,
IM_UNKNOWN,
@@ -308,7 +346,7 @@ static const struct InstructionMap OP_ALU_32_map[] = {
// RV64M
#define MUL_32_MAP_ITEM(NAME, OP, CODE) \
- { NAME, IT_R, { .mul_op = (OP) }, NOMEM, nullptr, {"d", "s", "t"}, (0x0200003b | (CODE)), 0xfc00707f, { .flags = (FLAGS_ALU_T_R_STD | IMF_MUL | IMF_FORCE_W_OP ) }}
+ { NAME, IT_R, { .mul_op = (OP) }, NOMEM, nullptr, {"d", "s", "t"}, (0x0200003b | (CODE)), 0xfe00707f, { .flags = (FLAGS_ALU_T_R_STD | IMF_MUL | IMF_FORCE_W_OP ) }}
static const struct InstructionMap OP_MUL_32_map[] = {
MUL_32_MAP_ITEM("mulw", MulOp::MUL, 0x0000),
@@ -373,6 +411,8 @@ static const struct InstructionMap C_inst_map[] = {
{"i", IT_UNKNOWN, NOALU, NOMEM, I_inst_map, {}, 0x3, 0x3, { .subfield = {5, 2} }},
};
+static const struct InstructionMap C_inst_unknown = IM_UNKNOWN;
+
// clang-format on
const BitField instruction_map_opcode_field = { 2, 0 };
@@ -382,14 +422,17 @@ static inline const struct InstructionMap &InstructionMapFind(uint32_t code) {
while (im->subclass != nullptr) {
im = &im->subclass[im->subfield.decode(code)];
}
+ if ((code ^ im->code) & im->mask) {
+ return C_inst_unknown;
+ }
return *im;
}
-const std::array RECOGNIZED_PSEUDOINSTRUCTIONS {
+const std::array RECOGNIZED_PSEUDOINSTRUCTIONS {
"nop", "la", "li", "mv", "not", "neg", "negw", "sext.b", "sext.h",
"sext.w", "zext.b", "zext.h", "zext.w", "seqz", "snez", "sltz", "slgz", "beqz",
"bnez", "blez", "bgez", "bltz", "bgtz", "bgt", "ble", "bgtu", "bleu",
- "j", "jal", "jr", "jalr", "ret", "call", "tail"
+ "j", "jal", "jr", "jalr", "ret", "call", "tail", "csrr", "csrw"
};
bool Instruction::symbolic_registers_enabled = false;
@@ -498,7 +541,6 @@ void Instruction::flags_alu_op_mem_ctl(
flags = (enum InstructionFlags)im.flags;
alu_op = im.alu;
mem_ctl = im.mem_ctl;
- if ((dt ^ im.code) & (im.mask)) { flags = (enum InstructionFlags)(flags & ~IMF_SUPPORTED); }
}
bool Instruction::operator==(const Instruction &c) const {
@@ -588,23 +630,31 @@ QMultiMap str_to_instruction_code_map;
void instruction_from_string_build_base(
const InstructionMap *im,
BitField field,
- uint32_t base_code) {
+ uint32_t base_code, uint32_t base_mask) {
uint32_t code;
uint8_t bits = field.count;
uint8_t shift = field.offset;
+ base_mask |= (((uint32_t)1 << bits) - 1) << shift;
+
for (unsigned int i = 0; i < 1U << bits; i++, im++) {
code = base_code | (i << shift);
if (im->subclass) {
- instruction_from_string_build_base(im->subclass, im->subfield, code);
+ instruction_from_string_build_base(im->subclass, im->subfield, code, base_mask);
continue;
}
if (!(im->flags & IMF_SUPPORTED)) { continue; }
- if (im->code != code) {
- ERROR("code mismatch %s computed 0x%08x found 0x%08x", im->name, code, im->code);
+ if ((im->code ^ code) & base_mask) {
+ ERROR("code mismatch %s computed 0x%08" PRIx32 " (mask 0x%08" PRIx32 ") found 0x%08" PRIx32,
+ im->name, code, base_mask, im->code);
+ continue;
+ }
+ if (~im->mask & base_mask) {
+ ERROR("code mismatch %s computed 0x%08" PRIx32 " (mask 0x%08" PRIx32 ") found 0x%08" PRIx32 " with too wide mask 0x%08" PRIx32,
+ im->name, code, base_mask, im->code, im->mask);
continue;
}
- str_to_instruction_code_map.insert(im->name, code);
+ str_to_instruction_code_map.insert(im->name, im->code);
}
#if 0
for (auto i = str_to_instruction_code_map.begin();
@@ -614,7 +664,7 @@ void instruction_from_string_build_base(
}
void instruction_from_string_build_base() {
- return instruction_from_string_build_base(C_inst_map, instruction_map_opcode_field, 0);
+ return instruction_from_string_build_base(C_inst_map, instruction_map_opcode_field, 0, 0);
}
static int parse_reg_from_string(const QString &str, uint *chars_taken = nullptr) {
@@ -945,7 +995,14 @@ size_t Instruction::pseudo_from_tokens(
.data();
return 8;
}
-
+ if (inst.base[0] == 'c') {
+ if (inst.base == QLatin1String("csrr")) {
+ return partially_apply("csrrs", 2, 2, "x0", code, buffsize, inst, reloc);
+ }
+ if (inst.base == QLatin1String("csrw")) {
+ return partially_apply("csrrw", 2, 0, "x0", code, buffsize, inst, reloc);
+ }
+ }
return 0;
}
size_t Instruction::partially_apply(
diff --git a/src/machine/instruction.h b/src/machine/instruction.h
index 902e2b4b..e7a4ed88 100644
--- a/src/machine/instruction.h
+++ b/src/machine/instruction.h
@@ -45,15 +45,16 @@ enum InstructionFlags : unsigned {
IMF_FORCE_W_OP = 1L << 15, /**< Force word (32-bit) operation even for XLEN=64 */
IMF_ECALL = 1L << 16, // seems easiest to encode ecall and ebreak as flags, but they might
IMF_EBREAK = 1L << 17, // be moved elsewhere in case we run out of InstructionFlag space.
+ IMF_XRET = 1L << 18, /**< Return from exception, MRET and SRET */
// Extensions:
// =============================================================================================
// RV64/32M
- IMF_MUL = 1L << 18, /**< Enables multiplication component of ALU. */
+ IMF_MUL = 1L << 19, /**< Enables multiplication component of ALU. */
// Zicsr
- IMF_CSR = 1L << 19, /**< Implies csr read and write */
- IMF_CSR_TO_ALU = 1L << 20, /**< Instruction modifies the current value */
- IMF_ALU_RS_ID = 1L << 21,
+ IMF_CSR = 1L << 20, /**< Implies csr read and write */
+ IMF_CSR_TO_ALU = 1L << 21, /**< Instruction modifies the current value */
+ IMF_ALU_RS_ID = 1L << 22,
// TODO do we want to add those signals to the visualization?
};
diff --git a/src/machine/machine.cpp b/src/machine/machine.cpp
index f13c4588..3f0f1e21 100644
--- a/src/machine/machine.cpp
+++ b/src/machine/machine.cpp
@@ -392,8 +392,8 @@ enum ExceptionCause Machine::get_exception_cause() const {
if (controlst == nullptr) {
return EXCAUSE_NONE;
}
- val = (controlst->read_internal(CSR::Id::MCAUSE).as_u64() >> 2) & 0x3f;
- if (val == 0) {
+ val = (controlst->read_internal(CSR::Id::MCAUSE).as_u64());
+ if (val & 0xffffffff80000000) {
return EXCAUSE_INT;
} else {
return (ExceptionCause)val;
diff --git a/src/machine/machinedefs.h b/src/machine/machinedefs.h
index 4858757d..becb3a23 100644
--- a/src/machine/machinedefs.h
+++ b/src/machine/machinedefs.h
@@ -40,19 +40,27 @@ static_assert(is_special_access((AccessControl)11), "");
enum ExceptionCause {
EXCAUSE_NONE = 0, // Use zero as default value when no exception is
- // pending.
- EXCAUSE_INT = 1, // Int is 0 on real CPU and in Cause register.
- EXCAUSE_UNKNOWN = 2,
- EXCAUSE_ADDRL = 4,
- EXCAUSE_ADDRS = 5,
- EXCAUSE_IBUS = 6,
- EXCAUSE_DBUS = 7,
- EXCAUSE_SYSCALL = 8,
- EXCAUSE_BREAK = 9,
- EXCAUSE_OVERFLOW = 12,
- EXCAUSE_TRAP = 13,
- EXCAUSE_HWBREAK = 14,
- EXCAUSE_COUNT = 15,
+ // ECAUSE_INSN_MISALIGNED - not defined for now, overlaps with EXCAUSE_NON
+ EXCAUSE_INSN_FAULT = 1, // Instruction access fault
+ EXCAUSE_INSN_ILLEGAL = 2, // Illegal instruction
+ EXCAUSE_BREAK = 3, // Breakpoint
+ EXCAUSE_LOAD_MISALIGNED = 4, // Load address misaligned
+ EXCAUSE_LOAD_FAULT = 5, // Load access fault
+ EXCAUSE_STORE_MISALIGNED = 6, // Store/AMO address misaligned
+ EXCAUSE_STORE_FAULT = 7, // Store/AMO access fault
+ EXCAUSE_ECALL_U = 8, // Environment call from U-mode
+ EXCAUSE_ECALL_S = 9, // Environment call from S-mode
+ EXCAUSE_RESERVED_10 = 10, // Reserved
+ EXCAUSE_ECALL_M = 11, // Environment call from M-mode
+ EXCAUSE_INSN_PAGE_FAULT = 12, // Instruction page fault
+ EXCAUSE_LOAD_PAGE_FAULT = 13, // Load page fault
+ EXCAUSE_RESERVED_14 = 14, // Reserved
+ EXCAUSE_STORE_PAGE_FAULT = 15, // Store/AMO page fault
+ // Simulator specific exception cause codes, alliases
+ EXCAUSE_HWBREAK = 16,
+ EXCAUSE_ECALL_ANY = 17, // sythetic exception to mark ECALL instruction
+ EXCAUSE_INT = 18, // External/asynchronous interrupt, bit 32 or 63
+ EXCAUSE_COUNT = 19,
};
enum LocationStatus {
diff --git a/src/machine/memory/backend/serialport.cpp b/src/machine/memory/backend/serialport.cpp
index 435805fd..f79a587d 100644
--- a/src/machine/memory/backend/serialport.cpp
+++ b/src/machine/memory/backend/serialport.cpp
@@ -8,21 +8,22 @@ using ae = machine::AccessEffects; // For enum values, type is obvious from
namespace machine {
constexpr Offset SERP_RX_ST_REG_o = 0x00u;
-constexpr Offset SERP_RX_ST_REG_READY_m = 0x1u;
-constexpr Offset SERP_RX_ST_REG_IE_m = 0x2u;
+constexpr uint32_t SERP_RX_ST_REG_READY_m = 0x1u;
+constexpr uint32_t SERP_RX_ST_REG_IE_m = 0x2u;
constexpr Offset SERP_RX_DATA_REG_o = 0x04u;
constexpr Offset SERP_TX_ST_REG_o = 0x08u;
-constexpr Offset SERP_TX_ST_REG_READY_m = 0x1u;
-constexpr Offset SERP_TX_ST_REG_IE_m = 0x2u;
+constexpr uint32_t SERP_TX_ST_REG_READY_m = 0x1u;
+constexpr uint32_t SERP_TX_ST_REG_IE_m = 0x2u;
constexpr Offset SERP_TX_DATA_REG_o = 0xcu;
SerialPort::SerialPort(Endian simulated_machine_endian)
: BackendMemory(simulated_machine_endian)
- , tx_irq_level(2)
- , rx_irq_level(3) // HW interrupt 1
+ , tx_irq_level(17) // The second platform HW interrupt
+ , rx_irq_level(16) // The first platform HW interrupt
+ , tx_st_reg(SERP_TX_ST_REG_READY_m)
{}
SerialPort::~SerialPort() = default;
@@ -129,7 +130,7 @@ uint32_t SerialPort::read_reg(Offset source, AccessEffects type) const {
}
rx_queue_check_internal();
break;
- case SERP_TX_ST_REG_o: value = tx_st_reg | SERP_TX_ST_REG_READY_m; break;
+ case SERP_TX_ST_REG_o: value = tx_st_reg; break;
default: printf("WARNING: Serial port - read out of range (at 0x%lu).\n", source); break;
}
@@ -189,4 +190,4 @@ LocationStatus SerialPort::location_status(Offset offset) const {
uint32_t SerialPort::get_change_counter() const {
return change_counter;
}
-} // namespace machine
\ No newline at end of file
+} // namespace machine
diff --git a/src/machine/pipeline.h b/src/machine/pipeline.h
index 4da7029a..92b1a74b 100644
--- a/src/machine/pipeline.h
+++ b/src/machine/pipeline.h
@@ -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:
@@ -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. */
@@ -261,6 +263,7 @@ struct MemoryInternalState {
bool branch_outcome = false;
bool branch_jalx = false;
bool branch_jalr = false;
+ bool xret = false;
};
struct MemoryState {
diff --git a/tests/cli/stalls/stdout.txt b/tests/cli/stalls/stdout.txt
index 7178cb69..d5c3cdd4 100644
--- a/tests/cli/stalls/stdout.txt
+++ b/tests/cli/stalls/stdout.txt
@@ -2,4 +2,4 @@ Machine stopped on BREAK exception.
Machine state report:
PC:0x00000244
R0:0x00000000 R1:0x00000011 R2:0x00000022 R3:0x00000033 R4:0x00000000 R5:0x00000055 R6:0x00000000 R7:0x00000000 R8:0x00000000 R9:0x00000000 R10:0x00000000 R11:0x00000000 R12:0x00000000 R13:0x00000000 R14:0x00000000 R15:0x00000000 R16:0x00000000 R17:0x00000000 R18:0x00000000 R19:0x00000000 R20:0x00000000 R21:0x00000011 R22:0x00000022 R23:0x00000033 R24:0x00000044 R25:0x00000055 R26:0x00000000 R27:0x00000000 R28:0x00000000 R29:0x00000000 R30:0x00000000 R31:0x00000000
-mvendorid: 0x00000000 marchid: 0x00000000 mimpid: 0x00000000 mhardid: 0x00000000 mstatus: 0x00000000 mie: 0x00000000 mtvec: 0x00000000 mscratch: 0x00000000 mepc: 0x00000240 mcause: 0x00000024 mtval: 0x00000000 mip: 0x00000000 mtinsr: 0x00000000 mtval2: 0x00000000 mcycle: 0x0000000c minstret: 0x0000000b
+mvendorid: 0x00000000 marchid: 0x00000000 mimpid: 0x00000000 mhardid: 0x00000000 mstatus: 0x00000000 mie: 0x00000000 mtvec: 0x00000000 mscratch: 0x00000000 mepc: 0x00000240 mcause: 0x00000003 mtval: 0x00000000 mip: 0x00000000 mtinsr: 0x00000000 mtval2: 0x00000000 mcycle: 0x0000000c minstret: 0x0000000b