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.
Files changed (115) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +261 -0
  3. package/dist/components/CPU.js +1170 -0
  4. package/dist/components/CPU.js.map +1 -0
  5. package/dist/components/Cart.js +23 -0
  6. package/dist/components/Cart.js.map +1 -0
  7. package/dist/components/IO/Empty.js +19 -0
  8. package/dist/components/IO/Empty.js.map +1 -0
  9. package/dist/components/IO/GPIOAttachments/GPIOAttachment.js +71 -0
  10. package/dist/components/IO/GPIOAttachments/GPIOAttachment.js.map +1 -0
  11. package/dist/components/IO/GPIOAttachments/GPIOJoystickAttachment.js +90 -0
  12. package/dist/components/IO/GPIOAttachments/GPIOJoystickAttachment.js.map +1 -0
  13. package/dist/components/IO/GPIOAttachments/GPIOKeyboardEncoderAttachment.js +489 -0
  14. package/dist/components/IO/GPIOAttachments/GPIOKeyboardEncoderAttachment.js.map +1 -0
  15. package/dist/components/IO/GPIOAttachments/GPIOKeyboardMatrixAttachment.js +274 -0
  16. package/dist/components/IO/GPIOAttachments/GPIOKeyboardMatrixAttachment.js.map +1 -0
  17. package/dist/components/IO/GPIOCard.js +597 -0
  18. package/dist/components/IO/GPIOCard.js.map +1 -0
  19. package/dist/components/IO/InputBoard.js +19 -0
  20. package/dist/components/IO/InputBoard.js.map +1 -0
  21. package/dist/components/IO/LCDCard.js +19 -0
  22. package/dist/components/IO/LCDCard.js.map +1 -0
  23. package/dist/components/IO/RAMCard.js +63 -0
  24. package/dist/components/IO/RAMCard.js.map +1 -0
  25. package/dist/components/IO/RTCCard.js +483 -0
  26. package/dist/components/IO/RTCCard.js.map +1 -0
  27. package/dist/components/IO/SerialCard.js +282 -0
  28. package/dist/components/IO/SerialCard.js.map +1 -0
  29. package/dist/components/IO/SoundCard.js +620 -0
  30. package/dist/components/IO/SoundCard.js.map +1 -0
  31. package/dist/components/IO/StorageCard.js +428 -0
  32. package/dist/components/IO/StorageCard.js.map +1 -0
  33. package/dist/components/IO/VGACard.js +9 -0
  34. package/dist/components/IO/VGACard.js.map +1 -0
  35. package/dist/components/IO/VideoCard.js +623 -0
  36. package/dist/components/IO/VideoCard.js.map +1 -0
  37. package/dist/components/IO.js +3 -0
  38. package/dist/components/IO.js.map +1 -0
  39. package/dist/components/Machine.js +310 -0
  40. package/dist/components/Machine.js.map +1 -0
  41. package/dist/components/RAM.js +24 -0
  42. package/dist/components/RAM.js.map +1 -0
  43. package/dist/components/ROM.js +23 -0
  44. package/dist/components/ROM.js.map +1 -0
  45. package/dist/index.js +441 -0
  46. package/dist/index.js.map +1 -0
  47. package/dist/tests/CPU.test.js +1626 -0
  48. package/dist/tests/CPU.test.js.map +1 -0
  49. package/dist/tests/Cart.test.js +119 -0
  50. package/dist/tests/Cart.test.js.map +1 -0
  51. package/dist/tests/IO/GPIOAttachments/GPIOAttachment.test.js +339 -0
  52. package/dist/tests/IO/GPIOAttachments/GPIOAttachment.test.js.map +1 -0
  53. package/dist/tests/IO/GPIOAttachments/GPIOJoystickAttachment.test.js +126 -0
  54. package/dist/tests/IO/GPIOAttachments/GPIOJoystickAttachment.test.js.map +1 -0
  55. package/dist/tests/IO/GPIOAttachments/GPIOKeyboardEncoderAttachment.test.js +779 -0
  56. package/dist/tests/IO/GPIOAttachments/GPIOKeyboardEncoderAttachment.test.js.map +1 -0
  57. package/dist/tests/IO/GPIOAttachments/GPIOKeyboardMatrixAttachment.test.js +355 -0
  58. package/dist/tests/IO/GPIOAttachments/GPIOKeyboardMatrixAttachment.test.js.map +1 -0
  59. package/dist/tests/IO/GPIOCard.test.js +503 -0
  60. package/dist/tests/IO/GPIOCard.test.js.map +1 -0
  61. package/dist/tests/IO/RAMCard.test.js +229 -0
  62. package/dist/tests/IO/RAMCard.test.js.map +1 -0
  63. package/dist/tests/IO/RTCCard.test.js +177 -0
  64. package/dist/tests/IO/RTCCard.test.js.map +1 -0
  65. package/dist/tests/IO/SerialCard.test.js +423 -0
  66. package/dist/tests/IO/SerialCard.test.js.map +1 -0
  67. package/dist/tests/IO/SoundCard.test.js +528 -0
  68. package/dist/tests/IO/SoundCard.test.js.map +1 -0
  69. package/dist/tests/IO/StorageCard.test.js +647 -0
  70. package/dist/tests/IO/StorageCard.test.js.map +1 -0
  71. package/dist/tests/IO/VideoCard.test.js +549 -0
  72. package/dist/tests/IO/VideoCard.test.js.map +1 -0
  73. package/dist/tests/Machine.test.js +383 -0
  74. package/dist/tests/Machine.test.js.map +1 -0
  75. package/dist/tests/RAM.test.js +160 -0
  76. package/dist/tests/RAM.test.js.map +1 -0
  77. package/dist/tests/ROM.test.js +123 -0
  78. package/dist/tests/ROM.test.js.map +1 -0
  79. package/jest.config.cjs +9 -0
  80. package/package.json +43 -0
  81. package/src/components/CPU.ts +1371 -0
  82. package/src/components/Cart.ts +20 -0
  83. package/src/components/IO/GPIOAttachments/GPIOAttachment.ts +189 -0
  84. package/src/components/IO/GPIOAttachments/GPIOJoystickAttachment.ts +99 -0
  85. package/src/components/IO/GPIOAttachments/GPIOKeyboardEncoderAttachment.ts +465 -0
  86. package/src/components/IO/GPIOAttachments/GPIOKeyboardMatrixAttachment.ts +287 -0
  87. package/src/components/IO/GPIOCard.ts +677 -0
  88. package/src/components/IO/RAMCard.ts +68 -0
  89. package/src/components/IO/RTCCard.ts +518 -0
  90. package/src/components/IO/SerialCard.ts +335 -0
  91. package/src/components/IO/SoundCard.ts +711 -0
  92. package/src/components/IO/StorageCard.ts +473 -0
  93. package/src/components/IO/VideoCard.ts +730 -0
  94. package/src/components/IO.ts +11 -0
  95. package/src/components/Machine.ts +364 -0
  96. package/src/components/RAM.ts +23 -0
  97. package/src/components/ROM.ts +19 -0
  98. package/src/index.ts +474 -0
  99. package/src/tests/CPU.test.ts +2045 -0
  100. package/src/tests/Cart.test.ts +149 -0
  101. package/src/tests/IO/GPIOAttachments/GPIOAttachment.test.ts +413 -0
  102. package/src/tests/IO/GPIOAttachments/GPIOJoystickAttachment.test.ts +147 -0
  103. package/src/tests/IO/GPIOAttachments/GPIOKeyboardEncoderAttachment.test.ts +961 -0
  104. package/src/tests/IO/GPIOAttachments/GPIOKeyboardMatrixAttachment.test.ts +449 -0
  105. package/src/tests/IO/GPIOCard.test.ts +644 -0
  106. package/src/tests/IO/RAMCard.test.ts +284 -0
  107. package/src/tests/IO/RTCCard.test.ts +222 -0
  108. package/src/tests/IO/SerialCard.test.ts +530 -0
  109. package/src/tests/IO/SoundCard.test.ts +659 -0
  110. package/src/tests/IO/StorageCard.test.ts +787 -0
  111. package/src/tests/IO/VideoCard.test.ts +668 -0
  112. package/src/tests/Machine.test.ts +437 -0
  113. package/src/tests/RAM.test.ts +196 -0
  114. package/src/tests/ROM.test.ts +154 -0
  115. 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
+ }