libmicroemu 0.2.0
ARM Microcontroller Emulator Library
Loading...
Searching...
No Matches
emulator.h
1#pragma once
2
3#include "libmicroemu/internal/bus/bus.h"
4#include "libmicroemu/internal/bus/endianess_converters.h"
5#include "libmicroemu/internal/bus/mem/mem_map_rw.h"
6#include "libmicroemu/internal/bus/mem/mem_ro.h"
7#include "libmicroemu/internal/bus/mem/mem_rw.h"
8#include "libmicroemu/internal/bus/mem/mem_rw_optional.h"
9#include "libmicroemu/internal/cpu_accessor.h"
10#include "libmicroemu/internal/cpu_ops.h"
11#include "libmicroemu/internal/decoder/decoder.h"
12#include "libmicroemu/internal/delegates.h"
13#include "libmicroemu/internal/executor/executor.h"
14#include "libmicroemu/internal/fetcher/fetcher.h"
15#include "libmicroemu/internal/logic/exceptions_ops.h"
16#include "libmicroemu/internal/logic/if_then_ops.h"
17#include "libmicroemu/internal/logic/pc_ops.h"
18#include "libmicroemu/internal/logic/reg_ops.h"
20#include "libmicroemu/internal/logic/spec_reg_ops.h"
21#include "libmicroemu/internal/peripherals/sys_ctrl_block.h"
22#include "libmicroemu/internal/peripherals/sys_tick.h"
23#include "libmicroemu/internal/processor/processor.h"
24#include "libmicroemu/internal/processor/step_flags.h"
26#include "libmicroemu/internal/semihosting/semihosting.h"
27#include "libmicroemu/logger.h"
28#include "libmicroemu/types.h"
29
30namespace libmicroemu::internal {
31template <typename TCpuStates> class Emulator {
32 // Forward declarations
33 class ExceptionTrigger;
34 class ExceptionReturn;
35
36public:
37 // Aliases for register operations
38 using SpecRegOps = SpecRegOps<TCpuStates, StaticLogger>;
39 using RegOps = RegOps<TCpuStates, SpecRegOps, StaticLogger>;
40
41 using CpuAccessor = CpuAccessor<TCpuStates, RegOps, SpecRegOps>;
42
43 // Aliases for peripherals
44 using SysCtrlBlock = SysCtrlBlock<CpuAccessor, StaticLogger>;
45 using SysTick = SysTick<CpuAccessor, ExceptionTrigger, StaticLogger>;
46
47 // Aliases for bus clients
48 using EndConv = LittleToLittleEndianConverter;
49 using Flash = MemRo<0U, CpuAccessor, EndConv>;
52
53 // clang-format off
54 using Peripherals = MemMapRw<3U, 0xE0000000U, 0xFFFFU,
55 CpuAccessor, ExceptionTrigger, StaticLogger,
56
57 // Peripherals
58 SysCtrlBlock,
59 SysTick
60 >;
61 // clang-format on
62
63 // clang-format off
64 using Bus = Bus<
65 CpuAccessor, ExceptionTrigger, StaticLogger,
66
67 // Bus clients
68 Flash,
69 Ram0,
70 Ram1,
71 Peripherals
72 >;
73 // clang-format on
74
75 // Semihosting modules
76 using Semihosting = Semihosting<CpuAccessor, Bus, StaticLogger>;
77
78 // Aliases for advance processor operations
79 using PcOps = PcOps<CpuAccessor, Bus, ExceptionReturn, StaticLogger>;
81 using ItOps = IfThenOps<CpuAccessor>;
82 using CpuOps = CpuOps<ItOps, PcOps, ExcOps, ExceptionTrigger>;
83
84 // aliases for uC steps
85 using Fetcher = Fetcher<CpuAccessor, Bus>;
86 using Decoder = Decoder<CpuAccessor, ItOps>;
87 using Executor = Executor<CpuAccessor, Bus, CpuOps, StaticLogger>;
88
89 // Processor specific classes
90 using ResetLogic = ResetLogic<CpuAccessor, Bus, CpuOps, StaticLogger>;
91 using Processor = Processor<CpuAccessor, Bus, CpuOps, Fetcher, Decoder, Executor, StaticLogger>;
92
93 Emulator(TCpuStates &cpu_states) : cpu_states_(cpu_states) {}
94
95 void SetFlashSegment(const u8 *seg_ptr, me_size_t seg_size, me_adr_t seg_vadr) {
96 flash_ = seg_ptr;
97 flash_size_ = seg_size;
98 flash_vadr_ = seg_vadr;
99 }
100
101 void SetRam1Segment(u8 *seg_ptr, me_size_t seg_size, me_adr_t seg_vadr) {
102 ram1_ = seg_ptr;
103 ram1_size_ = seg_size;
104 ram1_vadr_ = seg_vadr;
105 }
106
107 void SetRam2Segment(u8 *seg_ptr, me_size_t seg_size, me_adr_t seg_vadr) {
108 ram2_ = seg_ptr;
109 ram2_size_ = seg_size;
110 ram2_vadr_ = seg_vadr;
111 }
112
113 Bus BuildBus() {
114 Flash code_access(const_cast<u8 *>(flash_), flash_size_, flash_vadr_);
115 Ram0 rw_mem_access(ram1_, ram1_size_, ram1_vadr_);
116 Ram1 rw_stack_access(ram2_, ram2_size_, ram2_vadr_);
117 Peripherals peripheral_access;
118
119 Bus bus(code_access, rw_mem_access, rw_stack_access, peripheral_access);
120 return bus;
121 }
122
123 Result<void> Reset() {
124 auto bus = BuildBus();
125 auto &cpua = static_cast<CpuAccessor &>(cpu_states_);
126
127 auto res = ResetLogic::TakeReset(cpua, bus);
128 TRY(void, res);
129 return Ok();
130 }
131
132 void SetEntryPoint(u32 entry_point) {
133 const auto aligned_entry_point = entry_point & (~0x1U);
134
135 LOG_INFO(StaticLogger, "Overwrite entry point to 0x%X", aligned_entry_point);
136 auto &cpua = static_cast<CpuAccessor &>(cpu_states_);
137 PcOps::BranchTo(cpua, aligned_entry_point);
138 }
139
140 ExecResult Exec(i64 instr_limit, FPreExecStepCallback cb_pre_exec,
141 FPostExecStepCallback cb_post_exec) {
142 auto bus = BuildBus();
143 auto &cpua = static_cast<CpuAccessor &>(cpu_states_);
144 auto semihosting = Semihosting(cpua, bus);
145
146 u64 instr_count{0U};
147 bool is_instr_limit = instr_limit > 0;
148 u64 u_instr_limit = static_cast<u64>(instr_limit);
149
150 Delegates delegates(
151 cb_pre_exec, cb_post_exec,
152 [&semihosting](const u32 &imm32) -> Result<BkptFlagsSet> {
153 return semihosting.Call(imm32);
154 },
155 [](const u32 &imm32) -> Result<SvcFlagsSet> {
156 SvcFlagsSet svc_flags{0U};
157
158 if (imm32 == 0x1U) { // A supervisor call to exit the emulator
159 svc_flags |= static_cast<SvcFlagsSet>(SvcFlags::kOmitException);
160 svc_flags |= static_cast<SvcFlagsSet>(SvcFlags::kRequestExit);
161 return Ok<SvcFlagsSet>(svc_flags);
162 }
163
164 return Ok<SvcFlagsSet>(svc_flags);
165 });
166
167 while (true) {
168 const auto step_ret = Processor::Step(cpua, bus, delegates);
169 if (step_ret.IsErr()) {
170 return ExecResult(step_ret.status_code, EXIT_FAILURE);
171 }
172
173 const auto step_flags = step_ret.content;
174 if (step_flags & static_cast<StepFlagsSet>(StepFlags::kStepTerminationRequest)) {
175 return ExecResult(StatusCode::kSuccess, semihosting.GetExitStatusCode());
176 }
177
178 const auto systick_ret = SysTick::Step(cpua);
179 if (systick_ret.IsErr()) {
180 return ExecResult(systick_ret.status_code, EXIT_FAILURE);
181 }
182
183 ++instr_count;
184 if (is_instr_limit && instr_count >= u_instr_limit) {
186 }
187 }
188
189 // Should never reach here
190 return ExecResult(StatusCode::kUnexpected, EXIT_FAILURE);
191 }
192
193private:
194 // -------------------------------------------------
195 class ExceptionTrigger {
196 public:
197 template <typename... Args> static void SetPending(Args &&...args) {
198 ExcOps::SetExceptionPending(std::forward<Args>(args)...);
199 }
200
201 ExceptionTrigger() = delete;
202 ~ExceptionTrigger() = delete;
203 ExceptionTrigger(const ExceptionTrigger &) = delete;
204 ExceptionTrigger(ExceptionTrigger &&) = delete;
205
206 auto &operator=(const ExceptionTrigger &) = delete;
207 auto &operator=(ExceptionTrigger &&) = delete;
208 };
209
210 // -------------------------------------------------
211 class ExceptionReturn {
212 public:
213 template <typename... Args> static Result<void> Return(Args &&...args) {
214 return ExcOps::ExceptionReturn(std::forward<Args>(args)...);
215 }
216
217 ExceptionReturn() = delete;
218 ~ExceptionReturn() = delete;
219 ExceptionReturn(const ExceptionReturn &) = delete;
220 ExceptionReturn(ExceptionReturn &&) = delete;
221
222 auto &operator=(const ExceptionReturn &) = delete;
223 auto &operator=(ExceptionReturn &&) = delete;
224 };
225
226 const u8 *flash_{nullptr};
227 me_size_t flash_size_{0U};
228 me_adr_t flash_vadr_{0U};
229
230 u8 *ram1_{nullptr};
231 me_size_t ram1_size_{0U};
232 me_adr_t ram1_vadr_{0U};
233
234 u8 *ram2_{nullptr};
235 me_size_t ram2_size_{0U};
236 me_adr_t ram2_vadr_{0U};
237
238 TCpuStates &cpu_states_;
239};
240
241} // namespace libmicroemu::internal
Returned by the libmicroemu::Machine::Exec method. Contains the status code of the execution and the ...
Definition exec_result.h:18
Static logger class.
Definition logger.h:25
Definition delegates.h:10
Definition exceptions_ops.h:56
Definition if_then_ops.h:39
This class contains a function to convert the endianess from little to little endian.
Definition endianess_converters.h:102
Definition mem_map_rw.h:133
Definition mem_rw.h:9
Optional assignable memory class.
Definition mem_rw_optional.h:19
static Result< void > TakeReset(TCpuAccessor &cpua, TBus &bus)
Reset the processor.
Definition reset_logic.h:43
The libmicroemu::internal namespace contains all classes and functions of libmicroemu which are priva...
Definition bkpt_flags.h:6
@ kMaxInstructionsReached
Maximum instruction count reached.
Definition status_code.h:100
@ kUnexpected
An unexpected error occurred.
Definition status_code.h:28
@ kSuccess
Operation succeeded successfully.
Definition status_code.h:20
std::function< void(EmuContext &ctx)> FPreExecStepCallback
Callback function to be called before each instruction is executed.
Definition machine.h:35
std::function< void(EmuContext &ctx)> FPostExecStepCallback
Callback function to be called after each instruction is executed.
Definition machine.h:39
Contains the reset logic for the processor.
Contains the Result class which is used to return the result of a function.
#define TRY(OUT_TYPE, CALL)
Try to call a function and return an error if the call fails.
Definition result.h:138
Definition result.h:15