summaryrefslogtreecommitdiff
path: root/plugins/ao/eng_dsf/arm7.c
blob: b4314948e95763f2bc6fb3f44f29759819a8898f (plain)
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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
//
// ARM7 processor emulator
// version 1.6 / 2008-02-16
// (c) Radoslaw Balcewicz
//

#include "arm7.h"
#include "arm7i.h"

#ifdef ARM7_THUMB
#include "arm7thumb.h"
#endif

  //--------------------------------------------------------------------------
  // definitions and macros

  /** Macro for accessing banked registers. */
#define RX_BANK(t,r) (cpu->Rx_bank [t][r - 8])
  //--------------------------------------------------------------------------

  //--------------------------------------------------------------------------
  // private functions

  /** CPU Reset. */
static void Reset (struct sARM7 *cpu);
  //--------------------------------------------------------------------------

  // private variables

  /** Table for decoding bit-coded mode to zero based index. */
static const int s_tabTryb [32] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 -1, -1, -1, -1, -1, -1, ARM7_MODE_usr, ARM7_MODE_fiq, ARM7_MODE_irq,
 ARM7_MODE_svc, -1, -1, -1, ARM7_MODE_abt, -1, -1, -1, ARM7_MODE_und,
 -1, -1, -1, ARM7_MODE_sys};
  //--------------------------------------------------------------------------


  // public functions

struct sARM7* ARM7_Alloc ()
{
    struct sARM7 *cpu = malloc (sizeof (struct sARM7));
    memset (cpu, 0, sizeof (struct sARM7));
    return cpu;
}

void ARM7_Free (struct sARM7 *cpu) {
    free (cpu);
}

  //--------------------------------------------------------------------------
  /** ARM7 emulator init. */
void ARM7_Init (struct sARM7 *cpu)
  {
  // sane startup values
  cpu->fiq = 0;
  cpu->irq = 0;
  cpu->carry = 0;
  cpu->overflow = 0;
  cpu->flagi = FALSE;
  cpu->cykle = 0;

  // reset will do the rest
  ARM7_HardReset (cpu);
  }
  //--------------------------------------------------------------------------

  //--------------------------------------------------------------------------
  /** Power-ON reset. */
void ARM7_HardReset (struct sARM7 *cpu)
  {
  // CPSR that makes sense
  cpu->Rx [ARM7_CPSR] = ARM7_CPSR_I | ARM7_CPSR_F | ARM7_CPSR_M_svc;
  Reset (cpu);
  }
  //--------------------------------------------------------------------------

  //--------------------------------------------------------------------------
  /** Hardware reset via /RESET line. */
void ARM7_SoftReset (struct sARM7 *cpu)
  {
  Reset (cpu);
  }
  //--------------------------------------------------------------------------

  //--------------------------------------------------------------------------
  /** CPSR update, possibly changing operating mode. */
void ARM7_SetCPSR (struct sARM7 *cpu, ARM7_REG sr)
  {
  int stary, nowy;

  stary = s_tabTryb [ARM7_CPSR_M (cpu->Rx [ARM7_CPSR])];
  nowy = s_tabTryb [ARM7_CPSR_M (sr)];
  // do we have to change modes?
  if (nowy != stary)
    {
    // save this mode registers
    RX_BANK (stary, ARM7_SP) = cpu->Rx [ARM7_SP],
    RX_BANK (stary, ARM7_LR) = cpu->Rx [ARM7_LR],
    RX_BANK (stary, ARM7_SPSR) = cpu->Rx [ARM7_SPSR];
    if (stary == ARM7_MODE_fiq)
      {
      // copy R8-R12
      RX_BANK (ARM7_MODE_fiq, 8) = cpu->Rx [8],
      RX_BANK (ARM7_MODE_fiq, 9) = cpu->Rx [9],
      RX_BANK (ARM7_MODE_fiq, 10) = cpu->Rx [10],
      RX_BANK (ARM7_MODE_fiq, 11) = cpu->Rx [11],
      RX_BANK (ARM7_MODE_fiq, 12) = cpu->Rx [12];
      cpu->Rx [8] = RX_BANK (ARM7_MODE_usr, 8),
      cpu->Rx [9] = RX_BANK (ARM7_MODE_usr, 9),
      cpu->Rx [10] = RX_BANK (ARM7_MODE_usr, 10),
      cpu->Rx [11] = RX_BANK (ARM7_MODE_usr, 11),
      cpu->Rx [12] = RX_BANK (ARM7_MODE_usr, 12);
      }

    // fetch new mode registers
    cpu->Rx [ARM7_SP] = RX_BANK (nowy, ARM7_SP),
    cpu->Rx [ARM7_LR] = RX_BANK (nowy, ARM7_LR),
    cpu->Rx [ARM7_SPSR] = RX_BANK (nowy, ARM7_SPSR);
    if (nowy == ARM7_MODE_fiq)
      {
      // copy R8-R12
      RX_BANK (ARM7_MODE_usr, 8) = cpu->Rx [8],
      RX_BANK (ARM7_MODE_usr, 9) = cpu->Rx [9],
      RX_BANK (ARM7_MODE_usr, 10) = cpu->Rx [10],
      RX_BANK (ARM7_MODE_usr, 11) = cpu->Rx [11],
      RX_BANK (ARM7_MODE_usr, 12) = cpu->Rx [12];
      cpu->Rx [8] = RX_BANK (ARM7_MODE_fiq, 8),
      cpu->Rx [9] = RX_BANK (ARM7_MODE_fiq, 9),
      cpu->Rx [10] = RX_BANK (ARM7_MODE_fiq, 10),
      cpu->Rx [11] = RX_BANK (ARM7_MODE_fiq, 11),
      cpu->Rx [12] = RX_BANK (ARM7_MODE_fiq, 12);
      }
    }

  // new CPSR value
  cpu->Rx [ARM7_CPSR] = sr;

  // mode change could've enabled interrups, so we test for those and set
  // appropriate flag for the instruction loop to catch
  if (cpu->fiq)
    cpu->flagi |= ARM7_FL_FIQ;
#ifndef ARM7_DREAMCAST
  if (cpu->irq)
    cpu->flagi |= ARM7_FL_IRQ;
#endif
  }
  //--------------------------------------------------------------------------

  //--------------------------------------------------------------------------
  /** Sets FIQ line state. */
void ARM7_SetFIQ (struct sARM7 *cpu, int stan)
  {
  stan = stan ? TRUE : FALSE;
  // we catch changes only
  if (stan ^ cpu->fiq)
    {
    cpu->fiq = stan;
    if (cpu->fiq)
      cpu->flagi |= ARM7_FL_FIQ;
    }
  }
  //--------------------------------------------------------------------------

  //--------------------------------------------------------------------------
  /** Sets IRQ line state. */
void ARM7_SetIRQ (struct sARM7 *cpu, int stan)
  {
  stan = stan ? TRUE : FALSE;
  // we catch changes only
  if (stan ^ cpu->irq)
    {
    cpu->irq = stan;
    if (cpu->irq)
      cpu->flagi |= ARM7_FL_IRQ;
    }
  }
  //--------------------------------------------------------------------------

  //--------------------------------------------------------------------------
  /** Tests for pending interrupts, switches to one if possible. */
void ARM7_CheckIRQ (struct sARM7 *cpu)
  {
  UINT32 sr = cpu->Rx [ARM7_CPSR];

  // clear all interrupt flags
  cpu->flagi &= ~(ARM7_FL_FIQ | ARM7_FL_IRQ);
  
  // check for pending interrupts we can switch to
  // (FIQ can interrupt IRQ, but not the other way around)
  if (cpu->fiq)
    {
    if (!(sr & ARM7_CPSR_F))
      {
      // FIQ
      ARM7_SetCPSR (cpu, ARM7_CPSR_MX (sr, ARM7_CPSR_M_fiq) | ARM7_CPSR_F | ARM7_CPSR_I);
      cpu->Rx [ARM7_SPSR] = sr;
      // set new PC (return from interrupt will subtract 4)
      cpu->Rx [ARM7_LR] = cpu->Rx [ARM7_PC] + 4;
      cpu->Rx [ARM7_PC] = 0x0000001c;
      }
    }
#ifndef ARM7_DREAMCAST
  if (cpu->irq)
    {
    if (!(sr & ARM7_CPSR_I))
      {
      // IRQ
      ARM7_SetCPSR (cpu, ARM7_CPSR_MX (sr, ARM7_CPSR_M_irq) | ARM7_CPSR_I);
      cpu->Rx [ARM7_SPSR] = sr;
      // set new PC (return from interrupt will subtract 4)
      cpu->Rx [ARM7_LR] = cpu->Rx [ARM7_PC] + 4;
      cpu->Rx [ARM7_PC] = 0x00000018;
      cpu->irq = 0;
      }
    }
#endif
  }
  //--------------------------------------------------------------------------

  //--------------------------------------------------------------------------
  /** Single step. */
void ARM7_Step (struct sARM7 *cpu)
{
  // make a step
#ifdef ARM7_THUMB
  if (cpu->Rx[ARM7_CPSR] & ARM7_CPSR_T)
  {
	ARM7i_Thumb_Step(cpu);
  }
  else
#endif
  {
        ARM7i_Step (cpu);
  }
  // and test interrupts
  ARM7_CheckIRQ (cpu);
}
  //--------------------------------------------------------------------------

  //--------------------------------------------------------------------------
  /** Runs emulation for at least n cycles, returns actual amount of cycles
 burned - normal interpreter. */
int ARM7_Execute (struct sARM7 *cpu, int n)
  {
  cpu->cykle = 0;
  while (cpu->cykle < n)
    {
    ARM7_CheckIRQ (cpu);
    while (!cpu->flagi && cpu->cykle < n)
      // make one step, sum up cycles
      cpu->cykle += ARM7i_Step (cpu);
    }
  return cpu->cykle;
  }
  //--------------------------------------------------------------------------


  // private functions


  //--------------------------------------------------------------------------
  /** CPU Reset. */
void Reset (struct sARM7 *cpu)
  {
  // clear ALU flags
  cpu->carry = 0;
  cpu->overflow = 0;
  // test CPSR mode and pick a valid one if necessary
  if (s_tabTryb [ARM7_CPSR_M (cpu->Rx [ARM7_CPSR])] < 0)
    cpu->Rx [ARM7_CPSR] = ARM7_CPSR_I | ARM7_CPSR_F | ARM7_CPSR_M_svc;
  // set up registers according to manual
  RX_BANK (ARM7_MODE_svc, ARM7_LR) = cpu->Rx [ARM7_PC];
  RX_BANK (ARM7_MODE_svc, ARM7_SPSR) = cpu->Rx [ARM7_CPSR];
  ARM7_SetCPSR (cpu, ARM7_CPSR_I | ARM7_CPSR_F | ARM7_CPSR_M_svc);
  cpu->Rx [ARM7_PC] = 0x00000000;
  }
  //--------------------------------------------------------------------------