src/arm/arm.c (view raw)
1#include "arm.h"
2
3#include "isa-arm.h"
4#include "isa-inlines.h"
5#include "isa-thumb.h"
6
7#include <limits.h>
8
9static inline enum RegisterBank _ARMSelectBank(enum PrivilegeMode);
10
11void ARMSetPrivilegeMode(struct ARMCore* cpu, enum PrivilegeMode mode) {
12 if (mode == cpu->privilegeMode) {
13 // Not switching modes after all
14 return;
15 }
16
17 enum RegisterBank newBank = _ARMSelectBank(mode);
18 enum RegisterBank oldBank = _ARMSelectBank(cpu->privilegeMode);
19 if (newBank != oldBank) {
20 // Switch banked registers
21 if (mode == MODE_FIQ || cpu->privilegeMode == MODE_FIQ) {
22 int oldFIQBank = oldBank == BANK_FIQ;
23 int newFIQBank = newBank == BANK_FIQ;
24 cpu->bankedRegisters[oldFIQBank][2] = cpu->gprs[8];
25 cpu->bankedRegisters[oldFIQBank][3] = cpu->gprs[9];
26 cpu->bankedRegisters[oldFIQBank][4] = cpu->gprs[10];
27 cpu->bankedRegisters[oldFIQBank][5] = cpu->gprs[11];
28 cpu->bankedRegisters[oldFIQBank][6] = cpu->gprs[12];
29 cpu->gprs[8] = cpu->bankedRegisters[newFIQBank][2];
30 cpu->gprs[9] = cpu->bankedRegisters[newFIQBank][3];
31 cpu->gprs[10] = cpu->bankedRegisters[newFIQBank][4];
32 cpu->gprs[11] = cpu->bankedRegisters[newFIQBank][5];
33 cpu->gprs[12] = cpu->bankedRegisters[newFIQBank][6];
34 }
35 cpu->bankedRegisters[oldBank][0] = cpu->gprs[ARM_SP];
36 cpu->bankedRegisters[oldBank][1] = cpu->gprs[ARM_LR];
37 cpu->gprs[ARM_SP] = cpu->bankedRegisters[newBank][0];
38 cpu->gprs[ARM_LR] = cpu->bankedRegisters[newBank][1];
39
40 cpu->bankedSPSRs[oldBank] = cpu->spsr.packed;
41 cpu->spsr.packed = cpu->bankedSPSRs[newBank];
42
43 }
44 cpu->privilegeMode = mode;
45}
46
47static inline enum RegisterBank _ARMSelectBank(enum PrivilegeMode mode) {
48 switch (mode) {
49 case MODE_USER:
50 case MODE_SYSTEM:
51 // No banked registers
52 return BANK_NONE;
53 case MODE_FIQ:
54 return BANK_FIQ;
55 case MODE_IRQ:
56 return BANK_IRQ;
57 case MODE_SUPERVISOR:
58 return BANK_SUPERVISOR;
59 case MODE_ABORT:
60 return BANK_ABORT;
61 case MODE_UNDEFINED:
62 return BANK_UNDEFINED;
63 default:
64 // This should be unreached
65 return BANK_NONE;
66 }
67}
68
69void ARMInit(struct ARMCore* cpu) {
70 cpu->memory = 0;
71 cpu->board = 0;
72}
73
74void ARMAssociateMemory(struct ARMCore* cpu, struct ARMMemory* memory) {
75 cpu->memory = memory;
76}
77
78void ARMAssociateBoard(struct ARMCore* cpu, struct ARMBoard* board) {
79 cpu->board = board;
80 board->cpu = cpu;
81}
82
83void ARMReset(struct ARMCore* cpu) {
84 int i;
85 for (i = 0; i < 16; ++i) {
86 cpu->gprs[i] = 0;
87 }
88 for (i = 0; i < 6; ++i) {
89 cpu->bankedRegisters[i][0] = 0;
90 cpu->bankedRegisters[i][1] = 0;
91 cpu->bankedRegisters[i][2] = 0;
92 cpu->bankedRegisters[i][3] = 0;
93 cpu->bankedRegisters[i][4] = 0;
94 cpu->bankedRegisters[i][5] = 0;
95 cpu->bankedRegisters[i][6] = 0;
96 cpu->bankedSPSRs[i] = 0;
97 }
98
99 cpu->privilegeMode = MODE_SYSTEM;
100 cpu->cpsr.packed = MODE_SYSTEM;
101 cpu->spsr.packed = 0;
102
103 cpu->shifterOperand = 0;
104 cpu->shifterCarryOut = 0;
105
106 cpu->executionMode = MODE_THUMB;
107 _ARMSetMode(cpu, MODE_ARM);
108
109 cpu->currentPC = 0;
110 int currentCycles = 0;
111 ARM_WRITE_PC;
112
113 cpu->cycles = 0;
114 cpu->nextEvent = 0;
115
116 cpu->board->reset(cpu->board);
117}
118
119void ARMRaiseIRQ(struct ARMCore* cpu) {
120 if (cpu->cpsr.i) {
121 return;
122 }
123 union PSR cpsr = cpu->cpsr;
124 int instructionWidth;
125 if (cpu->executionMode == MODE_THUMB) {
126 instructionWidth = WORD_SIZE_THUMB;
127 } else {
128 instructionWidth = WORD_SIZE_ARM;
129 }
130 ARMSetPrivilegeMode(cpu, MODE_IRQ);
131 cpu->cpsr.priv = MODE_IRQ;
132 cpu->gprs[ARM_LR] = cpu->gprs[ARM_PC] - instructionWidth + WORD_SIZE_ARM;
133 cpu->gprs[ARM_PC] = BASE_IRQ + WORD_SIZE_ARM;
134 cpu->memory->setActiveRegion(cpu->memory, cpu->gprs[ARM_PC]);
135 _ARMSetMode(cpu, MODE_ARM);
136 cpu->spsr = cpsr;
137 cpu->cpsr.i = 1;
138}
139
140void ARMRaiseSWI(struct ARMCore* cpu) {
141 union PSR cpsr = cpu->cpsr;
142 int instructionWidth;
143 if (cpu->executionMode == MODE_THUMB) {
144 instructionWidth = WORD_SIZE_THUMB;
145 } else {
146 instructionWidth = WORD_SIZE_ARM;
147 }
148 ARMSetPrivilegeMode(cpu, MODE_SUPERVISOR);
149 cpu->cpsr.priv = MODE_SUPERVISOR;
150 cpu->gprs[ARM_LR] = cpu->gprs[ARM_PC] - instructionWidth;
151 cpu->gprs[ARM_PC] = BASE_SWI + WORD_SIZE_ARM;
152 cpu->memory->setActiveRegion(cpu->memory, cpu->gprs[ARM_PC]);
153 _ARMSetMode(cpu, MODE_ARM);
154 cpu->spsr = cpsr;
155 cpu->cpsr.i = 1;
156}
157
158void ARMRun(struct ARMCore* cpu) {
159 if (cpu->executionMode == MODE_THUMB) {
160 ThumbStep(cpu);
161 } else {
162 ARMStep(cpu);
163 }
164 if (cpu->cycles >= cpu->nextEvent) {
165 cpu->board->processEvents(cpu->board);
166 }
167}