summaryrefslogtreecommitdiffstats
path: root/src/core/arm/interpreter/arm_interpreter.cpp
blob: 6f6a5913cb0fa56f209232dd55550c6f2c4d4647 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
// Copyright 2014 Citra Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.  

#include "core/arm/interpreter/arm_interpreter.h"

const static cpu_config_t arm11_cpu_info = {
    "armv6", "arm11", 0x0007b000, 0x0007f000, NONCACHE
};

ARM_Interpreter::ARM_Interpreter()  {
    state = new ARMul_State;

    ARMul_EmulateInit();
    memset(state, 0, sizeof(ARMul_State));

    ARMul_NewState(state);

    state->abort_model = 0;
    state->cpu = (cpu_config_t*)&arm11_cpu_info;
    state->bigendSig = LOW;

    ARMul_SelectProcessor(state, ARM_v6_Prop | ARM_v5_Prop | ARM_v5e_Prop);
    state->lateabtSig = LOW;
    mmu_init(state);

    // Reset the core to initial state
    ARMul_CoProInit(state); 
    ARMul_Reset(state);
    state->NextInstr = RESUME; // NOTE: This will be overwritten by LoadContext
    state->Emulate = 3;

    state->pc = state->Reg[15] = 0x00000000;
    state->Reg[13] = 0x10000000; // Set stack pointer to the top of the stack
    state->servaddr = 0xFFFF0000;
}

ARM_Interpreter::~ARM_Interpreter() {
    delete state;
}

/**
 * Set the Program Counter to an address
 * @param addr Address to set PC to
 */
void ARM_Interpreter::SetPC(u32 pc) {
    state->pc = state->Reg[15] = pc;
}

/*
 * Get the current Program Counter
 * @return Returns current PC
 */
u32 ARM_Interpreter::GetPC() const {
    return state->pc;
}

/**
 * Get an ARM register
 * @param index Register index (0-15)
 * @return Returns the value in the register
 */
u32 ARM_Interpreter::GetReg(int index) const {
    return state->Reg[index];
}

/**
 * Set an ARM register
 * @param index Register index (0-15)
 * @param value Value to set register to
 */
void ARM_Interpreter::SetReg(int index, u32 value) {
    state->Reg[index] = value;
}

/**
 * Get the current CPSR register
 * @return Returns the value of the CPSR register
 */
u32 ARM_Interpreter::GetCPSR() const {
    return state->Cpsr;
}

/**
 * Set the current CPSR register
 * @param cpsr Value to set CPSR to
 */
void ARM_Interpreter::SetCPSR(u32 cpsr) {
    state->Cpsr = cpsr;
}

/**
 * Returns the number of clock ticks since the last reset
 * @return Returns number of clock ticks
 */
u64 ARM_Interpreter::GetTicks() const {
    return ARMul_Time(state);
}

/**
 * Executes the given number of instructions
 * @param num_instructions Number of instructions to executes
 */
void ARM_Interpreter::ExecuteInstructions(int num_instructions) {
    state->NumInstrsToExecute = num_instructions - 1;
    ARMul_Emulate32(state);
}

/**
 * Saves the current CPU context
 * @param ctx Thread context to save
 * @todo Do we need to save Reg[15] and NextInstr?
 */
void ARM_Interpreter::SaveContext(ThreadContext& ctx) {
    memcpy(ctx.cpu_registers, state->Reg, sizeof(ctx.cpu_registers));
    memcpy(ctx.fpu_registers, state->ExtReg, sizeof(ctx.fpu_registers));

    ctx.sp = state->Reg[13];
    ctx.lr = state->Reg[14];
    ctx.pc = state->pc;
    ctx.cpsr = state->Cpsr;

    ctx.fpscr = state->VFP[1];
    ctx.fpexc = state->VFP[2];

    ctx.reg_15 = state->Reg[15];
    ctx.mode = state->NextInstr;
}

/**
 * Loads a CPU context
 * @param ctx Thread context to load
 * @param Do we need to load Reg[15] and NextInstr?
 */
void ARM_Interpreter::LoadContext(const ThreadContext& ctx) {
    memcpy(state->Reg, ctx.cpu_registers, sizeof(ctx.cpu_registers));
    memcpy(state->ExtReg, ctx.fpu_registers, sizeof(ctx.fpu_registers));

    state->Reg[13] = ctx.sp;
    state->Reg[14] = ctx.lr;
    state->pc = ctx.pc;
    state->Cpsr = ctx.cpsr;

    state->VFP[1] = ctx.fpscr;
    state->VFP[2] = ctx.fpexc;

    state->Reg[15] = ctx.reg_15;
    state->NextInstr = ctx.mode;
}

/// Prepare core for thread reschedule (if needed to correctly handle state)
void ARM_Interpreter::PrepareReschedule() {
    state->NumInstrsToExecute = 0;
}