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