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->cycles = 0;
104 cpu->nextEvent = 0;
105
106 cpu->shifterOperand = 0;
107 cpu->shifterCarryOut = 0;
108
109 cpu->executionMode = MODE_THUMB;
110 _ARMSetMode(cpu, MODE_ARM);
111
112 ARM_WRITE_PC;
113
114 cpu->board->reset(cpu->board);
115}
116
117void ARMRaiseIRQ(struct ARMCore* cpu) {
118 if (cpu->cpsr.i) {
119 return;
120 }
121 union PSR cpsr = cpu->cpsr;
122 int instructionWidth;
123 if (cpu->executionMode == MODE_THUMB) {
124 instructionWidth = WORD_SIZE_THUMB;
125 } else {
126 instructionWidth = WORD_SIZE_ARM;
127 }
128 ARMSetPrivilegeMode(cpu, MODE_IRQ);
129 cpu->cpsr.priv = MODE_IRQ;
130 cpu->gprs[ARM_LR] = cpu->gprs[ARM_PC] - instructionWidth + WORD_SIZE_ARM;
131 cpu->gprs[ARM_PC] = BASE_IRQ + WORD_SIZE_ARM;
132 cpu->memory->setActiveRegion(cpu->memory, cpu->gprs[ARM_PC]);
133 _ARMSetMode(cpu, MODE_ARM);
134 cpu->spsr = cpsr;
135 cpu->cpsr.i = 1;
136}
137
138void ARMRaiseSWI(struct ARMCore* cpu) {
139 union PSR cpsr = cpu->cpsr;
140 int instructionWidth;
141 if (cpu->executionMode == MODE_THUMB) {
142 instructionWidth = WORD_SIZE_THUMB;
143 } else {
144 instructionWidth = WORD_SIZE_ARM;
145 }
146 ARMSetPrivilegeMode(cpu, MODE_SUPERVISOR);
147 cpu->cpsr.priv = MODE_IRQ;
148 cpu->gprs[ARM_LR] = cpu->gprs[ARM_PC] - instructionWidth + WORD_SIZE_ARM;
149 cpu->gprs[ARM_PC] = BASE_SWI + WORD_SIZE_ARM;
150 cpu->memory->setActiveRegion(cpu->memory, cpu->gprs[ARM_PC]);
151 _ARMSetMode(cpu, MODE_ARM);
152 cpu->spsr = cpsr;
153 cpu->cpsr.i = 1;
154}
155
156void ARMRun(struct ARMCore* cpu) {
157 if (cpu->executionMode == MODE_THUMB) {
158 ThumbStep(cpu);
159 } else {
160 ARMStep(cpu);
161 }
162 if (cpu->cycles >= cpu->nextEvent) {
163 cpu->board->processEvents(cpu->board);
164 }
165}