@gba-kit/arm-emulator 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +64 -0
- package/dist/arm-cpu.d.ts +141 -0
- package/dist/arm-cpu.d.ts.map +1 -0
- package/dist/arm-cpu.js +1875 -0
- package/dist/arm-cpu.js.map +1 -0
- package/dist/cpu-snapshot.d.ts +18 -0
- package/dist/cpu-snapshot.d.ts.map +1 -0
- package/dist/cpu-snapshot.js +2 -0
- package/dist/cpu-snapshot.js.map +1 -0
- package/dist/disassembler.d.ts +17 -0
- package/dist/disassembler.d.ts.map +1 -0
- package/dist/disassembler.js +617 -0
- package/dist/disassembler.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/memory.d.ts +42 -0
- package/dist/memory.d.ts.map +1 -0
- package/dist/memory.js +218 -0
- package/dist/memory.js.map +1 -0
- package/dist/types.d.ts +91 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +10 -0
- package/dist/types.js.map +1 -0
- package/dist/utils.d.ts +51 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +126 -0
- package/dist/utils.js.map +1 -0
- package/package.json +56 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Bruno Macabeus
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# @gba-kit/arm-emulator
|
|
2
|
+
|
|
3
|
+
Pure ARM7TDMI CPU emulator supporting both Thumb (16-bit) and ARM (32-bit) instruction sets.
|
|
4
|
+
|
|
5
|
+
> Note: It doesn't include any GBA-specific logic. The CPU accepts a `MemoryBus` interface and an optional SWI handler callback, so it can be embedded in any ARM7TDMI-based system.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @gba-kit/arm-emulator
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
### ARM CPU
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
import { GbaMemory } from '@gba-kit/arm-emulator';
|
|
19
|
+
import { ArmCpu } from '@gba-kit/arm-emulator/arm-cpu';
|
|
20
|
+
|
|
21
|
+
const memory = new GbaMemory();
|
|
22
|
+
const cpu = new ArmCpu(memory, {
|
|
23
|
+
swiHandler: (cpu, swiNumber) => {
|
|
24
|
+
// Platform-specific SWI handling
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
cpu.registers[15] = 0x08000000; // set PC
|
|
29
|
+
cpu.step(); // execute one instruction
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Disassembly
|
|
33
|
+
|
|
34
|
+
```typescript
|
|
35
|
+
import { disassembleArm, disassembleThumb } from '@gba-kit/arm-emulator/disassembler';
|
|
36
|
+
|
|
37
|
+
const mnemonic = disassembleThumb(0x4770, 0x08000000);
|
|
38
|
+
// "bx lr"
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Exports
|
|
42
|
+
|
|
43
|
+
### Main entry (`@gba-kit/arm-emulator`)
|
|
44
|
+
|
|
45
|
+
| Export | Type | Description |
|
|
46
|
+
| --------------------------------- | ----- | ------------------------------- |
|
|
47
|
+
| `GbaMemory` | class | Memory bus with region dispatch |
|
|
48
|
+
| `PC`, `LR`, `SP`, `SENTINEL_ADDR` | const | Register index constants |
|
|
49
|
+
|
|
50
|
+
Types: `CpsrFlags`, `DebugAction`, `DebugHooks`, `ExecutionResult`, `ExternalCall`, `MemoryBus`, `MemoryWrite`, `CpuSnapshot`
|
|
51
|
+
|
|
52
|
+
### Subpath exports
|
|
53
|
+
|
|
54
|
+
| Subpath | Description |
|
|
55
|
+
| ------------------------------------ | -------------------------------------------------------------------- |
|
|
56
|
+
| `@gba-kit/arm-emulator/arm-cpu` | `ArmCpu` class — full ARM7TDMI with mode switching, banked registers |
|
|
57
|
+
| `@gba-kit/arm-emulator/disassembler` | `disassembleArm()`, `disassembleThumb()` functions |
|
|
58
|
+
| `@gba-kit/arm-emulator/cpu-snapshot` | `CpuSnapshot` interface for serializable CPU state |
|
|
59
|
+
|
|
60
|
+
## Testing
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
pnpm test
|
|
64
|
+
```
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ARM7TDMI Full CPU Emulator
|
|
3
|
+
*
|
|
4
|
+
* Supports both ARM (32-bit) and Thumb (16-bit) instruction sets,
|
|
5
|
+
* CPU modes with banked registers, and HLE BIOS calls via SWI.
|
|
6
|
+
*
|
|
7
|
+
* This class is the full-featured CPU for the GBA emulator.
|
|
8
|
+
*
|
|
9
|
+
* References:
|
|
10
|
+
* - ARM7TDMI TRM (DDI0029G): https://ww1.microchip.com/downloads/en/DeviceDoc/DDI0029G_7TDMI_R3_trm.pdf
|
|
11
|
+
* - GBATEK: http://problemkaputt.de/gbatek.htm
|
|
12
|
+
*/
|
|
13
|
+
import type { CpuSnapshot } from './cpu-snapshot.js';
|
|
14
|
+
import type { CpsrFlags, DebugHooks, ExecutionResult, MemoryBus } from './types.js';
|
|
15
|
+
/** CPU mode codes (bits 4-0 of CPSR) */
|
|
16
|
+
export declare const MODE_USR = 16;
|
|
17
|
+
export declare const MODE_FIQ = 17;
|
|
18
|
+
export declare const MODE_IRQ = 18;
|
|
19
|
+
export declare const MODE_SVC = 19;
|
|
20
|
+
export declare const MODE_ABT = 23;
|
|
21
|
+
export declare const MODE_UND = 27;
|
|
22
|
+
export declare const MODE_SYS = 31;
|
|
23
|
+
/**
|
|
24
|
+
* Callback for Software Interrupt (SWI) instructions.
|
|
25
|
+
* Platform-specific: on GBA, the SWI number selects a BIOS function.
|
|
26
|
+
* If not provided, SWI instructions are silently ignored.
|
|
27
|
+
*/
|
|
28
|
+
export type SwiHandler = (cpu: ArmCpu, swiNumber: number) => void;
|
|
29
|
+
/**
|
|
30
|
+
* Full ARM7TDMI CPU supporting ARM and Thumb instruction sets,
|
|
31
|
+
* with CPU modes and banked registers.
|
|
32
|
+
*/
|
|
33
|
+
export declare class ArmCpu {
|
|
34
|
+
#private;
|
|
35
|
+
/** General-purpose registers r0-r15 (current view, mode-dependent) */
|
|
36
|
+
readonly registers: Uint32Array<ArrayBuffer>;
|
|
37
|
+
/**
|
|
38
|
+
* Current Program Status Register (full 32-bit).
|
|
39
|
+
*
|
|
40
|
+
* Bit layout:
|
|
41
|
+
* - 31: N (Negative)
|
|
42
|
+
* - 30: Z (Zero)
|
|
43
|
+
* - 29: C (Carry)
|
|
44
|
+
* - 28: V (Overflow)
|
|
45
|
+
* - 7: I (IRQ disable)
|
|
46
|
+
* - 6: F (FIQ disable)
|
|
47
|
+
* - 5: T (Thumb state: 0=ARM, 1=Thumb)
|
|
48
|
+
* - 4-0: Mode (0x10=USR, 0x11=FIQ, 0x12=IRQ, 0x13=SVC, 0x17=ABT, 0x1B=UND, 0x1F=SYS)
|
|
49
|
+
*/
|
|
50
|
+
cpsr: number;
|
|
51
|
+
/** Memory bus */
|
|
52
|
+
readonly memory: MemoryBus;
|
|
53
|
+
constructor(memory: MemoryBus, options?: {
|
|
54
|
+
hooks?: DebugHooks;
|
|
55
|
+
swiHandler?: SwiHandler;
|
|
56
|
+
});
|
|
57
|
+
/**
|
|
58
|
+
* Set the banked SP for a given mode without switching modes.
|
|
59
|
+
* Used to initialize stack pointers (e.g. GBA BIOS sets IRQ/SVC stacks).
|
|
60
|
+
*/
|
|
61
|
+
setBankedSP(mode: number, value: number): void;
|
|
62
|
+
/** Get condition flags from CPSR as a CpsrFlags object */
|
|
63
|
+
get flags(): CpsrFlags;
|
|
64
|
+
/** Get Negative flag */
|
|
65
|
+
getN(): boolean;
|
|
66
|
+
/** Get Zero flag */
|
|
67
|
+
getZ(): boolean;
|
|
68
|
+
/** Get Carry flag */
|
|
69
|
+
getC(): boolean;
|
|
70
|
+
/** Get Overflow flag */
|
|
71
|
+
getV(): boolean;
|
|
72
|
+
/** Get Thumb state bit */
|
|
73
|
+
getT(): boolean;
|
|
74
|
+
/** Get current CPU mode */
|
|
75
|
+
getMode(): number;
|
|
76
|
+
/** Set Negative flag */
|
|
77
|
+
setN(val: boolean): void;
|
|
78
|
+
/** Set Zero flag */
|
|
79
|
+
setZ(val: boolean): void;
|
|
80
|
+
/** Set Carry flag */
|
|
81
|
+
setC(val: boolean): void;
|
|
82
|
+
/** Set Overflow flag */
|
|
83
|
+
setV(val: boolean): void;
|
|
84
|
+
/** Set Thumb state bit */
|
|
85
|
+
setT(val: boolean): void;
|
|
86
|
+
/** Set all four condition flags at once from an AluResult */
|
|
87
|
+
setFlags(n: boolean, z: boolean, c: boolean, v: boolean): void;
|
|
88
|
+
/** Set NZ flags from a result value, leave C and V unchanged */
|
|
89
|
+
setNZ(result: number): void;
|
|
90
|
+
/** Get the SPSR for the current mode. Returns 0 for USR/SYS (no SPSR). */
|
|
91
|
+
getSPSR(): number;
|
|
92
|
+
/** Set the SPSR for the current mode. No-op for USR/SYS. */
|
|
93
|
+
setSPSR(value: number): void;
|
|
94
|
+
/**
|
|
95
|
+
* Switch CPU mode. Saves banked registers from the old mode
|
|
96
|
+
* and restores them for the new mode.
|
|
97
|
+
*/
|
|
98
|
+
switchMode(newMode: number): void;
|
|
99
|
+
/** Attach or detach debug hooks */
|
|
100
|
+
setDebugHooks(hooks: DebugHooks | undefined): void;
|
|
101
|
+
/** Register a stub for an external function call */
|
|
102
|
+
registerStub(symbolName: string): number;
|
|
103
|
+
/** Serialize to a plain snapshot. */
|
|
104
|
+
serialize(): CpuSnapshot;
|
|
105
|
+
/** Restore from a snapshot. */
|
|
106
|
+
deserialize(snap: CpuSnapshot): void;
|
|
107
|
+
/** Reset CPU state for a new execution */
|
|
108
|
+
resetState(): void;
|
|
109
|
+
/** Check if IRQs are disabled (CPSR I bit set) */
|
|
110
|
+
irqDisabled(): boolean;
|
|
111
|
+
/**
|
|
112
|
+
* Enter IRQ exception.
|
|
113
|
+
*
|
|
114
|
+
* Standard ARM7TDMI exception entry:
|
|
115
|
+
* 1. Save CPSR to SPSR_irq
|
|
116
|
+
* 2. Switch to IRQ mode
|
|
117
|
+
* 3. Set LR_irq to return address (next instruction + 4)
|
|
118
|
+
* 4. Set I bit (disable further IRQs)
|
|
119
|
+
* 5. Clear T bit (enter ARM state)
|
|
120
|
+
* 6. Set PC to IRQ vector (0x00000018)
|
|
121
|
+
*
|
|
122
|
+
* The BIOS stub at 0x18 (installed by Gba.#installBiosStub) handles:
|
|
123
|
+
* - Saving registers to IRQ stack
|
|
124
|
+
* - Calling the user's handler from [0x03007FFC]
|
|
125
|
+
* - Restoring registers and returning from IRQ
|
|
126
|
+
*
|
|
127
|
+
* The BIOS stub at 0x80 handles IE/IF acknowledgment and BIOS IF mirror
|
|
128
|
+
* update before calling the user handler.
|
|
129
|
+
*/
|
|
130
|
+
enterIrq(): void;
|
|
131
|
+
/** Enter Undefined Instruction exception */
|
|
132
|
+
enterUnd(instrAddr: number): void;
|
|
133
|
+
/**
|
|
134
|
+
* Execute one instruction (ARM or Thumb based on T bit).
|
|
135
|
+
* Returns false if halted.
|
|
136
|
+
*/
|
|
137
|
+
step(): boolean;
|
|
138
|
+
/** Run until halt or instruction limit */
|
|
139
|
+
run(maxInstructions: number): ExecutionResult;
|
|
140
|
+
}
|
|
141
|
+
//# sourceMappingURL=arm-cpu.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"arm-cpu.d.ts","sourceRoot":"","sources":["../src/arm-cpu.ts"],"names":[],"mappings":"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"}
|