rp2040js 0.17.17 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (182) hide show
  1. package/dist/cjs/clock/clock.d.ts +11 -11
  2. package/dist/cjs/clock/clock.js +2 -2
  3. package/dist/cjs/clock/mock-clock.d.ts +17 -17
  4. package/dist/cjs/clock/mock-clock.js +52 -52
  5. package/dist/cjs/clock/realtime-clock.d.ts +23 -23
  6. package/dist/cjs/clock/realtime-clock.js +73 -73
  7. package/dist/cjs/cortex-m0-core.d.ts +87 -87
  8. package/dist/cjs/cortex-m0-core.js +1251 -1251
  9. package/dist/cjs/gdb/gdb-connection.d.ts +11 -11
  10. package/dist/cjs/gdb/gdb-connection.js +57 -57
  11. package/dist/cjs/gdb/gdb-server.d.ts +23 -23
  12. package/dist/cjs/gdb/gdb-server.js +232 -232
  13. package/dist/cjs/gdb/gdb-tcp-server.d.ts +10 -10
  14. package/dist/cjs/gdb/gdb-tcp-server.js +34 -34
  15. package/dist/cjs/gdb/gdb-utils.d.ts +9 -9
  16. package/dist/cjs/gdb/gdb-utils.js +48 -48
  17. package/dist/cjs/gpio-pin.d.ts +56 -56
  18. package/dist/cjs/gpio-pin.js +216 -216
  19. package/dist/cjs/index.d.ts +11 -11
  20. package/dist/cjs/index.js +36 -36
  21. package/dist/cjs/interpolator.d.ts +36 -36
  22. package/dist/cjs/interpolator.js +150 -150
  23. package/dist/cjs/irq.d.ts +29 -29
  24. package/dist/cjs/irq.js +33 -33
  25. package/dist/cjs/peripherals/adc.d.ts +52 -52
  26. package/dist/cjs/peripherals/adc.js +261 -261
  27. package/dist/cjs/peripherals/busctrl.d.ts +10 -10
  28. package/dist/cjs/peripherals/busctrl.js +84 -84
  29. package/dist/cjs/peripherals/clocks.d.ts +9 -9
  30. package/dist/cjs/peripherals/clocks.js +42 -42
  31. package/dist/cjs/peripherals/dma.d.ts +109 -109
  32. package/dist/cjs/peripherals/dma.js +520 -520
  33. package/dist/cjs/peripherals/i2c.d.ts +54 -54
  34. package/dist/cjs/peripherals/i2c.js +458 -458
  35. package/dist/cjs/peripherals/io.d.ts +11 -11
  36. package/dist/cjs/peripherals/io.js +100 -100
  37. package/dist/cjs/peripherals/pads.d.ts +13 -13
  38. package/dist/cjs/peripherals/pads.js +58 -58
  39. package/dist/cjs/peripherals/peripheral.d.ts +22 -22
  40. package/dist/cjs/peripherals/peripheral.js +61 -61
  41. package/dist/cjs/peripherals/pio.d.ts +120 -120
  42. package/dist/cjs/peripherals/pio.js +1086 -1086
  43. package/dist/cjs/peripherals/ppb.d.ts +25 -25
  44. package/dist/cjs/peripherals/ppb.js +229 -229
  45. package/dist/cjs/peripherals/pwm.d.ts +65 -65
  46. package/dist/cjs/peripherals/pwm.js +372 -372
  47. package/dist/cjs/peripherals/reset.d.ts +8 -8
  48. package/dist/cjs/peripherals/reset.js +40 -40
  49. package/dist/cjs/peripherals/rtc.d.ts +10 -10
  50. package/dist/cjs/peripherals/rtc.js +74 -74
  51. package/dist/cjs/peripherals/spi.d.ts +38 -38
  52. package/dist/cjs/peripherals/spi.js +240 -240
  53. package/dist/cjs/peripherals/ssi.d.ts +6 -6
  54. package/dist/cjs/peripherals/ssi.js +43 -43
  55. package/dist/cjs/peripherals/syscfg.d.ts +5 -5
  56. package/dist/cjs/peripherals/syscfg.js +26 -26
  57. package/dist/cjs/peripherals/sysinfo.d.ts +4 -4
  58. package/dist/cjs/peripherals/sysinfo.js +22 -22
  59. package/dist/cjs/peripherals/tbman.d.ts +4 -4
  60. package/dist/cjs/peripherals/tbman.js +17 -17
  61. package/dist/cjs/peripherals/timer.d.ts +18 -18
  62. package/dist/cjs/peripherals/timer.js +156 -156
  63. package/dist/cjs/peripherals/uart.d.ts +31 -31
  64. package/dist/cjs/peripherals/uart.js +132 -132
  65. package/dist/cjs/peripherals/usb.d.ts +29 -29
  66. package/dist/cjs/peripherals/usb.js +309 -309
  67. package/dist/cjs/rp2040.d.ts +71 -71
  68. package/dist/cjs/rp2040.js +361 -361
  69. package/dist/cjs/sio.d.ts +21 -21
  70. package/dist/cjs/sio.js +425 -425
  71. package/dist/cjs/usb/cdc.d.ts +20 -20
  72. package/dist/cjs/usb/cdc.js +126 -126
  73. package/dist/cjs/usb/interfaces.d.ts +47 -47
  74. package/dist/cjs/usb/interfaces.js +46 -46
  75. package/dist/cjs/usb/setup.d.ts +5 -5
  76. package/dist/cjs/usb/setup.js +53 -53
  77. package/dist/cjs/utils/assembler.d.ts +79 -79
  78. package/dist/cjs/utils/assembler.js +328 -328
  79. package/dist/cjs/utils/bit.d.ts +3 -3
  80. package/dist/cjs/utils/bit.js +15 -15
  81. package/dist/cjs/utils/fifo.d.ts +15 -15
  82. package/dist/cjs/utils/fifo.js +56 -56
  83. package/dist/cjs/utils/logging.d.ts +23 -23
  84. package/dist/cjs/utils/logging.js +48 -48
  85. package/dist/cjs/utils/pio-assembler.d.ts +45 -45
  86. package/dist/cjs/utils/pio-assembler.js +87 -87
  87. package/dist/cjs/utils/time.d.ts +2 -2
  88. package/dist/cjs/utils/time.js +32 -32
  89. package/dist/cjs/utils/timer32.d.ts +57 -57
  90. package/dist/cjs/utils/timer32.js +208 -208
  91. package/dist/esm/clock/clock.d.ts +11 -11
  92. package/dist/esm/clock/clock.js +1 -1
  93. package/dist/esm/clock/mock-clock.d.ts +17 -17
  94. package/dist/esm/clock/mock-clock.js +47 -47
  95. package/dist/esm/clock/realtime-clock.d.ts +23 -23
  96. package/dist/esm/clock/realtime-clock.js +68 -68
  97. package/dist/esm/cortex-m0-core.d.ts +87 -87
  98. package/dist/esm/cortex-m0-core.js +1247 -1247
  99. package/dist/esm/gdb/gdb-connection.d.ts +11 -11
  100. package/dist/esm/gdb/gdb-connection.js +53 -53
  101. package/dist/esm/gdb/gdb-server.d.ts +23 -23
  102. package/dist/esm/gdb/gdb-server.js +228 -228
  103. package/dist/esm/gdb/gdb-tcp-server.d.ts +10 -10
  104. package/dist/esm/gdb/gdb-tcp-server.js +30 -30
  105. package/dist/esm/gdb/gdb-utils.d.ts +9 -9
  106. package/dist/esm/gdb/gdb-utils.js +36 -36
  107. package/dist/esm/gpio-pin.d.ts +56 -56
  108. package/dist/esm/gpio-pin.js +212 -212
  109. package/dist/esm/index.d.ts +11 -11
  110. package/dist/esm/index.js +11 -11
  111. package/dist/esm/interpolator.d.ts +36 -36
  112. package/dist/esm/interpolator.js +145 -145
  113. package/dist/esm/irq.d.ts +29 -29
  114. package/dist/esm/irq.js +30 -30
  115. package/dist/esm/peripherals/adc.d.ts +52 -52
  116. package/dist/esm/peripherals/adc.js +257 -257
  117. package/dist/esm/peripherals/busctrl.d.ts +10 -10
  118. package/dist/esm/peripherals/busctrl.js +80 -80
  119. package/dist/esm/peripherals/clocks.d.ts +9 -9
  120. package/dist/esm/peripherals/clocks.js +38 -38
  121. package/dist/esm/peripherals/dma.d.ts +109 -109
  122. package/dist/esm/peripherals/dma.js +515 -515
  123. package/dist/esm/peripherals/i2c.d.ts +54 -54
  124. package/dist/esm/peripherals/i2c.js +454 -454
  125. package/dist/esm/peripherals/io.d.ts +11 -11
  126. package/dist/esm/peripherals/io.js +96 -96
  127. package/dist/esm/peripherals/pads.d.ts +13 -13
  128. package/dist/esm/peripherals/pads.js +54 -54
  129. package/dist/esm/peripherals/peripheral.d.ts +22 -22
  130. package/dist/esm/peripherals/peripheral.js +55 -55
  131. package/dist/esm/peripherals/pio.d.ts +120 -120
  132. package/dist/esm/peripherals/pio.js +1081 -1081
  133. package/dist/esm/peripherals/ppb.d.ts +25 -25
  134. package/dist/esm/peripherals/ppb.js +225 -225
  135. package/dist/esm/peripherals/pwm.d.ts +65 -65
  136. package/dist/esm/peripherals/pwm.js +368 -368
  137. package/dist/esm/peripherals/reset.d.ts +8 -8
  138. package/dist/esm/peripherals/reset.js +36 -36
  139. package/dist/esm/peripherals/rtc.d.ts +10 -10
  140. package/dist/esm/peripherals/rtc.js +70 -70
  141. package/dist/esm/peripherals/spi.d.ts +38 -38
  142. package/dist/esm/peripherals/spi.js +236 -236
  143. package/dist/esm/peripherals/ssi.d.ts +6 -6
  144. package/dist/esm/peripherals/ssi.js +39 -39
  145. package/dist/esm/peripherals/syscfg.d.ts +5 -5
  146. package/dist/esm/peripherals/syscfg.js +22 -22
  147. package/dist/esm/peripherals/sysinfo.d.ts +4 -4
  148. package/dist/esm/peripherals/sysinfo.js +18 -18
  149. package/dist/esm/peripherals/tbman.d.ts +4 -4
  150. package/dist/esm/peripherals/tbman.js +13 -13
  151. package/dist/esm/peripherals/timer.d.ts +18 -18
  152. package/dist/esm/peripherals/timer.js +152 -152
  153. package/dist/esm/peripherals/uart.d.ts +31 -31
  154. package/dist/esm/peripherals/uart.js +128 -128
  155. package/dist/esm/peripherals/usb.d.ts +29 -29
  156. package/dist/esm/peripherals/usb.js +305 -305
  157. package/dist/esm/rp2040.d.ts +71 -71
  158. package/dist/esm/rp2040.js +357 -357
  159. package/dist/esm/sio.d.ts +21 -21
  160. package/dist/esm/sio.js +421 -421
  161. package/dist/esm/usb/cdc.d.ts +20 -20
  162. package/dist/esm/usb/cdc.js +121 -121
  163. package/dist/esm/usb/interfaces.d.ts +47 -47
  164. package/dist/esm/usb/interfaces.js +43 -43
  165. package/dist/esm/usb/setup.d.ts +5 -5
  166. package/dist/esm/usb/setup.js +46 -46
  167. package/dist/esm/utils/assembler.d.ts +79 -79
  168. package/dist/esm/utils/assembler.js +245 -245
  169. package/dist/esm/utils/bit.d.ts +3 -3
  170. package/dist/esm/utils/bit.js +9 -9
  171. package/dist/esm/utils/fifo.d.ts +15 -15
  172. package/dist/esm/utils/fifo.js +52 -52
  173. package/dist/esm/utils/logging.d.ts +23 -23
  174. package/dist/esm/utils/logging.js +44 -44
  175. package/dist/esm/utils/pio-assembler.d.ts +45 -45
  176. package/dist/esm/utils/pio-assembler.js +75 -75
  177. package/dist/esm/utils/time.d.ts +2 -2
  178. package/dist/esm/utils/time.js +27 -27
  179. package/dist/esm/utils/timer32.d.ts +57 -57
  180. package/dist/esm/utils/timer32.js +203 -203
  181. package/package.json +33 -22
  182. package/dist/esm/package.json +0 -1
@@ -1,1247 +1,1247 @@
1
- import { MAX_HARDWARE_IRQ } from './irq';
2
- import { APB_START_ADDRESS, SIO_START_ADDRESS } from './rp2040';
3
- /* eslint-disable @typescript-eslint/no-unused-vars */
4
- const EXC_RESET = 1;
5
- const EXC_NMI = 2;
6
- const EXC_HARDFAULT = 3;
7
- const EXC_SVCALL = 11;
8
- const EXC_PENDSV = 14;
9
- const EXC_SYSTICK = 15;
10
- const SYSM_APSR = 0;
11
- const SYSM_IAPSR = 1;
12
- const SYSM_EAPSR = 2;
13
- const SYSM_XPSR = 3;
14
- const SYSM_IPSR = 5;
15
- const SYSM_EPSR = 6;
16
- const SYSM_IEPSR = 7;
17
- export const SYSM_MSP = 8;
18
- export const SYSM_PSP = 9;
19
- export const SYSM_PRIMASK = 16;
20
- export const SYSM_CONTROL = 20;
21
- /* eslint-enable @typescript-eslint/no-unused-vars */
22
- // Lowest possible exception priority
23
- const LOWEST_PRIORITY = 4;
24
- var ExecutionMode;
25
- (function (ExecutionMode) {
26
- ExecutionMode[ExecutionMode["Mode_Thread"] = 0] = "Mode_Thread";
27
- ExecutionMode[ExecutionMode["Mode_Handler"] = 1] = "Mode_Handler";
28
- })(ExecutionMode || (ExecutionMode = {}));
29
- function signExtend8(value) {
30
- return (value << 24) >> 24;
31
- }
32
- function signExtend16(value) {
33
- return (value << 16) >> 16;
34
- }
35
- const spRegister = 13;
36
- const pcRegister = 15;
37
- var StackPointerBank;
38
- (function (StackPointerBank) {
39
- StackPointerBank[StackPointerBank["SPmain"] = 0] = "SPmain";
40
- StackPointerBank[StackPointerBank["SPprocess"] = 1] = "SPprocess";
41
- })(StackPointerBank || (StackPointerBank = {}));
42
- const LOG_NAME = 'CortexM0Core';
43
- export class CortexM0Core {
44
- constructor(rp2040) {
45
- this.rp2040 = rp2040;
46
- this.registers = new Uint32Array(16);
47
- this.bankedSP = 0;
48
- this.cycles = 0;
49
- this.eventRegistered = false;
50
- this.waiting = false;
51
- // APSR fields
52
- this.N = false;
53
- this.C = false;
54
- this.Z = false;
55
- this.V = false;
56
- // How many bytes to rewind the last break instruction
57
- this.breakRewind = 0;
58
- // PRIMASK fields
59
- this.PM = false;
60
- // CONTROL fields
61
- this.SPSEL = StackPointerBank.SPmain;
62
- this.nPRIV = false;
63
- this.currentMode = ExecutionMode.Mode_Thread;
64
- this.IPSR = 0;
65
- this.interruptNMIMask = 0;
66
- this.pendingInterrupts = 0;
67
- this.enabledInterrupts = 0;
68
- this.interruptPriorities = [0xffffffff, 0x0, 0x0, 0x0];
69
- this.pendingNMI = false;
70
- this.pendingPendSV = false;
71
- this.pendingSVCall = false;
72
- this.pendingSystick = false;
73
- this.interruptsUpdated = false;
74
- this.VTOR = 0;
75
- this.SHPR2 = 0;
76
- this.SHPR3 = 0;
77
- /** Hook to listen for function calls - branch-link (BL/BLX) instructions */
78
- this.blTaken = (core, blx) => {
79
- void core; // surpress unused variable warnings
80
- void blx;
81
- };
82
- this.SP = 0xfffffffc;
83
- this.bankedSP = 0xfffffffc;
84
- }
85
- get logger() {
86
- return this.rp2040.logger;
87
- }
88
- reset() {
89
- this.SP = this.rp2040.readUint32(this.VTOR);
90
- this.PC = this.rp2040.readUint32(this.VTOR + 4) & 0xfffffffe;
91
- this.cycles = 0;
92
- }
93
- get SP() {
94
- return this.registers[13];
95
- }
96
- set SP(value) {
97
- this.registers[13] = value & ~0x3;
98
- }
99
- get LR() {
100
- return this.registers[14];
101
- }
102
- set LR(value) {
103
- this.registers[14] = value;
104
- }
105
- get PC() {
106
- return this.registers[15];
107
- }
108
- set PC(value) {
109
- this.registers[15] = value;
110
- }
111
- get APSR() {
112
- return ((this.N ? 0x80000000 : 0) |
113
- (this.Z ? 0x40000000 : 0) |
114
- (this.C ? 0x20000000 : 0) |
115
- (this.V ? 0x10000000 : 0));
116
- }
117
- set APSR(value) {
118
- this.N = !!(value & 0x80000000);
119
- this.Z = !!(value & 0x40000000);
120
- this.C = !!(value & 0x20000000);
121
- this.V = !!(value & 0x10000000);
122
- }
123
- get xPSR() {
124
- return this.APSR | this.IPSR | (1 << 24);
125
- }
126
- set xPSR(value) {
127
- this.APSR = value;
128
- this.IPSR = value & 0x3f;
129
- }
130
- checkCondition(cond) {
131
- // Evaluate base condition.
132
- let result = false;
133
- switch (cond >> 1) {
134
- case 0b000:
135
- result = this.Z;
136
- break;
137
- case 0b001:
138
- result = this.C;
139
- break;
140
- case 0b010:
141
- result = this.N;
142
- break;
143
- case 0b011:
144
- result = this.V;
145
- break;
146
- case 0b100:
147
- result = this.C && !this.Z;
148
- break;
149
- case 0b101:
150
- result = this.N === this.V;
151
- break;
152
- case 0b110:
153
- result = this.N === this.V && !this.Z;
154
- break;
155
- case 0b111:
156
- result = true;
157
- break;
158
- }
159
- return cond & 0b1 && cond != 0b1111 ? !result : result;
160
- }
161
- readUint32(address) {
162
- return this.rp2040.readUint32(address);
163
- }
164
- readUint16(address) {
165
- return this.rp2040.readUint16(address);
166
- }
167
- readUint8(address) {
168
- return this.rp2040.readUint8(address);
169
- }
170
- writeUint32(address, value) {
171
- this.rp2040.writeUint32(address, value);
172
- }
173
- writeUint16(address, value) {
174
- this.rp2040.writeUint16(address, value);
175
- }
176
- writeUint8(address, value) {
177
- this.rp2040.writeUint8(address, value);
178
- }
179
- switchStack(stack) {
180
- if (this.SPSEL !== stack) {
181
- const temp = this.SP;
182
- this.SP = this.bankedSP;
183
- this.bankedSP = temp;
184
- this.SPSEL = stack;
185
- }
186
- }
187
- get SPprocess() {
188
- return this.SPSEL === StackPointerBank.SPprocess ? this.SP : this.bankedSP;
189
- }
190
- set SPprocess(value) {
191
- if (this.SPSEL === StackPointerBank.SPprocess) {
192
- this.SP = value;
193
- }
194
- else {
195
- this.bankedSP = value >>> 0;
196
- }
197
- }
198
- get SPmain() {
199
- return this.SPSEL === StackPointerBank.SPmain ? this.SP : this.bankedSP;
200
- }
201
- set SPmain(value) {
202
- if (this.SPSEL === StackPointerBank.SPmain) {
203
- this.SP = value;
204
- }
205
- else {
206
- this.bankedSP = value >>> 0;
207
- }
208
- }
209
- exceptionEntry(exceptionNumber) {
210
- // PushStack:
211
- let framePtr = 0;
212
- let framePtrAlign = 0;
213
- if (this.SPSEL && this.currentMode === ExecutionMode.Mode_Thread) {
214
- framePtrAlign = this.SPprocess & 0b100 ? 1 : 0;
215
- this.SPprocess = (this.SPprocess - 0x20) & ~0b100;
216
- framePtr = this.SPprocess;
217
- }
218
- else {
219
- framePtrAlign = this.SPmain & 0b100 ? 1 : 0;
220
- this.SPmain = (this.SPmain - 0x20) & ~0b100;
221
- framePtr = this.SPmain;
222
- }
223
- /* only the stack locations, not the store order, are architected */
224
- this.writeUint32(framePtr, this.registers[0]);
225
- this.writeUint32(framePtr + 0x4, this.registers[1]);
226
- this.writeUint32(framePtr + 0x8, this.registers[2]);
227
- this.writeUint32(framePtr + 0xc, this.registers[3]);
228
- this.writeUint32(framePtr + 0x10, this.registers[12]);
229
- this.writeUint32(framePtr + 0x14, this.LR);
230
- this.writeUint32(framePtr + 0x18, this.PC & ~1); // ReturnAddress(ExceptionType);
231
- this.writeUint32(framePtr + 0x1c, (this.xPSR & ~(1 << 9)) | (framePtrAlign << 9));
232
- if (this.currentMode == ExecutionMode.Mode_Handler) {
233
- this.LR = 0xfffffff1;
234
- }
235
- else {
236
- if (!this.SPSEL) {
237
- this.LR = 0xfffffff9;
238
- }
239
- else {
240
- this.LR = 0xfffffffd;
241
- }
242
- }
243
- // ExceptionTaken:
244
- this.currentMode = ExecutionMode.Mode_Handler; // Enter Handler Mode, now Privileged
245
- this.IPSR = exceptionNumber;
246
- this.switchStack(StackPointerBank.SPmain);
247
- this.eventRegistered = true;
248
- const vectorTable = this.VTOR;
249
- this.PC = this.readUint32(vectorTable + 4 * exceptionNumber);
250
- }
251
- exceptionReturn(excReturn) {
252
- let framePtr = this.SPmain;
253
- switch (excReturn & 0xf) {
254
- case 0b0001: // Return to Handler
255
- this.currentMode = ExecutionMode.Mode_Handler;
256
- this.switchStack(StackPointerBank.SPmain);
257
- break;
258
- case 0b1001: // Return to Thread using Main stack
259
- this.currentMode = ExecutionMode.Mode_Thread;
260
- this.switchStack(StackPointerBank.SPmain);
261
- break;
262
- case 0b1101: // Return to Thread using Process stack
263
- framePtr = this.SPprocess;
264
- this.currentMode = ExecutionMode.Mode_Thread;
265
- this.switchStack(StackPointerBank.SPprocess);
266
- break;
267
- // Assigning CurrentMode to Mode_Thread causes a drop in privilege
268
- // if CONTROL.nPRIV is set to 1
269
- }
270
- // PopStack:
271
- this.registers[0] = this.readUint32(framePtr); // Stack accesses are performed as Unprivileged accesses if
272
- this.registers[1] = this.readUint32(framePtr + 0x4); // CONTROL<0>=='1' && EXC_RETURN<3>=='1' Privileged otherwise
273
- this.registers[2] = this.readUint32(framePtr + 0x8);
274
- this.registers[3] = this.readUint32(framePtr + 0xc);
275
- this.registers[12] = this.readUint32(framePtr + 0x10);
276
- this.LR = this.readUint32(framePtr + 0x14);
277
- this.PC = this.readUint32(framePtr + 0x18);
278
- const psr = this.readUint32(framePtr + 0x1c);
279
- const framePtrAlign = psr & (1 << 9) ? 0b100 : 0;
280
- switch (excReturn & 0xf) {
281
- case 0b0001: // Returning to Handler mode
282
- this.SPmain = (this.SPmain + 0x20) | framePtrAlign;
283
- break;
284
- case 0b1001: // Returning to Thread mode using Main stack
285
- this.SPmain = (this.SPmain + 0x20) | framePtrAlign;
286
- break;
287
- case 0b1101: // Returning to Thread mode using Process stack
288
- this.SPprocess = (this.SPprocess + 0x20) | framePtrAlign;
289
- break;
290
- }
291
- this.APSR = psr & 0xf0000000;
292
- const forceThread = this.currentMode == ExecutionMode.Mode_Thread && this.nPRIV;
293
- this.IPSR = forceThread ? 0 : psr & 0x3f;
294
- this.interruptsUpdated = true;
295
- // Thumb bit should always be one! EPSR<24> = psr<24>; // Load valid EPSR bits from memory
296
- this.eventRegistered = true;
297
- // if CurrentMode == Mode_Thread && SCR.SLEEPONEXIT == '1' then
298
- // SleepOnExit(); // IMPLEMENTATION DEFINED
299
- }
300
- get pendSVPriority() {
301
- return (this.SHPR3 >> 22) & 0x3;
302
- }
303
- get svCallPriority() {
304
- return this.SHPR2 >>> 30;
305
- }
306
- get systickPriority() {
307
- return this.SHPR3 >>> 30;
308
- }
309
- exceptionPriority(n) {
310
- switch (n) {
311
- case EXC_RESET:
312
- return -3;
313
- case EXC_NMI:
314
- return -2;
315
- case EXC_HARDFAULT:
316
- return -1;
317
- case EXC_SVCALL:
318
- return this.svCallPriority;
319
- case EXC_PENDSV:
320
- return this.pendSVPriority;
321
- case EXC_SYSTICK:
322
- return this.systickPriority;
323
- default: {
324
- if (n < 16) {
325
- return LOWEST_PRIORITY;
326
- }
327
- const intNum = n - 16;
328
- for (let priority = 0; priority < 4; priority++) {
329
- if (this.interruptPriorities[priority] & (1 << intNum)) {
330
- return priority;
331
- }
332
- }
333
- return LOWEST_PRIORITY;
334
- }
335
- }
336
- }
337
- get vectPending() {
338
- if (this.pendingNMI) {
339
- return EXC_NMI;
340
- }
341
- const { svCallPriority, systickPriority, pendSVPriority, pendingInterrupts } = this;
342
- for (let priority = 0; priority < LOWEST_PRIORITY; priority++) {
343
- const levelInterrupts = pendingInterrupts & this.interruptPriorities[priority];
344
- if (this.pendingSVCall && priority === svCallPriority) {
345
- return EXC_SVCALL;
346
- }
347
- if (this.pendingPendSV && priority === pendSVPriority) {
348
- return EXC_PENDSV;
349
- }
350
- if (this.pendingSystick && priority === systickPriority) {
351
- return EXC_SYSTICK;
352
- }
353
- if (levelInterrupts) {
354
- for (let interruptNumber = 0; interruptNumber < 32; interruptNumber++) {
355
- if (levelInterrupts & (1 << interruptNumber)) {
356
- return 16 + interruptNumber;
357
- }
358
- }
359
- }
360
- }
361
- return 0;
362
- }
363
- setInterrupt(irq, value) {
364
- const irqBit = 1 << irq;
365
- if (value && !(this.pendingInterrupts & irqBit)) {
366
- this.pendingInterrupts |= irqBit;
367
- this.interruptsUpdated = true;
368
- if (this.waiting && this.checkForInterrupts()) {
369
- this.waiting = false;
370
- }
371
- }
372
- else if (!value) {
373
- this.pendingInterrupts &= ~irqBit;
374
- }
375
- }
376
- checkForInterrupts() {
377
- /* If we're waiting for an interrupt (i.e. WFI/WFE), the ARM says:
378
- > If PRIMASK.PM is set to 1, an asynchronous exception that has a higher group priority than any
379
- > active exception results in a WFI instruction exit. If the group priority of the exception is less than or
380
- > equal to the execution group priority, the exception is ignored.
381
- */
382
- const currentPriority = this.waiting
383
- ? this.PM
384
- ? this.exceptionPriority(this.IPSR)
385
- : LOWEST_PRIORITY
386
- : Math.min(this.exceptionPriority(this.IPSR), this.PM ? 0 : LOWEST_PRIORITY);
387
- const interruptSet = this.pendingInterrupts & this.enabledInterrupts;
388
- const { svCallPriority, systickPriority, pendSVPriority } = this;
389
- if (this.pendingNMI) {
390
- this.pendingNMI = false;
391
- this.exceptionEntry(EXC_NMI);
392
- return true;
393
- }
394
- for (let priority = 0; priority < currentPriority; priority++) {
395
- const levelInterrupts = interruptSet & this.interruptPriorities[priority];
396
- if (this.pendingSVCall && priority === svCallPriority) {
397
- this.pendingSVCall = false;
398
- this.exceptionEntry(EXC_SVCALL);
399
- return true;
400
- }
401
- if (this.pendingPendSV && priority === pendSVPriority) {
402
- this.pendingPendSV = false;
403
- this.exceptionEntry(EXC_PENDSV);
404
- return true;
405
- }
406
- if (this.pendingSystick && priority === systickPriority) {
407
- this.pendingSystick = false;
408
- this.exceptionEntry(EXC_SYSTICK);
409
- return true;
410
- }
411
- if (levelInterrupts) {
412
- for (let interruptNumber = 0; interruptNumber < 32; interruptNumber++) {
413
- if (levelInterrupts & (1 << interruptNumber)) {
414
- if (interruptNumber > MAX_HARDWARE_IRQ) {
415
- this.pendingInterrupts &= ~(1 << interruptNumber);
416
- }
417
- this.exceptionEntry(16 + interruptNumber);
418
- return true;
419
- }
420
- }
421
- }
422
- }
423
- this.interruptsUpdated = false;
424
- return false;
425
- }
426
- readSpecialRegister(sysm) {
427
- switch (sysm) {
428
- case SYSM_APSR:
429
- return this.APSR;
430
- case SYSM_XPSR:
431
- return this.xPSR;
432
- case SYSM_IPSR:
433
- return this.IPSR;
434
- case SYSM_PRIMASK:
435
- return this.PM ? 1 : 0;
436
- case SYSM_MSP:
437
- return this.SPmain;
438
- case SYSM_PSP:
439
- return this.SPprocess;
440
- case SYSM_CONTROL:
441
- return (this.SPSEL === StackPointerBank.SPprocess ? 2 : 0) | (this.nPRIV ? 1 : 0);
442
- default:
443
- this.logger.warn(LOG_NAME, `MRS with unimplemented SYSm value: ${sysm}`);
444
- return 0;
445
- }
446
- }
447
- writeSpecialRegister(sysm, value) {
448
- switch (sysm) {
449
- case SYSM_APSR:
450
- this.APSR = value;
451
- break;
452
- case SYSM_XPSR:
453
- this.xPSR = value;
454
- break;
455
- case SYSM_IPSR:
456
- this.IPSR = value;
457
- break;
458
- case SYSM_PRIMASK:
459
- this.PM = !!(value & 1);
460
- this.interruptsUpdated = true;
461
- break;
462
- case SYSM_MSP:
463
- this.SPmain = value;
464
- break;
465
- case SYSM_PSP:
466
- this.SPprocess = value;
467
- break;
468
- case SYSM_CONTROL:
469
- this.nPRIV = !!(value & 1);
470
- if (this.currentMode === ExecutionMode.Mode_Thread) {
471
- this.switchStack(value & 2 ? StackPointerBank.SPprocess : StackPointerBank.SPmain);
472
- }
473
- break;
474
- default:
475
- this.logger.warn(LOG_NAME, `MRS with unimplemented SYSm value: ${sysm}`);
476
- return 0;
477
- }
478
- }
479
- BXWritePC(address) {
480
- if (this.currentMode == ExecutionMode.Mode_Handler && address >>> 28 == 0b1111) {
481
- this.exceptionReturn(address & 0x0fffffff);
482
- }
483
- else {
484
- this.PC = address & ~1;
485
- }
486
- }
487
- substractUpdateFlags(minuend, subtrahend) {
488
- const result = minuend - subtrahend;
489
- this.N = !!(result & 0x80000000);
490
- this.Z = (result & 0xffffffff) === 0;
491
- this.C = minuend >= subtrahend;
492
- this.V =
493
- (!!(result & 0x80000000) && !(minuend & 0x80000000) && !!(subtrahend & 0x80000000)) ||
494
- (!(result & 0x80000000) && !!(minuend & 0x80000000) && !(subtrahend & 0x80000000));
495
- return result;
496
- }
497
- addUpdateFlags(addend1, addend2) {
498
- const unsignedSum = (addend1 + addend2) >>> 0;
499
- const signedSum = (addend1 | 0) + (addend2 | 0);
500
- const result = addend1 + addend2;
501
- this.N = !!(result & 0x80000000);
502
- this.Z = (result & 0xffffffff) === 0;
503
- this.C = result === unsignedSum ? false : true;
504
- this.V = (result | 0) === signedSum ? false : true;
505
- return result & 0xffffffff;
506
- }
507
- cyclesIO(addr, write = false) {
508
- addr = addr >>> 0;
509
- if (addr >= SIO_START_ADDRESS && addr < SIO_START_ADDRESS + 0x10000000) {
510
- return 0;
511
- }
512
- if (addr >= APB_START_ADDRESS && addr < APB_START_ADDRESS + 0x10000000) {
513
- return write ? 4 : 3;
514
- }
515
- return 1;
516
- }
517
- executeInstruction() {
518
- if (this.interruptsUpdated) {
519
- if (this.checkForInterrupts()) {
520
- this.waiting = false;
521
- }
522
- }
523
- // ARM Thumb instruction encoding - 16 bits / 2 bytes
524
- const opcodePC = this.PC & ~1; //ensure no LSB set PC are executed
525
- const opcode = this.readUint16(opcodePC);
526
- const wideInstruction = opcode >> 12 === 0b1111 || opcode >> 11 === 0b11101;
527
- const opcode2 = wideInstruction ? this.readUint16(opcodePC + 2) : 0;
528
- this.PC += 2;
529
- this.cycles++;
530
- // ADCS
531
- if (opcode >> 6 === 0b0100000101) {
532
- const Rm = (opcode >> 3) & 0x7;
533
- const Rdn = opcode & 0x7;
534
- this.registers[Rdn] = this.addUpdateFlags(this.registers[Rm], this.registers[Rdn] + (this.C ? 1 : 0));
535
- }
536
- // ADD (register = SP plus immediate)
537
- else if (opcode >> 11 === 0b10101) {
538
- const imm8 = opcode & 0xff;
539
- const Rd = (opcode >> 8) & 0x7;
540
- this.registers[Rd] = this.SP + (imm8 << 2);
541
- }
542
- // ADD (SP plus immediate)
543
- else if (opcode >> 7 === 0b101100000) {
544
- const imm32 = (opcode & 0x7f) << 2;
545
- this.SP += imm32;
546
- }
547
- // ADDS (Encoding T1)
548
- else if (opcode >> 9 === 0b0001110) {
549
- const imm3 = (opcode >> 6) & 0x7;
550
- const Rn = (opcode >> 3) & 0x7;
551
- const Rd = opcode & 0x7;
552
- this.registers[Rd] = this.addUpdateFlags(this.registers[Rn], imm3);
553
- }
554
- // ADDS (Encoding T2)
555
- else if (opcode >> 11 === 0b00110) {
556
- const imm8 = opcode & 0xff;
557
- const Rdn = (opcode >> 8) & 0x7;
558
- this.registers[Rdn] = this.addUpdateFlags(this.registers[Rdn], imm8);
559
- }
560
- // ADDS (register)
561
- else if (opcode >> 9 === 0b0001100) {
562
- const Rm = (opcode >> 6) & 0x7;
563
- const Rn = (opcode >> 3) & 0x7;
564
- const Rd = opcode & 0x7;
565
- this.registers[Rd] = this.addUpdateFlags(this.registers[Rn], this.registers[Rm]);
566
- }
567
- // ADD (register)
568
- else if (opcode >> 8 === 0b01000100) {
569
- const Rm = (opcode >> 3) & 0xf;
570
- const Rdn = ((opcode & 0x80) >> 4) | (opcode & 0x7);
571
- const leftValue = Rdn === pcRegister ? this.PC + 2 : this.registers[Rdn];
572
- const rightValue = this.registers[Rm];
573
- const result = leftValue + rightValue;
574
- if (Rdn !== spRegister && Rdn !== pcRegister) {
575
- this.registers[Rdn] = result;
576
- }
577
- else if (Rdn === pcRegister) {
578
- this.registers[Rdn] = result & ~0x1;
579
- this.cycles++;
580
- }
581
- else if (Rdn === spRegister) {
582
- this.registers[Rdn] = result & ~0x3;
583
- }
584
- }
585
- // ADR
586
- else if (opcode >> 11 === 0b10100) {
587
- const imm8 = opcode & 0xff;
588
- const Rd = (opcode >> 8) & 0x7;
589
- this.registers[Rd] = (opcodePC & 0xfffffffc) + 4 + (imm8 << 2);
590
- }
591
- // ANDS (Encoding T2)
592
- else if (opcode >> 6 === 0b0100000000) {
593
- const Rm = (opcode >> 3) & 0x7;
594
- const Rdn = opcode & 0x7;
595
- const result = this.registers[Rdn] & this.registers[Rm];
596
- this.registers[Rdn] = result;
597
- this.N = !!(result & 0x80000000);
598
- this.Z = (result & 0xffffffff) === 0;
599
- }
600
- // ASRS (immediate)
601
- else if (opcode >> 11 === 0b00010) {
602
- const imm5 = (opcode >> 6) & 0x1f;
603
- const Rm = (opcode >> 3) & 0x7;
604
- const Rd = opcode & 0x7;
605
- const input = this.registers[Rm];
606
- const shiftN = imm5 ? imm5 : 32;
607
- const result = shiftN < 32 ? input >> shiftN : (input & 0x80000000) >> 31;
608
- this.registers[Rd] = result;
609
- this.N = !!(result & 0x80000000);
610
- this.Z = (result & 0xffffffff) === 0;
611
- this.C = input & (1 << (shiftN - 1)) ? true : false;
612
- }
613
- // ASRS (register)
614
- else if (opcode >> 6 === 0b0100000100) {
615
- const Rm = (opcode >> 3) & 0x7;
616
- const Rdn = opcode & 0x7;
617
- const input = this.registers[Rdn];
618
- const shiftN = (this.registers[Rm] & 0xff) < 32 ? this.registers[Rm] & 0xff : 32;
619
- const result = shiftN < 32 ? input >> shiftN : (input & 0x80000000) >> 31;
620
- this.registers[Rdn] = result;
621
- this.N = !!(result & 0x80000000);
622
- this.Z = (result & 0xffffffff) === 0;
623
- this.C = input & (1 << (shiftN - 1)) ? true : false;
624
- }
625
- // B (with cond)
626
- else if (opcode >> 12 === 0b1101 && ((opcode >> 9) & 0x7) !== 0b111) {
627
- let imm8 = (opcode & 0xff) << 1;
628
- const cond = (opcode >> 8) & 0xf;
629
- if (imm8 & (1 << 8)) {
630
- imm8 = (imm8 & 0x1ff) - 0x200;
631
- }
632
- if (this.checkCondition(cond)) {
633
- this.PC += imm8 + 2;
634
- this.cycles++;
635
- }
636
- }
637
- // B
638
- else if (opcode >> 11 === 0b11100) {
639
- let imm11 = (opcode & 0x7ff) << 1;
640
- if (imm11 & (1 << 11)) {
641
- imm11 = (imm11 & 0x7ff) - 0x800;
642
- }
643
- this.PC += imm11 + 2;
644
- this.cycles++;
645
- }
646
- // BICS
647
- else if (opcode >> 6 === 0b0100001110) {
648
- const Rm = (opcode >> 3) & 0x7;
649
- const Rdn = opcode & 0x7;
650
- const result = (this.registers[Rdn] &= ~this.registers[Rm]);
651
- this.N = !!(result & 0x80000000);
652
- this.Z = result === 0;
653
- }
654
- // BKPT
655
- else if (opcode >> 8 === 0b10111110) {
656
- const imm8 = opcode & 0xff;
657
- this.breakRewind = 2;
658
- this.rp2040.onBreak(imm8);
659
- }
660
- // BL
661
- else if (opcode >> 11 === 0b11110 && opcode2 >> 14 === 0b11 && ((opcode2 >> 12) & 0x1) == 1) {
662
- const imm11 = opcode2 & 0x7ff;
663
- const J2 = (opcode2 >> 11) & 0x1;
664
- const J1 = (opcode2 >> 13) & 0x1;
665
- const imm10 = opcode & 0x3ff;
666
- const S = (opcode >> 10) & 0x1;
667
- const I1 = 1 - (S ^ J1);
668
- const I2 = 1 - (S ^ J2);
669
- const imm32 = ((S ? 0b11111111 : 0) << 24) | ((I1 << 23) | (I2 << 22) | (imm10 << 12) | (imm11 << 1));
670
- this.LR = (this.PC + 2) | 0x1;
671
- this.PC += 2 + imm32;
672
- this.cycles += 2;
673
- this.blTaken(this, false);
674
- }
675
- // BLX
676
- else if (opcode >> 7 === 0b010001111 && (opcode & 0x7) === 0) {
677
- const Rm = (opcode >> 3) & 0xf;
678
- this.LR = this.PC | 0x1;
679
- this.PC = this.registers[Rm] & ~1;
680
- this.cycles++;
681
- this.blTaken(this, true);
682
- }
683
- // BX
684
- else if (opcode >> 7 === 0b010001110 && (opcode & 0x7) === 0) {
685
- const Rm = (opcode >> 3) & 0xf;
686
- this.BXWritePC(this.registers[Rm]);
687
- this.cycles++;
688
- }
689
- // CMN (register)
690
- else if (opcode >> 6 === 0b0100001011) {
691
- const Rm = (opcode >> 3) & 0x7;
692
- const Rn = opcode & 0x7;
693
- this.addUpdateFlags(this.registers[Rn], this.registers[Rm]);
694
- }
695
- // CMP immediate
696
- else if (opcode >> 11 === 0b00101) {
697
- const Rn = (opcode >> 8) & 0x7;
698
- const imm8 = opcode & 0xff;
699
- this.substractUpdateFlags(this.registers[Rn], imm8);
700
- }
701
- // CMP (register)
702
- else if (opcode >> 6 === 0b0100001010) {
703
- const Rm = (opcode >> 3) & 0x7;
704
- const Rn = opcode & 0x7;
705
- this.substractUpdateFlags(this.registers[Rn], this.registers[Rm]);
706
- }
707
- // CMP (register) encoding T2
708
- else if (opcode >> 8 === 0b01000101) {
709
- const Rm = (opcode >> 3) & 0xf;
710
- const Rn = ((opcode >> 4) & 0x8) | (opcode & 0x7);
711
- this.substractUpdateFlags(this.registers[Rn], this.registers[Rm]);
712
- }
713
- // CPSID i
714
- else if (opcode === 0xb672) {
715
- this.PM = true;
716
- }
717
- // CPSIE i
718
- else if (opcode === 0xb662) {
719
- this.PM = false;
720
- this.interruptsUpdated = true;
721
- }
722
- // DMB SY
723
- else if (opcode === 0xf3bf && (opcode2 & 0xfff0) === 0x8f50) {
724
- this.PC += 2;
725
- this.cycles += 2;
726
- }
727
- // DSB SY
728
- else if (opcode === 0xf3bf && (opcode2 & 0xfff0) === 0x8f40) {
729
- this.PC += 2;
730
- this.cycles += 2;
731
- }
732
- // EORS
733
- else if (opcode >> 6 === 0b0100000001) {
734
- const Rm = (opcode >> 3) & 0x7;
735
- const Rdn = opcode & 0x7;
736
- const result = this.registers[Rm] ^ this.registers[Rdn];
737
- this.registers[Rdn] = result;
738
- this.N = !!(result & 0x80000000);
739
- this.Z = result === 0;
740
- }
741
- // ISB SY
742
- else if (opcode === 0xf3bf && (opcode2 & 0xfff0) === 0x8f60) {
743
- this.PC += 2;
744
- this.cycles += 2;
745
- }
746
- // LDMIA
747
- else if (opcode >> 11 === 0b11001) {
748
- const Rn = (opcode >> 8) & 0x7;
749
- const registers = opcode & 0xff;
750
- let address = this.registers[Rn];
751
- for (let i = 0; i < 8; i++) {
752
- if (registers & (1 << i)) {
753
- this.registers[i] = this.readUint32(address);
754
- address += 4;
755
- this.cycles++;
756
- }
757
- }
758
- // Write back
759
- if (!(registers & (1 << Rn))) {
760
- this.registers[Rn] = address;
761
- }
762
- }
763
- // LDR (immediate)
764
- else if (opcode >> 11 === 0b01101) {
765
- const imm5 = ((opcode >> 6) & 0x1f) << 2;
766
- const Rn = (opcode >> 3) & 0x7;
767
- const Rt = opcode & 0x7;
768
- const addr = this.registers[Rn] + imm5;
769
- this.cycles += this.cyclesIO(addr);
770
- this.registers[Rt] = this.readUint32(addr);
771
- }
772
- // LDR (sp + immediate)
773
- else if (opcode >> 11 === 0b10011) {
774
- const Rt = (opcode >> 8) & 0x7;
775
- const imm8 = opcode & 0xff;
776
- const addr = this.SP + (imm8 << 2);
777
- this.cycles += this.cyclesIO(addr);
778
- this.registers[Rt] = this.readUint32(addr);
779
- }
780
- // LDR (literal)
781
- else if (opcode >> 11 === 0b01001) {
782
- const imm8 = (opcode & 0xff) << 2;
783
- const Rt = (opcode >> 8) & 7;
784
- const nextPC = this.PC + 2;
785
- const addr = (nextPC & 0xfffffffc) + imm8;
786
- this.cycles += this.cyclesIO(addr);
787
- this.registers[Rt] = this.readUint32(addr);
788
- }
789
- // LDR (register)
790
- else if (opcode >> 9 === 0b0101100) {
791
- const Rm = (opcode >> 6) & 0x7;
792
- const Rn = (opcode >> 3) & 0x7;
793
- const Rt = opcode & 0x7;
794
- const addr = this.registers[Rm] + this.registers[Rn];
795
- this.cycles += this.cyclesIO(addr);
796
- this.registers[Rt] = this.readUint32(addr);
797
- }
798
- // LDRB (immediate)
799
- else if (opcode >> 11 === 0b01111) {
800
- const imm5 = (opcode >> 6) & 0x1f;
801
- const Rn = (opcode >> 3) & 0x7;
802
- const Rt = opcode & 0x7;
803
- const addr = this.registers[Rn] + imm5;
804
- this.cycles += this.cyclesIO(addr);
805
- this.registers[Rt] = this.readUint8(addr);
806
- }
807
- // LDRB (register)
808
- else if (opcode >> 9 === 0b0101110) {
809
- const Rm = (opcode >> 6) & 0x7;
810
- const Rn = (opcode >> 3) & 0x7;
811
- const Rt = opcode & 0x7;
812
- const addr = this.registers[Rm] + this.registers[Rn];
813
- this.cycles += this.cyclesIO(addr);
814
- this.registers[Rt] = this.readUint8(addr);
815
- }
816
- // LDRH (immediate)
817
- else if (opcode >> 11 === 0b10001) {
818
- const imm5 = (opcode >> 6) & 0x1f;
819
- const Rn = (opcode >> 3) & 0x7;
820
- const Rt = opcode & 0x7;
821
- const addr = this.registers[Rn] + (imm5 << 1);
822
- this.cycles += this.cyclesIO(addr);
823
- this.registers[Rt] = this.readUint16(addr);
824
- }
825
- // LDRH (register)
826
- else if (opcode >> 9 === 0b0101101) {
827
- const Rm = (opcode >> 6) & 0x7;
828
- const Rn = (opcode >> 3) & 0x7;
829
- const Rt = opcode & 0x7;
830
- const addr = this.registers[Rm] + this.registers[Rn];
831
- this.cycles += this.cyclesIO(addr);
832
- this.registers[Rt] = this.readUint16(addr);
833
- }
834
- // LDRSB
835
- else if (opcode >> 9 === 0b0101011) {
836
- const Rm = (opcode >> 6) & 0x7;
837
- const Rn = (opcode >> 3) & 0x7;
838
- const Rt = opcode & 0x7;
839
- const addr = this.registers[Rm] + this.registers[Rn];
840
- this.cycles += this.cyclesIO(addr);
841
- this.registers[Rt] = signExtend8(this.readUint8(addr));
842
- }
843
- // LDRSH
844
- else if (opcode >> 9 === 0b0101111) {
845
- const Rm = (opcode >> 6) & 0x7;
846
- const Rn = (opcode >> 3) & 0x7;
847
- const Rt = opcode & 0x7;
848
- const addr = this.registers[Rm] + this.registers[Rn];
849
- this.cycles += this.cyclesIO(addr);
850
- this.registers[Rt] = signExtend16(this.readUint16(addr));
851
- }
852
- // LSLS (immediate)
853
- else if (opcode >> 11 === 0b00000) {
854
- const imm5 = (opcode >> 6) & 0x1f;
855
- const Rm = (opcode >> 3) & 0x7;
856
- const Rd = opcode & 0x7;
857
- const input = this.registers[Rm];
858
- const result = input << imm5;
859
- this.registers[Rd] = result;
860
- this.N = !!(result & 0x80000000);
861
- this.Z = result === 0;
862
- this.C = imm5 ? !!(input & (1 << (32 - imm5))) : this.C;
863
- }
864
- // LSLS (register)
865
- else if (opcode >> 6 === 0b0100000010) {
866
- const Rm = (opcode >> 3) & 0x7;
867
- const Rdn = opcode & 0x7;
868
- const input = this.registers[Rdn];
869
- const shiftCount = this.registers[Rm] & 0xff;
870
- const result = shiftCount >= 32 ? 0 : input << shiftCount;
871
- this.registers[Rdn] = result;
872
- this.N = !!(result & 0x80000000);
873
- this.Z = result === 0;
874
- this.C = shiftCount ? !!(input & (1 << (32 - shiftCount))) : this.C;
875
- }
876
- // LSRS (immediate)
877
- else if (opcode >> 11 === 0b00001) {
878
- const imm5 = (opcode >> 6) & 0x1f;
879
- const Rm = (opcode >> 3) & 0x7;
880
- const Rd = opcode & 0x7;
881
- const input = this.registers[Rm];
882
- const result = imm5 ? input >>> imm5 : 0;
883
- this.registers[Rd] = result;
884
- this.N = !!(result & 0x80000000);
885
- this.Z = result === 0;
886
- this.C = !!((input >>> (imm5 ? imm5 - 1 : 31)) & 0x1);
887
- }
888
- // LSRS (register)
889
- else if (opcode >> 6 === 0b0100000011) {
890
- const Rm = (opcode >> 3) & 0x7;
891
- const Rdn = opcode & 0x7;
892
- const shiftAmount = this.registers[Rm] & 0xff;
893
- const input = this.registers[Rdn];
894
- const result = shiftAmount < 32 ? input >>> shiftAmount : 0;
895
- this.registers[Rdn] = result;
896
- this.N = !!(result & 0x80000000);
897
- this.Z = result === 0;
898
- this.C = shiftAmount <= 32 ? !!((input >>> (shiftAmount - 1)) & 0x1) : false;
899
- }
900
- // MOV
901
- else if (opcode >> 8 === 0b01000110) {
902
- const Rm = (opcode >> 3) & 0xf;
903
- const Rd = ((opcode >> 4) & 0x8) | (opcode & 0x7);
904
- let value = Rm === pcRegister ? this.PC + 2 : this.registers[Rm];
905
- if (Rd === pcRegister) {
906
- this.cycles++;
907
- value &= ~1;
908
- }
909
- else if (Rd === spRegister) {
910
- value &= ~3;
911
- }
912
- this.registers[Rd] = value;
913
- }
914
- // MOVS
915
- else if (opcode >> 11 === 0b00100) {
916
- const value = opcode & 0xff;
917
- const Rd = (opcode >> 8) & 7;
918
- this.registers[Rd] = value;
919
- this.N = !!(value & 0x80000000);
920
- this.Z = value === 0;
921
- }
922
- // MRS
923
- else if (opcode === 0b1111001111101111 && opcode2 >> 12 == 0b1000) {
924
- const SYSm = opcode2 & 0xff;
925
- const Rd = (opcode2 >> 8) & 0xf;
926
- this.registers[Rd] = this.readSpecialRegister(SYSm);
927
- this.PC += 2;
928
- this.cycles += 2;
929
- }
930
- // MSR
931
- else if (opcode >> 4 === 0b111100111000 && opcode2 >> 8 == 0b10001000) {
932
- const SYSm = opcode2 & 0xff;
933
- const Rn = opcode & 0xf;
934
- this.writeSpecialRegister(SYSm, this.registers[Rn]);
935
- this.PC += 2;
936
- this.cycles += 2;
937
- }
938
- // MULS
939
- else if (opcode >> 6 === 0b0100001101) {
940
- const Rn = (opcode >> 3) & 0x7;
941
- const Rdm = opcode & 0x7;
942
- const result = Math.imul(this.registers[Rn], this.registers[Rdm]);
943
- this.registers[Rdm] = result;
944
- this.N = !!(result & 0x80000000);
945
- this.Z = (result & 0xffffffff) === 0;
946
- }
947
- // MVNS
948
- else if (opcode >> 6 === 0b0100001111) {
949
- const Rm = (opcode >> 3) & 7;
950
- const Rd = opcode & 7;
951
- const result = ~this.registers[Rm];
952
- this.registers[Rd] = result;
953
- this.N = !!(result & 0x80000000);
954
- this.Z = result === 0;
955
- }
956
- // ORRS (Encoding T2)
957
- else if (opcode >> 6 === 0b0100001100) {
958
- const Rm = (opcode >> 3) & 0x7;
959
- const Rdn = opcode & 0x7;
960
- const result = this.registers[Rdn] | this.registers[Rm];
961
- this.registers[Rdn] = result;
962
- this.N = !!(result & 0x80000000);
963
- this.Z = (result & 0xffffffff) === 0;
964
- }
965
- // POP
966
- else if (opcode >> 9 === 0b1011110) {
967
- const P = (opcode >> 8) & 1;
968
- let address = this.SP;
969
- for (let i = 0; i <= 7; i++) {
970
- if (opcode & (1 << i)) {
971
- this.registers[i] = this.readUint32(address);
972
- address += 4;
973
- this.cycles++;
974
- }
975
- }
976
- if (P) {
977
- this.SP = address + 4;
978
- this.BXWritePC(this.readUint32(address));
979
- this.cycles += 2;
980
- }
981
- else {
982
- this.SP = address;
983
- }
984
- }
985
- // PUSH
986
- else if (opcode >> 9 === 0b1011010) {
987
- let bitCount = 0;
988
- for (let i = 0; i <= 8; i++) {
989
- if (opcode & (1 << i)) {
990
- bitCount++;
991
- }
992
- }
993
- let address = this.SP - 4 * bitCount;
994
- for (let i = 0; i <= 7; i++) {
995
- if (opcode & (1 << i)) {
996
- this.writeUint32(address, this.registers[i]);
997
- this.cycles++;
998
- address += 4;
999
- }
1000
- }
1001
- if (opcode & (1 << 8)) {
1002
- this.writeUint32(address, this.registers[14]);
1003
- }
1004
- this.SP -= 4 * bitCount;
1005
- }
1006
- // REV
1007
- else if (opcode >> 6 === 0b1011101000) {
1008
- const Rm = (opcode >> 3) & 0x7;
1009
- const Rd = opcode & 0x7;
1010
- const input = this.registers[Rm];
1011
- this.registers[Rd] =
1012
- ((input & 0xff) << 24) |
1013
- (((input >> 8) & 0xff) << 16) |
1014
- (((input >> 16) & 0xff) << 8) |
1015
- ((input >> 24) & 0xff);
1016
- }
1017
- // REV16
1018
- else if (opcode >> 6 === 0b1011101001) {
1019
- const Rm = (opcode >> 3) & 0x7;
1020
- const Rd = opcode & 0x7;
1021
- const input = this.registers[Rm];
1022
- this.registers[Rd] =
1023
- (((input >> 16) & 0xff) << 24) |
1024
- (((input >> 24) & 0xff) << 16) |
1025
- ((input & 0xff) << 8) |
1026
- ((input >> 8) & 0xff);
1027
- }
1028
- // REVSH
1029
- else if (opcode >> 6 === 0b1011101011) {
1030
- const Rm = (opcode >> 3) & 0x7;
1031
- const Rd = opcode & 0x7;
1032
- const input = this.registers[Rm];
1033
- this.registers[Rd] = signExtend16(((input & 0xff) << 8) | ((input >> 8) & 0xff));
1034
- }
1035
- // ROR
1036
- else if (opcode >> 6 === 0b0100000111) {
1037
- const Rm = (opcode >> 3) & 0x7;
1038
- const Rdn = opcode & 0x7;
1039
- const input = this.registers[Rdn];
1040
- const shift = (this.registers[Rm] & 0xff) % 32;
1041
- const result = (input >>> shift) | (input << (32 - shift));
1042
- this.registers[Rdn] = result;
1043
- this.N = !!(result & 0x80000000);
1044
- this.Z = result === 0;
1045
- this.C = !!(result & 0x80000000);
1046
- }
1047
- // NEGS / RSBS
1048
- else if (opcode >> 6 === 0b0100001001) {
1049
- const Rn = (opcode >> 3) & 0x7;
1050
- const Rd = opcode & 0x7;
1051
- this.registers[Rd] = this.substractUpdateFlags(0, this.registers[Rn]);
1052
- }
1053
- // NOP
1054
- else if (opcode === 0b1011111100000000) {
1055
- // Do nothing!
1056
- }
1057
- // SBCS (Encoding T1)
1058
- else if (opcode >> 6 === 0b0100000110) {
1059
- const Rm = (opcode >> 3) & 0x7;
1060
- const Rdn = opcode & 0x7;
1061
- this.registers[Rdn] = this.substractUpdateFlags(this.registers[Rdn], this.registers[Rm] + (1 - (this.C ? 1 : 0)));
1062
- }
1063
- // SEV
1064
- else if (opcode === 0b1011111101000000) {
1065
- this.logger.info(LOG_NAME, 'SEV');
1066
- }
1067
- // STMIA
1068
- else if (opcode >> 11 === 0b11000) {
1069
- const Rn = (opcode >> 8) & 0x7;
1070
- const registers = opcode & 0xff;
1071
- let address = this.registers[Rn];
1072
- for (let i = 0; i < 8; i++) {
1073
- if (registers & (1 << i)) {
1074
- this.writeUint32(address, this.registers[i]);
1075
- address += 4;
1076
- this.cycles++;
1077
- }
1078
- }
1079
- // Write back
1080
- if (!(registers & (1 << Rn))) {
1081
- this.registers[Rn] = address;
1082
- }
1083
- }
1084
- // STR (immediate)
1085
- else if (opcode >> 11 === 0b01100) {
1086
- const imm5 = ((opcode >> 6) & 0x1f) << 2;
1087
- const Rn = (opcode >> 3) & 0x7;
1088
- const Rt = opcode & 0x7;
1089
- const address = this.registers[Rn] + imm5;
1090
- this.cycles += this.cyclesIO(address, true);
1091
- this.writeUint32(address, this.registers[Rt]);
1092
- }
1093
- // STR (sp + immediate)
1094
- else if (opcode >> 11 === 0b10010) {
1095
- const Rt = (opcode >> 8) & 0x7;
1096
- const imm8 = opcode & 0xff;
1097
- const address = this.SP + (imm8 << 2);
1098
- this.cycles += this.cyclesIO(address, true);
1099
- this.writeUint32(address, this.registers[Rt]);
1100
- }
1101
- // STR (register)
1102
- else if (opcode >> 9 === 0b0101000) {
1103
- const Rm = (opcode >> 6) & 0x7;
1104
- const Rn = (opcode >> 3) & 0x7;
1105
- const Rt = opcode & 0x7;
1106
- const address = this.registers[Rm] + this.registers[Rn];
1107
- this.cycles += this.cyclesIO(address, true);
1108
- this.writeUint32(address, this.registers[Rt]);
1109
- }
1110
- // STRB (immediate)
1111
- else if (opcode >> 11 === 0b01110) {
1112
- const imm5 = (opcode >> 6) & 0x1f;
1113
- const Rn = (opcode >> 3) & 0x7;
1114
- const Rt = opcode & 0x7;
1115
- const address = this.registers[Rn] + imm5;
1116
- this.cycles += this.cyclesIO(address, true);
1117
- this.writeUint8(address, this.registers[Rt]);
1118
- }
1119
- // STRB (register)
1120
- else if (opcode >> 9 === 0b0101010) {
1121
- const Rm = (opcode >> 6) & 0x7;
1122
- const Rn = (opcode >> 3) & 0x7;
1123
- const Rt = opcode & 0x7;
1124
- const address = this.registers[Rm] + this.registers[Rn];
1125
- this.cycles += this.cyclesIO(address, true);
1126
- this.writeUint8(address, this.registers[Rt]);
1127
- }
1128
- // STRH (immediate)
1129
- else if (opcode >> 11 === 0b10000) {
1130
- const imm5 = ((opcode >> 6) & 0x1f) << 1;
1131
- const Rn = (opcode >> 3) & 0x7;
1132
- const Rt = opcode & 0x7;
1133
- const address = this.registers[Rn] + imm5;
1134
- this.cycles += this.cyclesIO(address, true);
1135
- this.writeUint16(address, this.registers[Rt]);
1136
- }
1137
- // STRH (register)
1138
- else if (opcode >> 9 === 0b0101001) {
1139
- const Rm = (opcode >> 6) & 0x7;
1140
- const Rn = (opcode >> 3) & 0x7;
1141
- const Rt = opcode & 0x7;
1142
- const address = this.registers[Rm] + this.registers[Rn];
1143
- this.cycles += this.cyclesIO(address, true);
1144
- this.writeUint16(address, this.registers[Rt]);
1145
- }
1146
- // SUB (SP minus immediate)
1147
- else if (opcode >> 7 === 0b101100001) {
1148
- const imm32 = (opcode & 0x7f) << 2;
1149
- this.SP -= imm32;
1150
- }
1151
- // SUBS (Encoding T1)
1152
- else if (opcode >> 9 === 0b0001111) {
1153
- const imm3 = (opcode >> 6) & 0x7;
1154
- const Rn = (opcode >> 3) & 0x7;
1155
- const Rd = opcode & 0x7;
1156
- this.registers[Rd] = this.substractUpdateFlags(this.registers[Rn], imm3);
1157
- }
1158
- // SUBS (Encoding T2)
1159
- else if (opcode >> 11 === 0b00111) {
1160
- const imm8 = opcode & 0xff;
1161
- const Rdn = (opcode >> 8) & 0x7;
1162
- this.registers[Rdn] = this.substractUpdateFlags(this.registers[Rdn], imm8);
1163
- }
1164
- // SUBS (register)
1165
- else if (opcode >> 9 === 0b0001101) {
1166
- const Rm = (opcode >> 6) & 0x7;
1167
- const Rn = (opcode >> 3) & 0x7;
1168
- const Rd = opcode & 0x7;
1169
- this.registers[Rd] = this.substractUpdateFlags(this.registers[Rn], this.registers[Rm]);
1170
- }
1171
- // SVC
1172
- else if (opcode >> 8 === 0b11011111) {
1173
- this.pendingSVCall = true;
1174
- this.interruptsUpdated = true;
1175
- }
1176
- // SXTB
1177
- else if (opcode >> 6 === 0b1011001001) {
1178
- const Rm = (opcode >> 3) & 0x7;
1179
- const Rd = opcode & 0x7;
1180
- this.registers[Rd] = signExtend8(this.registers[Rm]);
1181
- }
1182
- // SXTH
1183
- else if (opcode >> 6 === 0b1011001000) {
1184
- const Rm = (opcode >> 3) & 0x7;
1185
- const Rd = opcode & 0x7;
1186
- this.registers[Rd] = signExtend16(this.registers[Rm]);
1187
- }
1188
- // TST
1189
- else if (opcode >> 6 == 0b0100001000) {
1190
- const Rm = (opcode >> 3) & 0x7;
1191
- const Rn = opcode & 0x7;
1192
- const result = this.registers[Rn] & this.registers[Rm];
1193
- this.N = !!(result & 0x80000000);
1194
- this.Z = result === 0;
1195
- }
1196
- // UDF
1197
- else if (opcode >> 8 == 0b11011110) {
1198
- const imm8 = opcode & 0xff;
1199
- this.breakRewind = 2;
1200
- this.rp2040.onBreak(imm8);
1201
- }
1202
- // UDF (Encoding T2)
1203
- else if (opcode >> 4 === 0b111101111111 && opcode2 >> 12 === 0b1010) {
1204
- const imm4 = opcode & 0xf;
1205
- const imm12 = opcode2 & 0xfff;
1206
- this.breakRewind = 4;
1207
- this.rp2040.onBreak((imm4 << 12) | imm12);
1208
- this.PC += 2;
1209
- }
1210
- // UXTB
1211
- else if (opcode >> 6 == 0b1011001011) {
1212
- const Rm = (opcode >> 3) & 0x7;
1213
- const Rd = opcode & 0x7;
1214
- this.registers[Rd] = this.registers[Rm] & 0xff;
1215
- }
1216
- // UXTH
1217
- else if (opcode >> 6 == 0b1011001010) {
1218
- const Rm = (opcode >> 3) & 0x7;
1219
- const Rd = opcode & 0x7;
1220
- this.registers[Rd] = this.registers[Rm] & 0xffff;
1221
- }
1222
- // WFE
1223
- else if (opcode === 0b1011111100100000) {
1224
- this.cycles++;
1225
- if (this.eventRegistered) {
1226
- this.eventRegistered = false;
1227
- }
1228
- else {
1229
- this.waiting = true;
1230
- }
1231
- }
1232
- // WFI
1233
- else if (opcode === 0b1011111100110000) {
1234
- this.cycles++;
1235
- this.waiting = true;
1236
- }
1237
- // YIELD
1238
- else if (opcode === 0b1011111100010000) {
1239
- // do nothing for now. Wait for event!
1240
- this.logger.info(LOG_NAME, 'Yield');
1241
- }
1242
- else {
1243
- this.logger.warn(LOG_NAME, `Warning: Instruction at ${opcodePC.toString(16)} is not implemented yet!`);
1244
- this.logger.warn(LOG_NAME, `Opcode: 0x${opcode.toString(16)} (0x${opcode2.toString(16)})`);
1245
- }
1246
- }
1247
- }
1
+ import { MAX_HARDWARE_IRQ } from './irq.js';
2
+ import { APB_START_ADDRESS, SIO_START_ADDRESS } from './rp2040.js';
3
+ /* eslint-disable @typescript-eslint/no-unused-vars */
4
+ const EXC_RESET = 1;
5
+ const EXC_NMI = 2;
6
+ const EXC_HARDFAULT = 3;
7
+ const EXC_SVCALL = 11;
8
+ const EXC_PENDSV = 14;
9
+ const EXC_SYSTICK = 15;
10
+ const SYSM_APSR = 0;
11
+ const SYSM_IAPSR = 1;
12
+ const SYSM_EAPSR = 2;
13
+ const SYSM_XPSR = 3;
14
+ const SYSM_IPSR = 5;
15
+ const SYSM_EPSR = 6;
16
+ const SYSM_IEPSR = 7;
17
+ export const SYSM_MSP = 8;
18
+ export const SYSM_PSP = 9;
19
+ export const SYSM_PRIMASK = 16;
20
+ export const SYSM_CONTROL = 20;
21
+ /* eslint-enable @typescript-eslint/no-unused-vars */
22
+ // Lowest possible exception priority
23
+ const LOWEST_PRIORITY = 4;
24
+ var ExecutionMode;
25
+ (function (ExecutionMode) {
26
+ ExecutionMode[ExecutionMode["Mode_Thread"] = 0] = "Mode_Thread";
27
+ ExecutionMode[ExecutionMode["Mode_Handler"] = 1] = "Mode_Handler";
28
+ })(ExecutionMode || (ExecutionMode = {}));
29
+ function signExtend8(value) {
30
+ return (value << 24) >> 24;
31
+ }
32
+ function signExtend16(value) {
33
+ return (value << 16) >> 16;
34
+ }
35
+ const spRegister = 13;
36
+ const pcRegister = 15;
37
+ var StackPointerBank;
38
+ (function (StackPointerBank) {
39
+ StackPointerBank[StackPointerBank["SPmain"] = 0] = "SPmain";
40
+ StackPointerBank[StackPointerBank["SPprocess"] = 1] = "SPprocess";
41
+ })(StackPointerBank || (StackPointerBank = {}));
42
+ const LOG_NAME = 'CortexM0Core';
43
+ export class CortexM0Core {
44
+ constructor(rp2040) {
45
+ this.rp2040 = rp2040;
46
+ this.registers = new Uint32Array(16);
47
+ this.bankedSP = 0;
48
+ this.cycles = 0;
49
+ this.eventRegistered = false;
50
+ this.waiting = false;
51
+ // APSR fields
52
+ this.N = false;
53
+ this.C = false;
54
+ this.Z = false;
55
+ this.V = false;
56
+ // How many bytes to rewind the last break instruction
57
+ this.breakRewind = 0;
58
+ // PRIMASK fields
59
+ this.PM = false;
60
+ // CONTROL fields
61
+ this.SPSEL = StackPointerBank.SPmain;
62
+ this.nPRIV = false;
63
+ this.currentMode = ExecutionMode.Mode_Thread;
64
+ this.IPSR = 0;
65
+ this.interruptNMIMask = 0;
66
+ this.pendingInterrupts = 0;
67
+ this.enabledInterrupts = 0;
68
+ this.interruptPriorities = [0xffffffff, 0x0, 0x0, 0x0];
69
+ this.pendingNMI = false;
70
+ this.pendingPendSV = false;
71
+ this.pendingSVCall = false;
72
+ this.pendingSystick = false;
73
+ this.interruptsUpdated = false;
74
+ this.VTOR = 0;
75
+ this.SHPR2 = 0;
76
+ this.SHPR3 = 0;
77
+ /** Hook to listen for function calls - branch-link (BL/BLX) instructions */
78
+ this.blTaken = (core, blx) => {
79
+ void core; // surpress unused variable warnings
80
+ void blx;
81
+ };
82
+ this.SP = 0xfffffffc;
83
+ this.bankedSP = 0xfffffffc;
84
+ }
85
+ get logger() {
86
+ return this.rp2040.logger;
87
+ }
88
+ reset() {
89
+ this.SP = this.rp2040.readUint32(this.VTOR);
90
+ this.PC = this.rp2040.readUint32(this.VTOR + 4) & 0xfffffffe;
91
+ this.cycles = 0;
92
+ }
93
+ get SP() {
94
+ return this.registers[13];
95
+ }
96
+ set SP(value) {
97
+ this.registers[13] = value & ~0x3;
98
+ }
99
+ get LR() {
100
+ return this.registers[14];
101
+ }
102
+ set LR(value) {
103
+ this.registers[14] = value;
104
+ }
105
+ get PC() {
106
+ return this.registers[15];
107
+ }
108
+ set PC(value) {
109
+ this.registers[15] = value;
110
+ }
111
+ get APSR() {
112
+ return ((this.N ? 0x80000000 : 0) |
113
+ (this.Z ? 0x40000000 : 0) |
114
+ (this.C ? 0x20000000 : 0) |
115
+ (this.V ? 0x10000000 : 0));
116
+ }
117
+ set APSR(value) {
118
+ this.N = !!(value & 0x80000000);
119
+ this.Z = !!(value & 0x40000000);
120
+ this.C = !!(value & 0x20000000);
121
+ this.V = !!(value & 0x10000000);
122
+ }
123
+ get xPSR() {
124
+ return this.APSR | this.IPSR | (1 << 24);
125
+ }
126
+ set xPSR(value) {
127
+ this.APSR = value;
128
+ this.IPSR = value & 0x3f;
129
+ }
130
+ checkCondition(cond) {
131
+ // Evaluate base condition.
132
+ let result = false;
133
+ switch (cond >> 1) {
134
+ case 0b000:
135
+ result = this.Z;
136
+ break;
137
+ case 0b001:
138
+ result = this.C;
139
+ break;
140
+ case 0b010:
141
+ result = this.N;
142
+ break;
143
+ case 0b011:
144
+ result = this.V;
145
+ break;
146
+ case 0b100:
147
+ result = this.C && !this.Z;
148
+ break;
149
+ case 0b101:
150
+ result = this.N === this.V;
151
+ break;
152
+ case 0b110:
153
+ result = this.N === this.V && !this.Z;
154
+ break;
155
+ case 0b111:
156
+ result = true;
157
+ break;
158
+ }
159
+ return cond & 0b1 && cond != 0b1111 ? !result : result;
160
+ }
161
+ readUint32(address) {
162
+ return this.rp2040.readUint32(address);
163
+ }
164
+ readUint16(address) {
165
+ return this.rp2040.readUint16(address);
166
+ }
167
+ readUint8(address) {
168
+ return this.rp2040.readUint8(address);
169
+ }
170
+ writeUint32(address, value) {
171
+ this.rp2040.writeUint32(address, value);
172
+ }
173
+ writeUint16(address, value) {
174
+ this.rp2040.writeUint16(address, value);
175
+ }
176
+ writeUint8(address, value) {
177
+ this.rp2040.writeUint8(address, value);
178
+ }
179
+ switchStack(stack) {
180
+ if (this.SPSEL !== stack) {
181
+ const temp = this.SP;
182
+ this.SP = this.bankedSP;
183
+ this.bankedSP = temp;
184
+ this.SPSEL = stack;
185
+ }
186
+ }
187
+ get SPprocess() {
188
+ return this.SPSEL === StackPointerBank.SPprocess ? this.SP : this.bankedSP;
189
+ }
190
+ set SPprocess(value) {
191
+ if (this.SPSEL === StackPointerBank.SPprocess) {
192
+ this.SP = value;
193
+ }
194
+ else {
195
+ this.bankedSP = value >>> 0;
196
+ }
197
+ }
198
+ get SPmain() {
199
+ return this.SPSEL === StackPointerBank.SPmain ? this.SP : this.bankedSP;
200
+ }
201
+ set SPmain(value) {
202
+ if (this.SPSEL === StackPointerBank.SPmain) {
203
+ this.SP = value;
204
+ }
205
+ else {
206
+ this.bankedSP = value >>> 0;
207
+ }
208
+ }
209
+ exceptionEntry(exceptionNumber) {
210
+ // PushStack:
211
+ let framePtr = 0;
212
+ let framePtrAlign = 0;
213
+ if (this.SPSEL && this.currentMode === ExecutionMode.Mode_Thread) {
214
+ framePtrAlign = this.SPprocess & 0b100 ? 1 : 0;
215
+ this.SPprocess = (this.SPprocess - 0x20) & ~0b100;
216
+ framePtr = this.SPprocess;
217
+ }
218
+ else {
219
+ framePtrAlign = this.SPmain & 0b100 ? 1 : 0;
220
+ this.SPmain = (this.SPmain - 0x20) & ~0b100;
221
+ framePtr = this.SPmain;
222
+ }
223
+ /* only the stack locations, not the store order, are architected */
224
+ this.writeUint32(framePtr, this.registers[0]);
225
+ this.writeUint32(framePtr + 0x4, this.registers[1]);
226
+ this.writeUint32(framePtr + 0x8, this.registers[2]);
227
+ this.writeUint32(framePtr + 0xc, this.registers[3]);
228
+ this.writeUint32(framePtr + 0x10, this.registers[12]);
229
+ this.writeUint32(framePtr + 0x14, this.LR);
230
+ this.writeUint32(framePtr + 0x18, this.PC & ~1); // ReturnAddress(ExceptionType);
231
+ this.writeUint32(framePtr + 0x1c, (this.xPSR & ~(1 << 9)) | (framePtrAlign << 9));
232
+ if (this.currentMode == ExecutionMode.Mode_Handler) {
233
+ this.LR = 0xfffffff1;
234
+ }
235
+ else {
236
+ if (!this.SPSEL) {
237
+ this.LR = 0xfffffff9;
238
+ }
239
+ else {
240
+ this.LR = 0xfffffffd;
241
+ }
242
+ }
243
+ // ExceptionTaken:
244
+ this.currentMode = ExecutionMode.Mode_Handler; // Enter Handler Mode, now Privileged
245
+ this.IPSR = exceptionNumber;
246
+ this.switchStack(StackPointerBank.SPmain);
247
+ this.eventRegistered = true;
248
+ const vectorTable = this.VTOR;
249
+ this.PC = this.readUint32(vectorTable + 4 * exceptionNumber);
250
+ }
251
+ exceptionReturn(excReturn) {
252
+ let framePtr = this.SPmain;
253
+ switch (excReturn & 0xf) {
254
+ case 0b0001: // Return to Handler
255
+ this.currentMode = ExecutionMode.Mode_Handler;
256
+ this.switchStack(StackPointerBank.SPmain);
257
+ break;
258
+ case 0b1001: // Return to Thread using Main stack
259
+ this.currentMode = ExecutionMode.Mode_Thread;
260
+ this.switchStack(StackPointerBank.SPmain);
261
+ break;
262
+ case 0b1101: // Return to Thread using Process stack
263
+ framePtr = this.SPprocess;
264
+ this.currentMode = ExecutionMode.Mode_Thread;
265
+ this.switchStack(StackPointerBank.SPprocess);
266
+ break;
267
+ // Assigning CurrentMode to Mode_Thread causes a drop in privilege
268
+ // if CONTROL.nPRIV is set to 1
269
+ }
270
+ // PopStack:
271
+ this.registers[0] = this.readUint32(framePtr); // Stack accesses are performed as Unprivileged accesses if
272
+ this.registers[1] = this.readUint32(framePtr + 0x4); // CONTROL<0>=='1' && EXC_RETURN<3>=='1' Privileged otherwise
273
+ this.registers[2] = this.readUint32(framePtr + 0x8);
274
+ this.registers[3] = this.readUint32(framePtr + 0xc);
275
+ this.registers[12] = this.readUint32(framePtr + 0x10);
276
+ this.LR = this.readUint32(framePtr + 0x14);
277
+ this.PC = this.readUint32(framePtr + 0x18);
278
+ const psr = this.readUint32(framePtr + 0x1c);
279
+ const framePtrAlign = psr & (1 << 9) ? 0b100 : 0;
280
+ switch (excReturn & 0xf) {
281
+ case 0b0001: // Returning to Handler mode
282
+ this.SPmain = (this.SPmain + 0x20) | framePtrAlign;
283
+ break;
284
+ case 0b1001: // Returning to Thread mode using Main stack
285
+ this.SPmain = (this.SPmain + 0x20) | framePtrAlign;
286
+ break;
287
+ case 0b1101: // Returning to Thread mode using Process stack
288
+ this.SPprocess = (this.SPprocess + 0x20) | framePtrAlign;
289
+ break;
290
+ }
291
+ this.APSR = psr & 0xf0000000;
292
+ const forceThread = this.currentMode == ExecutionMode.Mode_Thread && this.nPRIV;
293
+ this.IPSR = forceThread ? 0 : psr & 0x3f;
294
+ this.interruptsUpdated = true;
295
+ // Thumb bit should always be one! EPSR<24> = psr<24>; // Load valid EPSR bits from memory
296
+ this.eventRegistered = true;
297
+ // if CurrentMode == Mode_Thread && SCR.SLEEPONEXIT == '1' then
298
+ // SleepOnExit(); // IMPLEMENTATION DEFINED
299
+ }
300
+ get pendSVPriority() {
301
+ return (this.SHPR3 >> 22) & 0x3;
302
+ }
303
+ get svCallPriority() {
304
+ return this.SHPR2 >>> 30;
305
+ }
306
+ get systickPriority() {
307
+ return this.SHPR3 >>> 30;
308
+ }
309
+ exceptionPriority(n) {
310
+ switch (n) {
311
+ case EXC_RESET:
312
+ return -3;
313
+ case EXC_NMI:
314
+ return -2;
315
+ case EXC_HARDFAULT:
316
+ return -1;
317
+ case EXC_SVCALL:
318
+ return this.svCallPriority;
319
+ case EXC_PENDSV:
320
+ return this.pendSVPriority;
321
+ case EXC_SYSTICK:
322
+ return this.systickPriority;
323
+ default: {
324
+ if (n < 16) {
325
+ return LOWEST_PRIORITY;
326
+ }
327
+ const intNum = n - 16;
328
+ for (let priority = 0; priority < 4; priority++) {
329
+ if (this.interruptPriorities[priority] & (1 << intNum)) {
330
+ return priority;
331
+ }
332
+ }
333
+ return LOWEST_PRIORITY;
334
+ }
335
+ }
336
+ }
337
+ get vectPending() {
338
+ if (this.pendingNMI) {
339
+ return EXC_NMI;
340
+ }
341
+ const { svCallPriority, systickPriority, pendSVPriority, pendingInterrupts } = this;
342
+ for (let priority = 0; priority < LOWEST_PRIORITY; priority++) {
343
+ const levelInterrupts = pendingInterrupts & this.interruptPriorities[priority];
344
+ if (this.pendingSVCall && priority === svCallPriority) {
345
+ return EXC_SVCALL;
346
+ }
347
+ if (this.pendingPendSV && priority === pendSVPriority) {
348
+ return EXC_PENDSV;
349
+ }
350
+ if (this.pendingSystick && priority === systickPriority) {
351
+ return EXC_SYSTICK;
352
+ }
353
+ if (levelInterrupts) {
354
+ for (let interruptNumber = 0; interruptNumber < 32; interruptNumber++) {
355
+ if (levelInterrupts & (1 << interruptNumber)) {
356
+ return 16 + interruptNumber;
357
+ }
358
+ }
359
+ }
360
+ }
361
+ return 0;
362
+ }
363
+ setInterrupt(irq, value) {
364
+ const irqBit = 1 << irq;
365
+ if (value && !(this.pendingInterrupts & irqBit)) {
366
+ this.pendingInterrupts |= irqBit;
367
+ this.interruptsUpdated = true;
368
+ if (this.waiting && this.checkForInterrupts()) {
369
+ this.waiting = false;
370
+ }
371
+ }
372
+ else if (!value) {
373
+ this.pendingInterrupts &= ~irqBit;
374
+ }
375
+ }
376
+ checkForInterrupts() {
377
+ /* If we're waiting for an interrupt (i.e. WFI/WFE), the ARM says:
378
+ > If PRIMASK.PM is set to 1, an asynchronous exception that has a higher group priority than any
379
+ > active exception results in a WFI instruction exit. If the group priority of the exception is less than or
380
+ > equal to the execution group priority, the exception is ignored.
381
+ */
382
+ const currentPriority = this.waiting
383
+ ? this.PM
384
+ ? this.exceptionPriority(this.IPSR)
385
+ : LOWEST_PRIORITY
386
+ : Math.min(this.exceptionPriority(this.IPSR), this.PM ? 0 : LOWEST_PRIORITY);
387
+ const interruptSet = this.pendingInterrupts & this.enabledInterrupts;
388
+ const { svCallPriority, systickPriority, pendSVPriority } = this;
389
+ if (this.pendingNMI) {
390
+ this.pendingNMI = false;
391
+ this.exceptionEntry(EXC_NMI);
392
+ return true;
393
+ }
394
+ for (let priority = 0; priority < currentPriority; priority++) {
395
+ const levelInterrupts = interruptSet & this.interruptPriorities[priority];
396
+ if (this.pendingSVCall && priority === svCallPriority) {
397
+ this.pendingSVCall = false;
398
+ this.exceptionEntry(EXC_SVCALL);
399
+ return true;
400
+ }
401
+ if (this.pendingPendSV && priority === pendSVPriority) {
402
+ this.pendingPendSV = false;
403
+ this.exceptionEntry(EXC_PENDSV);
404
+ return true;
405
+ }
406
+ if (this.pendingSystick && priority === systickPriority) {
407
+ this.pendingSystick = false;
408
+ this.exceptionEntry(EXC_SYSTICK);
409
+ return true;
410
+ }
411
+ if (levelInterrupts) {
412
+ for (let interruptNumber = 0; interruptNumber < 32; interruptNumber++) {
413
+ if (levelInterrupts & (1 << interruptNumber)) {
414
+ if (interruptNumber > MAX_HARDWARE_IRQ) {
415
+ this.pendingInterrupts &= ~(1 << interruptNumber);
416
+ }
417
+ this.exceptionEntry(16 + interruptNumber);
418
+ return true;
419
+ }
420
+ }
421
+ }
422
+ }
423
+ this.interruptsUpdated = false;
424
+ return false;
425
+ }
426
+ readSpecialRegister(sysm) {
427
+ switch (sysm) {
428
+ case SYSM_APSR:
429
+ return this.APSR;
430
+ case SYSM_XPSR:
431
+ return this.xPSR;
432
+ case SYSM_IPSR:
433
+ return this.IPSR;
434
+ case SYSM_PRIMASK:
435
+ return this.PM ? 1 : 0;
436
+ case SYSM_MSP:
437
+ return this.SPmain;
438
+ case SYSM_PSP:
439
+ return this.SPprocess;
440
+ case SYSM_CONTROL:
441
+ return (this.SPSEL === StackPointerBank.SPprocess ? 2 : 0) | (this.nPRIV ? 1 : 0);
442
+ default:
443
+ this.logger.warn(LOG_NAME, `MRS with unimplemented SYSm value: ${sysm}`);
444
+ return 0;
445
+ }
446
+ }
447
+ writeSpecialRegister(sysm, value) {
448
+ switch (sysm) {
449
+ case SYSM_APSR:
450
+ this.APSR = value;
451
+ break;
452
+ case SYSM_XPSR:
453
+ this.xPSR = value;
454
+ break;
455
+ case SYSM_IPSR:
456
+ this.IPSR = value;
457
+ break;
458
+ case SYSM_PRIMASK:
459
+ this.PM = !!(value & 1);
460
+ this.interruptsUpdated = true;
461
+ break;
462
+ case SYSM_MSP:
463
+ this.SPmain = value;
464
+ break;
465
+ case SYSM_PSP:
466
+ this.SPprocess = value;
467
+ break;
468
+ case SYSM_CONTROL:
469
+ this.nPRIV = !!(value & 1);
470
+ if (this.currentMode === ExecutionMode.Mode_Thread) {
471
+ this.switchStack(value & 2 ? StackPointerBank.SPprocess : StackPointerBank.SPmain);
472
+ }
473
+ break;
474
+ default:
475
+ this.logger.warn(LOG_NAME, `MRS with unimplemented SYSm value: ${sysm}`);
476
+ return 0;
477
+ }
478
+ }
479
+ BXWritePC(address) {
480
+ if (this.currentMode == ExecutionMode.Mode_Handler && address >>> 28 == 0b1111) {
481
+ this.exceptionReturn(address & 0x0fffffff);
482
+ }
483
+ else {
484
+ this.PC = address & ~1;
485
+ }
486
+ }
487
+ substractUpdateFlags(minuend, subtrahend) {
488
+ const result = minuend - subtrahend;
489
+ this.N = !!(result & 0x80000000);
490
+ this.Z = (result & 0xffffffff) === 0;
491
+ this.C = minuend >= subtrahend;
492
+ this.V =
493
+ (!!(result & 0x80000000) && !(minuend & 0x80000000) && !!(subtrahend & 0x80000000)) ||
494
+ (!(result & 0x80000000) && !!(minuend & 0x80000000) && !(subtrahend & 0x80000000));
495
+ return result;
496
+ }
497
+ addUpdateFlags(addend1, addend2) {
498
+ const unsignedSum = (addend1 + addend2) >>> 0;
499
+ const signedSum = (addend1 | 0) + (addend2 | 0);
500
+ const result = addend1 + addend2;
501
+ this.N = !!(result & 0x80000000);
502
+ this.Z = (result & 0xffffffff) === 0;
503
+ this.C = result === unsignedSum ? false : true;
504
+ this.V = (result | 0) === signedSum ? false : true;
505
+ return result & 0xffffffff;
506
+ }
507
+ cyclesIO(addr, write = false) {
508
+ addr = addr >>> 0;
509
+ if (addr >= SIO_START_ADDRESS && addr < SIO_START_ADDRESS + 0x10000000) {
510
+ return 0;
511
+ }
512
+ if (addr >= APB_START_ADDRESS && addr < APB_START_ADDRESS + 0x10000000) {
513
+ return write ? 4 : 3;
514
+ }
515
+ return 1;
516
+ }
517
+ executeInstruction() {
518
+ if (this.interruptsUpdated) {
519
+ if (this.checkForInterrupts()) {
520
+ this.waiting = false;
521
+ }
522
+ }
523
+ // ARM Thumb instruction encoding - 16 bits / 2 bytes
524
+ const opcodePC = this.PC & ~1; //ensure no LSB set PC are executed
525
+ const opcode = this.readUint16(opcodePC);
526
+ const wideInstruction = opcode >> 12 === 0b1111 || opcode >> 11 === 0b11101;
527
+ const opcode2 = wideInstruction ? this.readUint16(opcodePC + 2) : 0;
528
+ this.PC += 2;
529
+ this.cycles++;
530
+ // ADCS
531
+ if (opcode >> 6 === 0b0100000101) {
532
+ const Rm = (opcode >> 3) & 0x7;
533
+ const Rdn = opcode & 0x7;
534
+ this.registers[Rdn] = this.addUpdateFlags(this.registers[Rm], this.registers[Rdn] + (this.C ? 1 : 0));
535
+ }
536
+ // ADD (register = SP plus immediate)
537
+ else if (opcode >> 11 === 0b10101) {
538
+ const imm8 = opcode & 0xff;
539
+ const Rd = (opcode >> 8) & 0x7;
540
+ this.registers[Rd] = this.SP + (imm8 << 2);
541
+ }
542
+ // ADD (SP plus immediate)
543
+ else if (opcode >> 7 === 0b101100000) {
544
+ const imm32 = (opcode & 0x7f) << 2;
545
+ this.SP += imm32;
546
+ }
547
+ // ADDS (Encoding T1)
548
+ else if (opcode >> 9 === 0b0001110) {
549
+ const imm3 = (opcode >> 6) & 0x7;
550
+ const Rn = (opcode >> 3) & 0x7;
551
+ const Rd = opcode & 0x7;
552
+ this.registers[Rd] = this.addUpdateFlags(this.registers[Rn], imm3);
553
+ }
554
+ // ADDS (Encoding T2)
555
+ else if (opcode >> 11 === 0b00110) {
556
+ const imm8 = opcode & 0xff;
557
+ const Rdn = (opcode >> 8) & 0x7;
558
+ this.registers[Rdn] = this.addUpdateFlags(this.registers[Rdn], imm8);
559
+ }
560
+ // ADDS (register)
561
+ else if (opcode >> 9 === 0b0001100) {
562
+ const Rm = (opcode >> 6) & 0x7;
563
+ const Rn = (opcode >> 3) & 0x7;
564
+ const Rd = opcode & 0x7;
565
+ this.registers[Rd] = this.addUpdateFlags(this.registers[Rn], this.registers[Rm]);
566
+ }
567
+ // ADD (register)
568
+ else if (opcode >> 8 === 0b01000100) {
569
+ const Rm = (opcode >> 3) & 0xf;
570
+ const Rdn = ((opcode & 0x80) >> 4) | (opcode & 0x7);
571
+ const leftValue = Rdn === pcRegister ? this.PC + 2 : this.registers[Rdn];
572
+ const rightValue = this.registers[Rm];
573
+ const result = leftValue + rightValue;
574
+ if (Rdn !== spRegister && Rdn !== pcRegister) {
575
+ this.registers[Rdn] = result;
576
+ }
577
+ else if (Rdn === pcRegister) {
578
+ this.registers[Rdn] = result & ~0x1;
579
+ this.cycles++;
580
+ }
581
+ else if (Rdn === spRegister) {
582
+ this.registers[Rdn] = result & ~0x3;
583
+ }
584
+ }
585
+ // ADR
586
+ else if (opcode >> 11 === 0b10100) {
587
+ const imm8 = opcode & 0xff;
588
+ const Rd = (opcode >> 8) & 0x7;
589
+ this.registers[Rd] = (opcodePC & 0xfffffffc) + 4 + (imm8 << 2);
590
+ }
591
+ // ANDS (Encoding T2)
592
+ else if (opcode >> 6 === 0b0100000000) {
593
+ const Rm = (opcode >> 3) & 0x7;
594
+ const Rdn = opcode & 0x7;
595
+ const result = this.registers[Rdn] & this.registers[Rm];
596
+ this.registers[Rdn] = result;
597
+ this.N = !!(result & 0x80000000);
598
+ this.Z = (result & 0xffffffff) === 0;
599
+ }
600
+ // ASRS (immediate)
601
+ else if (opcode >> 11 === 0b00010) {
602
+ const imm5 = (opcode >> 6) & 0x1f;
603
+ const Rm = (opcode >> 3) & 0x7;
604
+ const Rd = opcode & 0x7;
605
+ const input = this.registers[Rm];
606
+ const shiftN = imm5 ? imm5 : 32;
607
+ const result = shiftN < 32 ? input >> shiftN : (input & 0x80000000) >> 31;
608
+ this.registers[Rd] = result;
609
+ this.N = !!(result & 0x80000000);
610
+ this.Z = (result & 0xffffffff) === 0;
611
+ this.C = input & (1 << (shiftN - 1)) ? true : false;
612
+ }
613
+ // ASRS (register)
614
+ else if (opcode >> 6 === 0b0100000100) {
615
+ const Rm = (opcode >> 3) & 0x7;
616
+ const Rdn = opcode & 0x7;
617
+ const input = this.registers[Rdn];
618
+ const shiftN = (this.registers[Rm] & 0xff) < 32 ? this.registers[Rm] & 0xff : 32;
619
+ const result = shiftN < 32 ? input >> shiftN : (input & 0x80000000) >> 31;
620
+ this.registers[Rdn] = result;
621
+ this.N = !!(result & 0x80000000);
622
+ this.Z = (result & 0xffffffff) === 0;
623
+ this.C = input & (1 << (shiftN - 1)) ? true : false;
624
+ }
625
+ // B (with cond)
626
+ else if (opcode >> 12 === 0b1101 && ((opcode >> 9) & 0x7) !== 0b111) {
627
+ let imm8 = (opcode & 0xff) << 1;
628
+ const cond = (opcode >> 8) & 0xf;
629
+ if (imm8 & (1 << 8)) {
630
+ imm8 = (imm8 & 0x1ff) - 0x200;
631
+ }
632
+ if (this.checkCondition(cond)) {
633
+ this.PC += imm8 + 2;
634
+ this.cycles++;
635
+ }
636
+ }
637
+ // B
638
+ else if (opcode >> 11 === 0b11100) {
639
+ let imm11 = (opcode & 0x7ff) << 1;
640
+ if (imm11 & (1 << 11)) {
641
+ imm11 = (imm11 & 0x7ff) - 0x800;
642
+ }
643
+ this.PC += imm11 + 2;
644
+ this.cycles++;
645
+ }
646
+ // BICS
647
+ else if (opcode >> 6 === 0b0100001110) {
648
+ const Rm = (opcode >> 3) & 0x7;
649
+ const Rdn = opcode & 0x7;
650
+ const result = (this.registers[Rdn] &= ~this.registers[Rm]);
651
+ this.N = !!(result & 0x80000000);
652
+ this.Z = result === 0;
653
+ }
654
+ // BKPT
655
+ else if (opcode >> 8 === 0b10111110) {
656
+ const imm8 = opcode & 0xff;
657
+ this.breakRewind = 2;
658
+ this.rp2040.onBreak(imm8);
659
+ }
660
+ // BL
661
+ else if (opcode >> 11 === 0b11110 && opcode2 >> 14 === 0b11 && ((opcode2 >> 12) & 0x1) == 1) {
662
+ const imm11 = opcode2 & 0x7ff;
663
+ const J2 = (opcode2 >> 11) & 0x1;
664
+ const J1 = (opcode2 >> 13) & 0x1;
665
+ const imm10 = opcode & 0x3ff;
666
+ const S = (opcode >> 10) & 0x1;
667
+ const I1 = 1 - (S ^ J1);
668
+ const I2 = 1 - (S ^ J2);
669
+ const imm32 = ((S ? 0b11111111 : 0) << 24) | ((I1 << 23) | (I2 << 22) | (imm10 << 12) | (imm11 << 1));
670
+ this.LR = (this.PC + 2) | 0x1;
671
+ this.PC += 2 + imm32;
672
+ this.cycles += 2;
673
+ this.blTaken(this, false);
674
+ }
675
+ // BLX
676
+ else if (opcode >> 7 === 0b010001111 && (opcode & 0x7) === 0) {
677
+ const Rm = (opcode >> 3) & 0xf;
678
+ this.LR = this.PC | 0x1;
679
+ this.PC = this.registers[Rm] & ~1;
680
+ this.cycles++;
681
+ this.blTaken(this, true);
682
+ }
683
+ // BX
684
+ else if (opcode >> 7 === 0b010001110 && (opcode & 0x7) === 0) {
685
+ const Rm = (opcode >> 3) & 0xf;
686
+ this.BXWritePC(this.registers[Rm]);
687
+ this.cycles++;
688
+ }
689
+ // CMN (register)
690
+ else if (opcode >> 6 === 0b0100001011) {
691
+ const Rm = (opcode >> 3) & 0x7;
692
+ const Rn = opcode & 0x7;
693
+ this.addUpdateFlags(this.registers[Rn], this.registers[Rm]);
694
+ }
695
+ // CMP immediate
696
+ else if (opcode >> 11 === 0b00101) {
697
+ const Rn = (opcode >> 8) & 0x7;
698
+ const imm8 = opcode & 0xff;
699
+ this.substractUpdateFlags(this.registers[Rn], imm8);
700
+ }
701
+ // CMP (register)
702
+ else if (opcode >> 6 === 0b0100001010) {
703
+ const Rm = (opcode >> 3) & 0x7;
704
+ const Rn = opcode & 0x7;
705
+ this.substractUpdateFlags(this.registers[Rn], this.registers[Rm]);
706
+ }
707
+ // CMP (register) encoding T2
708
+ else if (opcode >> 8 === 0b01000101) {
709
+ const Rm = (opcode >> 3) & 0xf;
710
+ const Rn = ((opcode >> 4) & 0x8) | (opcode & 0x7);
711
+ this.substractUpdateFlags(this.registers[Rn], this.registers[Rm]);
712
+ }
713
+ // CPSID i
714
+ else if (opcode === 0xb672) {
715
+ this.PM = true;
716
+ }
717
+ // CPSIE i
718
+ else if (opcode === 0xb662) {
719
+ this.PM = false;
720
+ this.interruptsUpdated = true;
721
+ }
722
+ // DMB SY
723
+ else if (opcode === 0xf3bf && (opcode2 & 0xfff0) === 0x8f50) {
724
+ this.PC += 2;
725
+ this.cycles += 2;
726
+ }
727
+ // DSB SY
728
+ else if (opcode === 0xf3bf && (opcode2 & 0xfff0) === 0x8f40) {
729
+ this.PC += 2;
730
+ this.cycles += 2;
731
+ }
732
+ // EORS
733
+ else if (opcode >> 6 === 0b0100000001) {
734
+ const Rm = (opcode >> 3) & 0x7;
735
+ const Rdn = opcode & 0x7;
736
+ const result = this.registers[Rm] ^ this.registers[Rdn];
737
+ this.registers[Rdn] = result;
738
+ this.N = !!(result & 0x80000000);
739
+ this.Z = result === 0;
740
+ }
741
+ // ISB SY
742
+ else if (opcode === 0xf3bf && (opcode2 & 0xfff0) === 0x8f60) {
743
+ this.PC += 2;
744
+ this.cycles += 2;
745
+ }
746
+ // LDMIA
747
+ else if (opcode >> 11 === 0b11001) {
748
+ const Rn = (opcode >> 8) & 0x7;
749
+ const registers = opcode & 0xff;
750
+ let address = this.registers[Rn];
751
+ for (let i = 0; i < 8; i++) {
752
+ if (registers & (1 << i)) {
753
+ this.registers[i] = this.readUint32(address);
754
+ address += 4;
755
+ this.cycles++;
756
+ }
757
+ }
758
+ // Write back
759
+ if (!(registers & (1 << Rn))) {
760
+ this.registers[Rn] = address;
761
+ }
762
+ }
763
+ // LDR (immediate)
764
+ else if (opcode >> 11 === 0b01101) {
765
+ const imm5 = ((opcode >> 6) & 0x1f) << 2;
766
+ const Rn = (opcode >> 3) & 0x7;
767
+ const Rt = opcode & 0x7;
768
+ const addr = this.registers[Rn] + imm5;
769
+ this.cycles += this.cyclesIO(addr);
770
+ this.registers[Rt] = this.readUint32(addr);
771
+ }
772
+ // LDR (sp + immediate)
773
+ else if (opcode >> 11 === 0b10011) {
774
+ const Rt = (opcode >> 8) & 0x7;
775
+ const imm8 = opcode & 0xff;
776
+ const addr = this.SP + (imm8 << 2);
777
+ this.cycles += this.cyclesIO(addr);
778
+ this.registers[Rt] = this.readUint32(addr);
779
+ }
780
+ // LDR (literal)
781
+ else if (opcode >> 11 === 0b01001) {
782
+ const imm8 = (opcode & 0xff) << 2;
783
+ const Rt = (opcode >> 8) & 7;
784
+ const nextPC = this.PC + 2;
785
+ const addr = (nextPC & 0xfffffffc) + imm8;
786
+ this.cycles += this.cyclesIO(addr);
787
+ this.registers[Rt] = this.readUint32(addr);
788
+ }
789
+ // LDR (register)
790
+ else if (opcode >> 9 === 0b0101100) {
791
+ const Rm = (opcode >> 6) & 0x7;
792
+ const Rn = (opcode >> 3) & 0x7;
793
+ const Rt = opcode & 0x7;
794
+ const addr = this.registers[Rm] + this.registers[Rn];
795
+ this.cycles += this.cyclesIO(addr);
796
+ this.registers[Rt] = this.readUint32(addr);
797
+ }
798
+ // LDRB (immediate)
799
+ else if (opcode >> 11 === 0b01111) {
800
+ const imm5 = (opcode >> 6) & 0x1f;
801
+ const Rn = (opcode >> 3) & 0x7;
802
+ const Rt = opcode & 0x7;
803
+ const addr = this.registers[Rn] + imm5;
804
+ this.cycles += this.cyclesIO(addr);
805
+ this.registers[Rt] = this.readUint8(addr);
806
+ }
807
+ // LDRB (register)
808
+ else if (opcode >> 9 === 0b0101110) {
809
+ const Rm = (opcode >> 6) & 0x7;
810
+ const Rn = (opcode >> 3) & 0x7;
811
+ const Rt = opcode & 0x7;
812
+ const addr = this.registers[Rm] + this.registers[Rn];
813
+ this.cycles += this.cyclesIO(addr);
814
+ this.registers[Rt] = this.readUint8(addr);
815
+ }
816
+ // LDRH (immediate)
817
+ else if (opcode >> 11 === 0b10001) {
818
+ const imm5 = (opcode >> 6) & 0x1f;
819
+ const Rn = (opcode >> 3) & 0x7;
820
+ const Rt = opcode & 0x7;
821
+ const addr = this.registers[Rn] + (imm5 << 1);
822
+ this.cycles += this.cyclesIO(addr);
823
+ this.registers[Rt] = this.readUint16(addr);
824
+ }
825
+ // LDRH (register)
826
+ else if (opcode >> 9 === 0b0101101) {
827
+ const Rm = (opcode >> 6) & 0x7;
828
+ const Rn = (opcode >> 3) & 0x7;
829
+ const Rt = opcode & 0x7;
830
+ const addr = this.registers[Rm] + this.registers[Rn];
831
+ this.cycles += this.cyclesIO(addr);
832
+ this.registers[Rt] = this.readUint16(addr);
833
+ }
834
+ // LDRSB
835
+ else if (opcode >> 9 === 0b0101011) {
836
+ const Rm = (opcode >> 6) & 0x7;
837
+ const Rn = (opcode >> 3) & 0x7;
838
+ const Rt = opcode & 0x7;
839
+ const addr = this.registers[Rm] + this.registers[Rn];
840
+ this.cycles += this.cyclesIO(addr);
841
+ this.registers[Rt] = signExtend8(this.readUint8(addr));
842
+ }
843
+ // LDRSH
844
+ else if (opcode >> 9 === 0b0101111) {
845
+ const Rm = (opcode >> 6) & 0x7;
846
+ const Rn = (opcode >> 3) & 0x7;
847
+ const Rt = opcode & 0x7;
848
+ const addr = this.registers[Rm] + this.registers[Rn];
849
+ this.cycles += this.cyclesIO(addr);
850
+ this.registers[Rt] = signExtend16(this.readUint16(addr));
851
+ }
852
+ // LSLS (immediate)
853
+ else if (opcode >> 11 === 0b00000) {
854
+ const imm5 = (opcode >> 6) & 0x1f;
855
+ const Rm = (opcode >> 3) & 0x7;
856
+ const Rd = opcode & 0x7;
857
+ const input = this.registers[Rm];
858
+ const result = input << imm5;
859
+ this.registers[Rd] = result;
860
+ this.N = !!(result & 0x80000000);
861
+ this.Z = result === 0;
862
+ this.C = imm5 ? !!(input & (1 << (32 - imm5))) : this.C;
863
+ }
864
+ // LSLS (register)
865
+ else if (opcode >> 6 === 0b0100000010) {
866
+ const Rm = (opcode >> 3) & 0x7;
867
+ const Rdn = opcode & 0x7;
868
+ const input = this.registers[Rdn];
869
+ const shiftCount = this.registers[Rm] & 0xff;
870
+ const result = shiftCount >= 32 ? 0 : input << shiftCount;
871
+ this.registers[Rdn] = result;
872
+ this.N = !!(result & 0x80000000);
873
+ this.Z = result === 0;
874
+ this.C = shiftCount ? !!(input & (1 << (32 - shiftCount))) : this.C;
875
+ }
876
+ // LSRS (immediate)
877
+ else if (opcode >> 11 === 0b00001) {
878
+ const imm5 = (opcode >> 6) & 0x1f;
879
+ const Rm = (opcode >> 3) & 0x7;
880
+ const Rd = opcode & 0x7;
881
+ const input = this.registers[Rm];
882
+ const result = imm5 ? input >>> imm5 : 0;
883
+ this.registers[Rd] = result;
884
+ this.N = !!(result & 0x80000000);
885
+ this.Z = result === 0;
886
+ this.C = !!((input >>> (imm5 ? imm5 - 1 : 31)) & 0x1);
887
+ }
888
+ // LSRS (register)
889
+ else if (opcode >> 6 === 0b0100000011) {
890
+ const Rm = (opcode >> 3) & 0x7;
891
+ const Rdn = opcode & 0x7;
892
+ const shiftAmount = this.registers[Rm] & 0xff;
893
+ const input = this.registers[Rdn];
894
+ const result = shiftAmount < 32 ? input >>> shiftAmount : 0;
895
+ this.registers[Rdn] = result;
896
+ this.N = !!(result & 0x80000000);
897
+ this.Z = result === 0;
898
+ this.C = shiftAmount <= 32 ? !!((input >>> (shiftAmount - 1)) & 0x1) : false;
899
+ }
900
+ // MOV
901
+ else if (opcode >> 8 === 0b01000110) {
902
+ const Rm = (opcode >> 3) & 0xf;
903
+ const Rd = ((opcode >> 4) & 0x8) | (opcode & 0x7);
904
+ let value = Rm === pcRegister ? this.PC + 2 : this.registers[Rm];
905
+ if (Rd === pcRegister) {
906
+ this.cycles++;
907
+ value &= ~1;
908
+ }
909
+ else if (Rd === spRegister) {
910
+ value &= ~3;
911
+ }
912
+ this.registers[Rd] = value;
913
+ }
914
+ // MOVS
915
+ else if (opcode >> 11 === 0b00100) {
916
+ const value = opcode & 0xff;
917
+ const Rd = (opcode >> 8) & 7;
918
+ this.registers[Rd] = value;
919
+ this.N = !!(value & 0x80000000);
920
+ this.Z = value === 0;
921
+ }
922
+ // MRS
923
+ else if (opcode === 0b1111001111101111 && opcode2 >> 12 == 0b1000) {
924
+ const SYSm = opcode2 & 0xff;
925
+ const Rd = (opcode2 >> 8) & 0xf;
926
+ this.registers[Rd] = this.readSpecialRegister(SYSm);
927
+ this.PC += 2;
928
+ this.cycles += 2;
929
+ }
930
+ // MSR
931
+ else if (opcode >> 4 === 0b111100111000 && opcode2 >> 8 == 0b10001000) {
932
+ const SYSm = opcode2 & 0xff;
933
+ const Rn = opcode & 0xf;
934
+ this.writeSpecialRegister(SYSm, this.registers[Rn]);
935
+ this.PC += 2;
936
+ this.cycles += 2;
937
+ }
938
+ // MULS
939
+ else if (opcode >> 6 === 0b0100001101) {
940
+ const Rn = (opcode >> 3) & 0x7;
941
+ const Rdm = opcode & 0x7;
942
+ const result = Math.imul(this.registers[Rn], this.registers[Rdm]);
943
+ this.registers[Rdm] = result;
944
+ this.N = !!(result & 0x80000000);
945
+ this.Z = (result & 0xffffffff) === 0;
946
+ }
947
+ // MVNS
948
+ else if (opcode >> 6 === 0b0100001111) {
949
+ const Rm = (opcode >> 3) & 7;
950
+ const Rd = opcode & 7;
951
+ const result = ~this.registers[Rm];
952
+ this.registers[Rd] = result;
953
+ this.N = !!(result & 0x80000000);
954
+ this.Z = result === 0;
955
+ }
956
+ // ORRS (Encoding T2)
957
+ else if (opcode >> 6 === 0b0100001100) {
958
+ const Rm = (opcode >> 3) & 0x7;
959
+ const Rdn = opcode & 0x7;
960
+ const result = this.registers[Rdn] | this.registers[Rm];
961
+ this.registers[Rdn] = result;
962
+ this.N = !!(result & 0x80000000);
963
+ this.Z = (result & 0xffffffff) === 0;
964
+ }
965
+ // POP
966
+ else if (opcode >> 9 === 0b1011110) {
967
+ const P = (opcode >> 8) & 1;
968
+ let address = this.SP;
969
+ for (let i = 0; i <= 7; i++) {
970
+ if (opcode & (1 << i)) {
971
+ this.registers[i] = this.readUint32(address);
972
+ address += 4;
973
+ this.cycles++;
974
+ }
975
+ }
976
+ if (P) {
977
+ this.SP = address + 4;
978
+ this.BXWritePC(this.readUint32(address));
979
+ this.cycles += 2;
980
+ }
981
+ else {
982
+ this.SP = address;
983
+ }
984
+ }
985
+ // PUSH
986
+ else if (opcode >> 9 === 0b1011010) {
987
+ let bitCount = 0;
988
+ for (let i = 0; i <= 8; i++) {
989
+ if (opcode & (1 << i)) {
990
+ bitCount++;
991
+ }
992
+ }
993
+ let address = this.SP - 4 * bitCount;
994
+ for (let i = 0; i <= 7; i++) {
995
+ if (opcode & (1 << i)) {
996
+ this.writeUint32(address, this.registers[i]);
997
+ this.cycles++;
998
+ address += 4;
999
+ }
1000
+ }
1001
+ if (opcode & (1 << 8)) {
1002
+ this.writeUint32(address, this.registers[14]);
1003
+ }
1004
+ this.SP -= 4 * bitCount;
1005
+ }
1006
+ // REV
1007
+ else if (opcode >> 6 === 0b1011101000) {
1008
+ const Rm = (opcode >> 3) & 0x7;
1009
+ const Rd = opcode & 0x7;
1010
+ const input = this.registers[Rm];
1011
+ this.registers[Rd] =
1012
+ ((input & 0xff) << 24) |
1013
+ (((input >> 8) & 0xff) << 16) |
1014
+ (((input >> 16) & 0xff) << 8) |
1015
+ ((input >> 24) & 0xff);
1016
+ }
1017
+ // REV16
1018
+ else if (opcode >> 6 === 0b1011101001) {
1019
+ const Rm = (opcode >> 3) & 0x7;
1020
+ const Rd = opcode & 0x7;
1021
+ const input = this.registers[Rm];
1022
+ this.registers[Rd] =
1023
+ (((input >> 16) & 0xff) << 24) |
1024
+ (((input >> 24) & 0xff) << 16) |
1025
+ ((input & 0xff) << 8) |
1026
+ ((input >> 8) & 0xff);
1027
+ }
1028
+ // REVSH
1029
+ else if (opcode >> 6 === 0b1011101011) {
1030
+ const Rm = (opcode >> 3) & 0x7;
1031
+ const Rd = opcode & 0x7;
1032
+ const input = this.registers[Rm];
1033
+ this.registers[Rd] = signExtend16(((input & 0xff) << 8) | ((input >> 8) & 0xff));
1034
+ }
1035
+ // ROR
1036
+ else if (opcode >> 6 === 0b0100000111) {
1037
+ const Rm = (opcode >> 3) & 0x7;
1038
+ const Rdn = opcode & 0x7;
1039
+ const input = this.registers[Rdn];
1040
+ const shift = (this.registers[Rm] & 0xff) % 32;
1041
+ const result = (input >>> shift) | (input << (32 - shift));
1042
+ this.registers[Rdn] = result;
1043
+ this.N = !!(result & 0x80000000);
1044
+ this.Z = result === 0;
1045
+ this.C = !!(result & 0x80000000);
1046
+ }
1047
+ // NEGS / RSBS
1048
+ else if (opcode >> 6 === 0b0100001001) {
1049
+ const Rn = (opcode >> 3) & 0x7;
1050
+ const Rd = opcode & 0x7;
1051
+ this.registers[Rd] = this.substractUpdateFlags(0, this.registers[Rn]);
1052
+ }
1053
+ // NOP
1054
+ else if (opcode === 0b1011111100000000) {
1055
+ // Do nothing!
1056
+ }
1057
+ // SBCS (Encoding T1)
1058
+ else if (opcode >> 6 === 0b0100000110) {
1059
+ const Rm = (opcode >> 3) & 0x7;
1060
+ const Rdn = opcode & 0x7;
1061
+ this.registers[Rdn] = this.substractUpdateFlags(this.registers[Rdn], this.registers[Rm] + (1 - (this.C ? 1 : 0)));
1062
+ }
1063
+ // SEV
1064
+ else if (opcode === 0b1011111101000000) {
1065
+ this.logger.info(LOG_NAME, 'SEV');
1066
+ }
1067
+ // STMIA
1068
+ else if (opcode >> 11 === 0b11000) {
1069
+ const Rn = (opcode >> 8) & 0x7;
1070
+ const registers = opcode & 0xff;
1071
+ let address = this.registers[Rn];
1072
+ for (let i = 0; i < 8; i++) {
1073
+ if (registers & (1 << i)) {
1074
+ this.writeUint32(address, this.registers[i]);
1075
+ address += 4;
1076
+ this.cycles++;
1077
+ }
1078
+ }
1079
+ // Write back
1080
+ if (!(registers & (1 << Rn))) {
1081
+ this.registers[Rn] = address;
1082
+ }
1083
+ }
1084
+ // STR (immediate)
1085
+ else if (opcode >> 11 === 0b01100) {
1086
+ const imm5 = ((opcode >> 6) & 0x1f) << 2;
1087
+ const Rn = (opcode >> 3) & 0x7;
1088
+ const Rt = opcode & 0x7;
1089
+ const address = this.registers[Rn] + imm5;
1090
+ this.cycles += this.cyclesIO(address, true);
1091
+ this.writeUint32(address, this.registers[Rt]);
1092
+ }
1093
+ // STR (sp + immediate)
1094
+ else if (opcode >> 11 === 0b10010) {
1095
+ const Rt = (opcode >> 8) & 0x7;
1096
+ const imm8 = opcode & 0xff;
1097
+ const address = this.SP + (imm8 << 2);
1098
+ this.cycles += this.cyclesIO(address, true);
1099
+ this.writeUint32(address, this.registers[Rt]);
1100
+ }
1101
+ // STR (register)
1102
+ else if (opcode >> 9 === 0b0101000) {
1103
+ const Rm = (opcode >> 6) & 0x7;
1104
+ const Rn = (opcode >> 3) & 0x7;
1105
+ const Rt = opcode & 0x7;
1106
+ const address = this.registers[Rm] + this.registers[Rn];
1107
+ this.cycles += this.cyclesIO(address, true);
1108
+ this.writeUint32(address, this.registers[Rt]);
1109
+ }
1110
+ // STRB (immediate)
1111
+ else if (opcode >> 11 === 0b01110) {
1112
+ const imm5 = (opcode >> 6) & 0x1f;
1113
+ const Rn = (opcode >> 3) & 0x7;
1114
+ const Rt = opcode & 0x7;
1115
+ const address = this.registers[Rn] + imm5;
1116
+ this.cycles += this.cyclesIO(address, true);
1117
+ this.writeUint8(address, this.registers[Rt]);
1118
+ }
1119
+ // STRB (register)
1120
+ else if (opcode >> 9 === 0b0101010) {
1121
+ const Rm = (opcode >> 6) & 0x7;
1122
+ const Rn = (opcode >> 3) & 0x7;
1123
+ const Rt = opcode & 0x7;
1124
+ const address = this.registers[Rm] + this.registers[Rn];
1125
+ this.cycles += this.cyclesIO(address, true);
1126
+ this.writeUint8(address, this.registers[Rt]);
1127
+ }
1128
+ // STRH (immediate)
1129
+ else if (opcode >> 11 === 0b10000) {
1130
+ const imm5 = ((opcode >> 6) & 0x1f) << 1;
1131
+ const Rn = (opcode >> 3) & 0x7;
1132
+ const Rt = opcode & 0x7;
1133
+ const address = this.registers[Rn] + imm5;
1134
+ this.cycles += this.cyclesIO(address, true);
1135
+ this.writeUint16(address, this.registers[Rt]);
1136
+ }
1137
+ // STRH (register)
1138
+ else if (opcode >> 9 === 0b0101001) {
1139
+ const Rm = (opcode >> 6) & 0x7;
1140
+ const Rn = (opcode >> 3) & 0x7;
1141
+ const Rt = opcode & 0x7;
1142
+ const address = this.registers[Rm] + this.registers[Rn];
1143
+ this.cycles += this.cyclesIO(address, true);
1144
+ this.writeUint16(address, this.registers[Rt]);
1145
+ }
1146
+ // SUB (SP minus immediate)
1147
+ else if (opcode >> 7 === 0b101100001) {
1148
+ const imm32 = (opcode & 0x7f) << 2;
1149
+ this.SP -= imm32;
1150
+ }
1151
+ // SUBS (Encoding T1)
1152
+ else if (opcode >> 9 === 0b0001111) {
1153
+ const imm3 = (opcode >> 6) & 0x7;
1154
+ const Rn = (opcode >> 3) & 0x7;
1155
+ const Rd = opcode & 0x7;
1156
+ this.registers[Rd] = this.substractUpdateFlags(this.registers[Rn], imm3);
1157
+ }
1158
+ // SUBS (Encoding T2)
1159
+ else if (opcode >> 11 === 0b00111) {
1160
+ const imm8 = opcode & 0xff;
1161
+ const Rdn = (opcode >> 8) & 0x7;
1162
+ this.registers[Rdn] = this.substractUpdateFlags(this.registers[Rdn], imm8);
1163
+ }
1164
+ // SUBS (register)
1165
+ else if (opcode >> 9 === 0b0001101) {
1166
+ const Rm = (opcode >> 6) & 0x7;
1167
+ const Rn = (opcode >> 3) & 0x7;
1168
+ const Rd = opcode & 0x7;
1169
+ this.registers[Rd] = this.substractUpdateFlags(this.registers[Rn], this.registers[Rm]);
1170
+ }
1171
+ // SVC
1172
+ else if (opcode >> 8 === 0b11011111) {
1173
+ this.pendingSVCall = true;
1174
+ this.interruptsUpdated = true;
1175
+ }
1176
+ // SXTB
1177
+ else if (opcode >> 6 === 0b1011001001) {
1178
+ const Rm = (opcode >> 3) & 0x7;
1179
+ const Rd = opcode & 0x7;
1180
+ this.registers[Rd] = signExtend8(this.registers[Rm]);
1181
+ }
1182
+ // SXTH
1183
+ else if (opcode >> 6 === 0b1011001000) {
1184
+ const Rm = (opcode >> 3) & 0x7;
1185
+ const Rd = opcode & 0x7;
1186
+ this.registers[Rd] = signExtend16(this.registers[Rm]);
1187
+ }
1188
+ // TST
1189
+ else if (opcode >> 6 == 0b0100001000) {
1190
+ const Rm = (opcode >> 3) & 0x7;
1191
+ const Rn = opcode & 0x7;
1192
+ const result = this.registers[Rn] & this.registers[Rm];
1193
+ this.N = !!(result & 0x80000000);
1194
+ this.Z = result === 0;
1195
+ }
1196
+ // UDF
1197
+ else if (opcode >> 8 == 0b11011110) {
1198
+ const imm8 = opcode & 0xff;
1199
+ this.breakRewind = 2;
1200
+ this.rp2040.onBreak(imm8);
1201
+ }
1202
+ // UDF (Encoding T2)
1203
+ else if (opcode >> 4 === 0b111101111111 && opcode2 >> 12 === 0b1010) {
1204
+ const imm4 = opcode & 0xf;
1205
+ const imm12 = opcode2 & 0xfff;
1206
+ this.breakRewind = 4;
1207
+ this.rp2040.onBreak((imm4 << 12) | imm12);
1208
+ this.PC += 2;
1209
+ }
1210
+ // UXTB
1211
+ else if (opcode >> 6 == 0b1011001011) {
1212
+ const Rm = (opcode >> 3) & 0x7;
1213
+ const Rd = opcode & 0x7;
1214
+ this.registers[Rd] = this.registers[Rm] & 0xff;
1215
+ }
1216
+ // UXTH
1217
+ else if (opcode >> 6 == 0b1011001010) {
1218
+ const Rm = (opcode >> 3) & 0x7;
1219
+ const Rd = opcode & 0x7;
1220
+ this.registers[Rd] = this.registers[Rm] & 0xffff;
1221
+ }
1222
+ // WFE
1223
+ else if (opcode === 0b1011111100100000) {
1224
+ this.cycles++;
1225
+ if (this.eventRegistered) {
1226
+ this.eventRegistered = false;
1227
+ }
1228
+ else {
1229
+ this.waiting = true;
1230
+ }
1231
+ }
1232
+ // WFI
1233
+ else if (opcode === 0b1011111100110000) {
1234
+ this.cycles++;
1235
+ this.waiting = true;
1236
+ }
1237
+ // YIELD
1238
+ else if (opcode === 0b1011111100010000) {
1239
+ // do nothing for now. Wait for event!
1240
+ this.logger.info(LOG_NAME, 'Yield');
1241
+ }
1242
+ else {
1243
+ this.logger.warn(LOG_NAME, `Warning: Instruction at ${opcodePC.toString(16)} is not implemented yet!`);
1244
+ this.logger.warn(LOG_NAME, `Opcode: 0x${opcode.toString(16)} (0x${opcode2.toString(16)})`);
1245
+ }
1246
+ }
1247
+ }