ac6502 1.0.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 +261 -0
- package/dist/components/CPU.js +1170 -0
- package/dist/components/CPU.js.map +1 -0
- package/dist/components/Cart.js +23 -0
- package/dist/components/Cart.js.map +1 -0
- package/dist/components/IO/Empty.js +19 -0
- package/dist/components/IO/Empty.js.map +1 -0
- package/dist/components/IO/GPIOAttachments/GPIOAttachment.js +71 -0
- package/dist/components/IO/GPIOAttachments/GPIOAttachment.js.map +1 -0
- package/dist/components/IO/GPIOAttachments/GPIOJoystickAttachment.js +90 -0
- package/dist/components/IO/GPIOAttachments/GPIOJoystickAttachment.js.map +1 -0
- package/dist/components/IO/GPIOAttachments/GPIOKeyboardEncoderAttachment.js +489 -0
- package/dist/components/IO/GPIOAttachments/GPIOKeyboardEncoderAttachment.js.map +1 -0
- package/dist/components/IO/GPIOAttachments/GPIOKeyboardMatrixAttachment.js +274 -0
- package/dist/components/IO/GPIOAttachments/GPIOKeyboardMatrixAttachment.js.map +1 -0
- package/dist/components/IO/GPIOCard.js +597 -0
- package/dist/components/IO/GPIOCard.js.map +1 -0
- package/dist/components/IO/InputBoard.js +19 -0
- package/dist/components/IO/InputBoard.js.map +1 -0
- package/dist/components/IO/LCDCard.js +19 -0
- package/dist/components/IO/LCDCard.js.map +1 -0
- package/dist/components/IO/RAMCard.js +63 -0
- package/dist/components/IO/RAMCard.js.map +1 -0
- package/dist/components/IO/RTCCard.js +483 -0
- package/dist/components/IO/RTCCard.js.map +1 -0
- package/dist/components/IO/SerialCard.js +282 -0
- package/dist/components/IO/SerialCard.js.map +1 -0
- package/dist/components/IO/SoundCard.js +620 -0
- package/dist/components/IO/SoundCard.js.map +1 -0
- package/dist/components/IO/StorageCard.js +428 -0
- package/dist/components/IO/StorageCard.js.map +1 -0
- package/dist/components/IO/VGACard.js +9 -0
- package/dist/components/IO/VGACard.js.map +1 -0
- package/dist/components/IO/VideoCard.js +623 -0
- package/dist/components/IO/VideoCard.js.map +1 -0
- package/dist/components/IO.js +3 -0
- package/dist/components/IO.js.map +1 -0
- package/dist/components/Machine.js +310 -0
- package/dist/components/Machine.js.map +1 -0
- package/dist/components/RAM.js +24 -0
- package/dist/components/RAM.js.map +1 -0
- package/dist/components/ROM.js +23 -0
- package/dist/components/ROM.js.map +1 -0
- package/dist/index.js +441 -0
- package/dist/index.js.map +1 -0
- package/dist/tests/CPU.test.js +1626 -0
- package/dist/tests/CPU.test.js.map +1 -0
- package/dist/tests/Cart.test.js +119 -0
- package/dist/tests/Cart.test.js.map +1 -0
- package/dist/tests/IO/GPIOAttachments/GPIOAttachment.test.js +339 -0
- package/dist/tests/IO/GPIOAttachments/GPIOAttachment.test.js.map +1 -0
- package/dist/tests/IO/GPIOAttachments/GPIOJoystickAttachment.test.js +126 -0
- package/dist/tests/IO/GPIOAttachments/GPIOJoystickAttachment.test.js.map +1 -0
- package/dist/tests/IO/GPIOAttachments/GPIOKeyboardEncoderAttachment.test.js +779 -0
- package/dist/tests/IO/GPIOAttachments/GPIOKeyboardEncoderAttachment.test.js.map +1 -0
- package/dist/tests/IO/GPIOAttachments/GPIOKeyboardMatrixAttachment.test.js +355 -0
- package/dist/tests/IO/GPIOAttachments/GPIOKeyboardMatrixAttachment.test.js.map +1 -0
- package/dist/tests/IO/GPIOCard.test.js +503 -0
- package/dist/tests/IO/GPIOCard.test.js.map +1 -0
- package/dist/tests/IO/RAMCard.test.js +229 -0
- package/dist/tests/IO/RAMCard.test.js.map +1 -0
- package/dist/tests/IO/RTCCard.test.js +177 -0
- package/dist/tests/IO/RTCCard.test.js.map +1 -0
- package/dist/tests/IO/SerialCard.test.js +423 -0
- package/dist/tests/IO/SerialCard.test.js.map +1 -0
- package/dist/tests/IO/SoundCard.test.js +528 -0
- package/dist/tests/IO/SoundCard.test.js.map +1 -0
- package/dist/tests/IO/StorageCard.test.js +647 -0
- package/dist/tests/IO/StorageCard.test.js.map +1 -0
- package/dist/tests/IO/VideoCard.test.js +549 -0
- package/dist/tests/IO/VideoCard.test.js.map +1 -0
- package/dist/tests/Machine.test.js +383 -0
- package/dist/tests/Machine.test.js.map +1 -0
- package/dist/tests/RAM.test.js +160 -0
- package/dist/tests/RAM.test.js.map +1 -0
- package/dist/tests/ROM.test.js +123 -0
- package/dist/tests/ROM.test.js.map +1 -0
- package/jest.config.cjs +9 -0
- package/package.json +43 -0
- package/src/components/CPU.ts +1371 -0
- package/src/components/Cart.ts +20 -0
- package/src/components/IO/GPIOAttachments/GPIOAttachment.ts +189 -0
- package/src/components/IO/GPIOAttachments/GPIOJoystickAttachment.ts +99 -0
- package/src/components/IO/GPIOAttachments/GPIOKeyboardEncoderAttachment.ts +465 -0
- package/src/components/IO/GPIOAttachments/GPIOKeyboardMatrixAttachment.ts +287 -0
- package/src/components/IO/GPIOCard.ts +677 -0
- package/src/components/IO/RAMCard.ts +68 -0
- package/src/components/IO/RTCCard.ts +518 -0
- package/src/components/IO/SerialCard.ts +335 -0
- package/src/components/IO/SoundCard.ts +711 -0
- package/src/components/IO/StorageCard.ts +473 -0
- package/src/components/IO/VideoCard.ts +730 -0
- package/src/components/IO.ts +11 -0
- package/src/components/Machine.ts +364 -0
- package/src/components/RAM.ts +23 -0
- package/src/components/ROM.ts +19 -0
- package/src/index.ts +474 -0
- package/src/tests/CPU.test.ts +2045 -0
- package/src/tests/Cart.test.ts +149 -0
- package/src/tests/IO/GPIOAttachments/GPIOAttachment.test.ts +413 -0
- package/src/tests/IO/GPIOAttachments/GPIOJoystickAttachment.test.ts +147 -0
- package/src/tests/IO/GPIOAttachments/GPIOKeyboardEncoderAttachment.test.ts +961 -0
- package/src/tests/IO/GPIOAttachments/GPIOKeyboardMatrixAttachment.test.ts +449 -0
- package/src/tests/IO/GPIOCard.test.ts +644 -0
- package/src/tests/IO/RAMCard.test.ts +284 -0
- package/src/tests/IO/RTCCard.test.ts +222 -0
- package/src/tests/IO/SerialCard.test.ts +530 -0
- package/src/tests/IO/SoundCard.test.ts +659 -0
- package/src/tests/IO/StorageCard.test.ts +787 -0
- package/src/tests/IO/VideoCard.test.ts +668 -0
- package/src/tests/Machine.test.ts +437 -0
- package/src/tests/RAM.test.ts +196 -0
- package/src/tests/ROM.test.ts +154 -0
- package/tsconfig.json +12 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export class Cart {
|
|
2
|
+
|
|
3
|
+
static START: number = 0x8000
|
|
4
|
+
static END: number = 0xFFFF
|
|
5
|
+
static CODE: number = 0xC000
|
|
6
|
+
static SIZE: number = Cart.END - Cart.START + 1
|
|
7
|
+
|
|
8
|
+
data: number[] = [...Array(Cart.SIZE)].fill(0x00)
|
|
9
|
+
|
|
10
|
+
read(address: number): number {
|
|
11
|
+
return this.data[address]
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
load(data: number[]): void {
|
|
15
|
+
if (data.length != Cart.SIZE) { return }
|
|
16
|
+
|
|
17
|
+
this.data = data
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
}
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interface for devices that can be attached to GPIO ports
|
|
3
|
+
*/
|
|
4
|
+
export interface GPIOAttachment {
|
|
5
|
+
/**
|
|
6
|
+
* Reset the attachment to its initial state
|
|
7
|
+
*/
|
|
8
|
+
reset(): void
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Update the attachment state based on CPU clock ticks
|
|
12
|
+
* @param cpuFrequency - The CPU frequency in Hz
|
|
13
|
+
*/
|
|
14
|
+
tick(cpuFrequency: number): void
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Read data from Port A
|
|
18
|
+
* @param ddr - Data Direction Register value
|
|
19
|
+
* @param or - Output Register value
|
|
20
|
+
* @returns The data to be read from the port
|
|
21
|
+
*/
|
|
22
|
+
readPortA(ddr: number, or: number): number
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Read data from Port B
|
|
26
|
+
* @param ddr - Data Direction Register value
|
|
27
|
+
* @param or - Output Register value
|
|
28
|
+
* @returns The data to be read from the port
|
|
29
|
+
*/
|
|
30
|
+
readPortB(ddr: number, or: number): number
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Write data to Port A
|
|
34
|
+
* @param value - The value being written
|
|
35
|
+
* @param ddr - Data Direction Register value
|
|
36
|
+
*/
|
|
37
|
+
writePortA(value: number, ddr: number): void
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Write data to Port B
|
|
41
|
+
* @param value - The value being written
|
|
42
|
+
* @param ddr - Data Direction Register value
|
|
43
|
+
*/
|
|
44
|
+
writePortB(value: number, ddr: number): void
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Check if the attachment is enabled
|
|
48
|
+
* @returns true if enabled, false otherwise
|
|
49
|
+
*/
|
|
50
|
+
isEnabled(): boolean
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Get the priority of this attachment (lower values = higher priority)
|
|
54
|
+
* @returns The priority value
|
|
55
|
+
*/
|
|
56
|
+
getPriority(): number
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Clear interrupt flags
|
|
60
|
+
* @param ca1 - Clear CA1 interrupt
|
|
61
|
+
* @param ca2 - Clear CA2 interrupt
|
|
62
|
+
* @param cb1 - Clear CB1 interrupt
|
|
63
|
+
* @param cb2 - Clear CB2 interrupt
|
|
64
|
+
*/
|
|
65
|
+
clearInterrupts(ca1: boolean, ca2: boolean, cb1: boolean, cb2: boolean): void
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Update control line states
|
|
69
|
+
* @param ca1 - CA1 control line state
|
|
70
|
+
* @param ca2 - CA2 control line state
|
|
71
|
+
* @param cb1 - CB1 control line state
|
|
72
|
+
* @param cb2 - CB2 control line state
|
|
73
|
+
*/
|
|
74
|
+
updateControlLines(ca1: boolean, ca2: boolean, cb1: boolean, cb2: boolean): void
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Check if CA1 interrupt is pending
|
|
78
|
+
* @returns true if interrupt is pending
|
|
79
|
+
*/
|
|
80
|
+
hasCA1Interrupt(): boolean
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Check if CA2 interrupt is pending
|
|
84
|
+
* @returns true if interrupt is pending
|
|
85
|
+
*/
|
|
86
|
+
hasCA2Interrupt(): boolean
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Check if CB1 interrupt is pending
|
|
90
|
+
* @returns true if interrupt is pending
|
|
91
|
+
*/
|
|
92
|
+
hasCB1Interrupt(): boolean
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Check if CB2 interrupt is pending
|
|
96
|
+
* @returns true if interrupt is pending
|
|
97
|
+
*/
|
|
98
|
+
hasCB2Interrupt(): boolean
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Base abstract class for GPIO attachments with common functionality
|
|
103
|
+
*/
|
|
104
|
+
export abstract class GPIOAttachmentBase implements GPIOAttachment {
|
|
105
|
+
protected priority: number
|
|
106
|
+
protected enabled: boolean
|
|
107
|
+
protected ca1Interrupt: boolean
|
|
108
|
+
protected ca2Interrupt: boolean
|
|
109
|
+
protected cb1Interrupt: boolean
|
|
110
|
+
protected cb2Interrupt: boolean
|
|
111
|
+
|
|
112
|
+
constructor(
|
|
113
|
+
priority: number,
|
|
114
|
+
ca1Interrupt: boolean = false,
|
|
115
|
+
ca2Interrupt: boolean = false,
|
|
116
|
+
cb1Interrupt: boolean = false,
|
|
117
|
+
cb2Interrupt: boolean = false
|
|
118
|
+
) {
|
|
119
|
+
this.priority = priority
|
|
120
|
+
this.enabled = true
|
|
121
|
+
this.ca1Interrupt = ca1Interrupt
|
|
122
|
+
this.ca2Interrupt = ca2Interrupt
|
|
123
|
+
this.cb1Interrupt = cb1Interrupt
|
|
124
|
+
this.cb2Interrupt = cb2Interrupt
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
reset(): void {
|
|
128
|
+
this.enabled = true
|
|
129
|
+
this.ca1Interrupt = false
|
|
130
|
+
this.ca2Interrupt = false
|
|
131
|
+
this.cb1Interrupt = false
|
|
132
|
+
this.cb2Interrupt = false
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
tick(cpuFrequency: number): void {
|
|
136
|
+
// Default: no action
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
readPortA(ddr: number, or: number): number {
|
|
140
|
+
return 0xFF
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
readPortB(ddr: number, or: number): number {
|
|
144
|
+
return 0xFF
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
writePortA(value: number, ddr: number): void {
|
|
148
|
+
// Default: no action
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
writePortB(value: number, ddr: number): void {
|
|
152
|
+
// Default: no action
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
isEnabled(): boolean {
|
|
156
|
+
return this.enabled
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
getPriority(): number {
|
|
160
|
+
return this.priority
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
clearInterrupts(ca1: boolean, ca2: boolean, cb1: boolean, cb2: boolean): void {
|
|
164
|
+
if (ca1) this.ca1Interrupt = false
|
|
165
|
+
if (ca2) this.ca2Interrupt = false
|
|
166
|
+
if (cb1) this.cb1Interrupt = false
|
|
167
|
+
if (cb2) this.cb2Interrupt = false
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
updateControlLines(ca1: boolean, ca2: boolean, cb1: boolean, cb2: boolean): void {
|
|
171
|
+
// Default: no action
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
hasCA1Interrupt(): boolean {
|
|
175
|
+
return this.ca1Interrupt
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
hasCA2Interrupt(): boolean {
|
|
179
|
+
return this.ca2Interrupt
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
hasCB1Interrupt(): boolean {
|
|
183
|
+
return this.cb1Interrupt
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
hasCB2Interrupt(): boolean {
|
|
187
|
+
return this.cb2Interrupt
|
|
188
|
+
}
|
|
189
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { GPIOAttachmentBase } from './GPIOAttachment'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* GPIOJoystickAttachment - Emulates a joystick/gamepad connected to GPIO port
|
|
5
|
+
*
|
|
6
|
+
* Buttons are active-low (0 = pressed, 1 = released)
|
|
7
|
+
* Can be attached to either Port A or Port B
|
|
8
|
+
*/
|
|
9
|
+
export class GPIOJoystickAttachment extends GPIOAttachmentBase {
|
|
10
|
+
// Joystick button bit masks
|
|
11
|
+
static readonly BUTTON_UP = 0x01
|
|
12
|
+
static readonly BUTTON_DOWN = 0x02
|
|
13
|
+
static readonly BUTTON_LEFT = 0x04
|
|
14
|
+
static readonly BUTTON_RIGHT = 0x08
|
|
15
|
+
static readonly BUTTON_A = 0x10
|
|
16
|
+
static readonly BUTTON_B = 0x20
|
|
17
|
+
static readonly BUTTON_SELECT = 0x40
|
|
18
|
+
static readonly BUTTON_START = 0x80
|
|
19
|
+
|
|
20
|
+
private buttonState: number
|
|
21
|
+
private attachedToPortA: boolean
|
|
22
|
+
|
|
23
|
+
constructor(attachToPortA: boolean = true, priority: number = 0) {
|
|
24
|
+
// Call parent constructor with priority and no control line interrupts
|
|
25
|
+
super(priority, false, false, false, false)
|
|
26
|
+
this.attachedToPortA = attachToPortA
|
|
27
|
+
this.buttonState = 0x00
|
|
28
|
+
this.reset()
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
reset(): void {
|
|
32
|
+
super.reset()
|
|
33
|
+
this.buttonState = 0x00
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
readPortA(ddr: number, or: number): number {
|
|
37
|
+
if (this.attachedToPortA) {
|
|
38
|
+
// Return inverted button state (active-low)
|
|
39
|
+
return (~this.buttonState) & 0xFF
|
|
40
|
+
}
|
|
41
|
+
return 0xFF
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
readPortB(ddr: number, or: number): number {
|
|
45
|
+
if (!this.attachedToPortA) {
|
|
46
|
+
// Return inverted button state (active-low)
|
|
47
|
+
return (~this.buttonState) & 0xFF
|
|
48
|
+
}
|
|
49
|
+
return 0xFF
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Update the joystick button state
|
|
54
|
+
* @param buttons - Button state byte (1 = pressed, 0 = released)
|
|
55
|
+
*/
|
|
56
|
+
updateJoystick(buttons: number): void {
|
|
57
|
+
this.buttonState = buttons & 0xFF
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Get the current button state
|
|
62
|
+
* @returns The button state byte
|
|
63
|
+
*/
|
|
64
|
+
getButtonState(): number {
|
|
65
|
+
return this.buttonState
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Check if a specific button is pressed
|
|
70
|
+
* @param button - Button bit mask to check
|
|
71
|
+
* @returns true if button is pressed
|
|
72
|
+
*/
|
|
73
|
+
isButtonPressed(button: number): boolean {
|
|
74
|
+
return (this.buttonState & button) !== 0
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Press a button (set its bit)
|
|
79
|
+
* @param button - Button bit mask to press
|
|
80
|
+
*/
|
|
81
|
+
pressButton(button: number): void {
|
|
82
|
+
this.buttonState |= button
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Release a button (clear its bit)
|
|
87
|
+
* @param button - Button bit mask to release
|
|
88
|
+
*/
|
|
89
|
+
releaseButton(button: number): void {
|
|
90
|
+
this.buttonState &= ~button
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Clear all button presses
|
|
95
|
+
*/
|
|
96
|
+
releaseAllButtons(): void {
|
|
97
|
+
this.buttonState = 0x00
|
|
98
|
+
}
|
|
99
|
+
}
|