diff --git a/src/Targets/CMakeLists.txt b/src/Targets/CMakeLists.txt index 01432db5..5c872714 100755 --- a/src/Targets/CMakeLists.txt +++ b/src/Targets/CMakeLists.txt @@ -9,4 +9,5 @@ target_sources( ${CMAKE_CURRENT_SOURCE_DIR}/Microchip/AVR/AVR8/PhysicalInterface.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Microchip/AVR/AVR8/TargetDescription/TargetDescriptionFile.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Microchip/AVR/AVR8/OpcodeDecoder/Decoder.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/RiscV/RiscV.cpp ) diff --git a/src/Targets/RiscV/DebugModule/Registers/RegisterAddresses.hpp b/src/Targets/RiscV/DebugModule/Registers/RegisterAddresses.hpp new file mode 100644 index 00000000..a932c399 --- /dev/null +++ b/src/Targets/RiscV/DebugModule/Registers/RegisterAddresses.hpp @@ -0,0 +1,12 @@ +#pragma once + +#include + +namespace Targets::RiscV::DebugModule::Registers +{ + enum RegisterAddresses: std::uint8_t + { + CONTROL_REGISTER = 0x10, + STATUS_REGISTER = 0x11, + }; +} diff --git a/src/Targets/RiscV/RiscV.cpp b/src/Targets/RiscV/RiscV.cpp new file mode 100644 index 00000000..86bb8a77 --- /dev/null +++ b/src/Targets/RiscV/RiscV.cpp @@ -0,0 +1,223 @@ +#include "RiscV.hpp" + +#include +#include + +#include "DebugModule/Registers/RegisterAddresses.hpp" + +#include "src/Exceptions/Exception.hpp" + +#include "src/Logger/Logger.hpp" + +namespace Targets::RiscV +{ + using DebugModule::Registers::RegisterAddresses; + using DebugModule::Registers::ControlRegister; + using DebugModule::Registers::StatusRegister; + + RiscV::RiscV(const TargetConfig& targetConfig) + : name("CH32X035C8T6") // TODO: TDF + {} + + bool RiscV::supportsDebugTool(DebugTool* debugTool) { + return debugTool->getRiscVDebugInterface() != nullptr; + } + + void RiscV::setDebugTool(DebugTool* debugTool) { + this->riscVDebugInterface = debugTool->getRiscVDebugInterface(); + } + + void RiscV::activate() { + this->riscVDebugInterface->activate({}); + + // TODO: Select a hart here. + + this->stop(); + } + + void RiscV::deactivate() { + this->riscVDebugInterface->deactivate(); + } + + TargetDescriptor RiscV::getDescriptor() { + return TargetDescriptor( + "TDF ID", + TargetFamily::RISC_V, + this->name, + "TDF VENDOR NAME", + { + { + Targets::TargetMemoryType::FLASH, + TargetMemoryDescriptor( + Targets::TargetMemoryType::FLASH, + Targets::TargetMemoryAddressRange(0x00, 0x1000), + Targets::TargetMemoryAccess(true, true, false) + ) + } + }, + {}, + BreakpointResources(0, 0, 0), + {}, + TargetMemoryType::FLASH + ); + } + + void RiscV::run(std::optional toAddress) { + auto controlRegister = ControlRegister(); + controlRegister.debugModuleActive = true; + controlRegister.resumeRequest = true; + + this->writeControlRegister(controlRegister); + + constexpr auto maxAttempts = 10; + auto statusRegister = this->readStatusRegister(); + + for (auto attempts = 1; !statusRegister.allResumeAcknowledge && attempts <= maxAttempts; ++attempts) { + std::this_thread::sleep_for(std::chrono::microseconds(10)); + statusRegister = this->readStatusRegister(); + } + + controlRegister.resumeRequest = false; + this->writeControlRegister(controlRegister); + + if (!statusRegister.allResumeAcknowledge) { + throw Exceptions::Exception("Target took too long to acknowledge resume request"); + } + } + + void RiscV::stop() { + auto controlRegister = ControlRegister(); + controlRegister.debugModuleActive = true; + controlRegister.haltRequest = true; + + this->writeControlRegister(controlRegister); + + constexpr auto maxAttempts = 10; + auto statusRegister = this->readStatusRegister(); + + for (auto attempts = 1; !statusRegister.allHalted && attempts <= maxAttempts; ++attempts) { + std::this_thread::sleep_for(std::chrono::microseconds(10)); + statusRegister = this->readStatusRegister(); + } + + controlRegister.haltRequest = false; + this->writeControlRegister(controlRegister); + + if (!statusRegister.allHalted) { + throw Exceptions::Exception("Target took too long to halt selected harts"); + } + } + + void RiscV::step() { + + } + + void RiscV::reset() { + + } + + void RiscV::setSoftwareBreakpoint(TargetMemoryAddress address) { + + } + + void RiscV::removeSoftwareBreakpoint(TargetMemoryAddress address) { + + } + + void RiscV::setHardwareBreakpoint(TargetMemoryAddress address) { + + } + + void RiscV::removeHardwareBreakpoint(TargetMemoryAddress address) { + + } + + void RiscV::clearAllBreakpoints() { + + } + + void RiscV::writeRegisters(TargetRegisters registers) { + + } + + TargetRegisters RiscV::readRegisters(const Targets::TargetRegisterDescriptorIds& descriptorIds) { + return {}; + } + + TargetMemoryBuffer RiscV::readMemory( + TargetMemoryType memoryType, + TargetMemoryAddress startAddress, + TargetMemorySize bytes, + const std::set& excludedAddressRanges + ) { + return {}; + } + + void RiscV::writeMemory( + TargetMemoryType memoryType, + TargetMemoryAddress startAddress, + const TargetMemoryBuffer& buffer + ) { + + } + + void RiscV::eraseMemory(TargetMemoryType memoryType) { + + } + + TargetState RiscV::getState() { + return TargetState::STOPPED; + } + + TargetMemoryAddress RiscV::getProgramCounter() { + return 0; + } + + void RiscV::setProgramCounter(TargetMemoryAddress programCounter) { + + } + + TargetStackPointer RiscV::getStackPointer() { + return 0; + } + + std::map RiscV::getPinStates(int variantId) { + return {}; + } + + void RiscV::setPinState( + const TargetPinDescriptor& pinDescriptor, + const TargetPinState& state + ) { + + } + + void RiscV::enableProgrammingMode() { + + } + + void RiscV::disableProgrammingMode() { + + } + + bool RiscV::programmingModeEnabled() { + return false; + } + + ControlRegister RiscV::readControlRegister() { + return ControlRegister( + this->riscVDebugInterface->readDebugModuleRegister(RegisterAddresses::CONTROL_REGISTER) + ); + } + + StatusRegister RiscV::readStatusRegister() { + return StatusRegister(this->riscVDebugInterface->readDebugModuleRegister(RegisterAddresses::STATUS_REGISTER)); + } + + void RiscV::writeControlRegister(const ControlRegister& controlRegister) { + this->riscVDebugInterface->writeDebugModuleRegister( + RegisterAddresses::CONTROL_REGISTER, + controlRegister.value() + ); + } +} diff --git a/src/Targets/RiscV/RiscV.hpp b/src/Targets/RiscV/RiscV.hpp new file mode 100644 index 00000000..c9a4390b --- /dev/null +++ b/src/Targets/RiscV/RiscV.hpp @@ -0,0 +1,99 @@ +#pragma once + +#include + +#include "src/Targets/Target.hpp" +#include "src/DebugToolDrivers/DebugTool.hpp" + +#include "src/DebugToolDrivers/TargetInterfaces/RiscV/RiscVDebugInterface.hpp" + +#include "src/Targets/RiscV/DebugModule/DebugModule.hpp" +#include "src/Targets/RiscV/DebugModule/Registers/ControlRegister.hpp" +#include "src/Targets/RiscV/DebugModule/Registers/StatusRegister.hpp" + +namespace Targets::RiscV +{ + class RiscV: public Target + { + public: + explicit RiscV(const TargetConfig& targetConfig); + + /* + * The functions below implement the Target interface for RISC-V targets. + * + * See the Targets::Target abstract class for documentation on the expected behaviour of + * each function. + */ + + /** + * All RISC-V compatible debug tools must provide a valid RiscVDebugInterface. + * + * @param debugTool + * @return + */ + bool supportsDebugTool(DebugTool* debugTool) override; + + void setDebugTool(DebugTool* debugTool) override; + + void activate() override; + void deactivate() override; + + TargetDescriptor getDescriptor() override; + + void run(std::optional toAddress = std::nullopt) override; + void stop() override; + void step() override; + void reset() override; + + void setSoftwareBreakpoint(TargetMemoryAddress address) override; + void removeSoftwareBreakpoint(TargetMemoryAddress address) override; + + void setHardwareBreakpoint(TargetMemoryAddress address) override; + void removeHardwareBreakpoint(TargetMemoryAddress address) override; + void clearAllBreakpoints() override; + + void writeRegisters(TargetRegisters registers) override; + TargetRegisters readRegisters(const Targets::TargetRegisterDescriptorIds& descriptorIds) override; + + TargetMemoryBuffer readMemory( + TargetMemoryType memoryType, + TargetMemoryAddress startAddress, + TargetMemorySize bytes, + const std::set& excludedAddressRanges = {} + ) override; + void writeMemory( + TargetMemoryType memoryType, + TargetMemoryAddress startAddress, + const TargetMemoryBuffer& buffer + ) override; + void eraseMemory(TargetMemoryType memoryType) override; + + TargetState getState() override; + + TargetMemoryAddress getProgramCounter() override; + void setProgramCounter(TargetMemoryAddress programCounter) override; + + TargetStackPointer getStackPointer() override; + + std::map getPinStates(int variantId) override; + void setPinState( + const TargetPinDescriptor& pinDescriptor, + const TargetPinState& state + ) override; + + void enableProgrammingMode() override; + + void disableProgrammingMode() override; + + bool programmingModeEnabled() override; + + protected: + DebugToolDrivers::TargetInterfaces::RiscV::RiscVDebugInterface* riscVDebugInterface = nullptr; + std::string name; + + DebugModule::Registers::ControlRegister readControlRegister(); + DebugModule::Registers::StatusRegister readStatusRegister(); + + void writeControlRegister(const DebugModule::Registers::ControlRegister& controlRegister); + }; +} diff --git a/src/Targets/Targets.hpp b/src/Targets/Targets.hpp index 5b92021a..100c84b3 100644 --- a/src/Targets/Targets.hpp +++ b/src/Targets/Targets.hpp @@ -2,3 +2,4 @@ #include "src/Targets/Target.hpp" #include "src/Targets/Microchip/AVR/AVR8/Avr8.hpp" +#include "src/Targets/RiscV/RiscV.hpp"