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