ac6502 1.0.0 → 1.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/README.md +2 -2
- package/dist/components/IO/EmptyCard.js +17 -0
- package/dist/components/IO/EmptyCard.js.map +1 -0
- package/dist/components/IO/GPIOAttachments/GPIOKeypadAttachment.js +141 -0
- package/dist/components/IO/GPIOAttachments/GPIOKeypadAttachment.js.map +1 -0
- package/dist/components/IO/GPIOAttachments/GPIOLCDAttachment.js +716 -0
- package/dist/components/IO/GPIOAttachments/GPIOLCDAttachment.js.map +1 -0
- package/dist/components/IO/SerialCard.js +4 -4
- package/dist/components/IO/SerialCard.js.map +1 -1
- package/dist/components/Machine.js +84 -45
- package/dist/components/Machine.js.map +1 -1
- package/dist/index.js +175 -52
- package/dist/index.js.map +1 -1
- package/dist/tests/IO/GPIOAttachments/GPIOKeypadAttachment.test.js +323 -0
- package/dist/tests/IO/GPIOAttachments/GPIOKeypadAttachment.test.js.map +1 -0
- package/dist/tests/IO/GPIOAttachments/GPIOLCDAttachment.test.js +627 -0
- package/dist/tests/IO/GPIOAttachments/GPIOLCDAttachment.test.js.map +1 -0
- package/dist/tests/IO/SerialCard.test.js +4 -4
- package/dist/tests/IO/SerialCard.test.js.map +1 -1
- package/dist/tests/Machine.test.js +9 -3
- package/dist/tests/Machine.test.js.map +1 -1
- package/package.json +3 -3
- package/src/components/IO/EmptyCard.ts +16 -0
- package/src/components/IO/GPIOAttachments/GPIOKeypadAttachment.ts +153 -0
- package/src/components/IO/GPIOAttachments/GPIOLCDAttachment.ts +791 -0
- package/src/components/IO/SerialCard.ts +4 -4
- package/src/components/Machine.ts +107 -61
- package/src/index.ts +179 -87
- package/src/tests/IO/GPIOAttachments/GPIOKeypadAttachment.test.ts +389 -0
- package/src/tests/IO/GPIOAttachments/GPIOLCDAttachment.test.ts +795 -0
- package/src/tests/IO/SerialCard.test.ts +4 -4
- package/src/tests/Machine.test.ts +10 -3
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# 6502 Emulator
|
|
2
2
|
|
|
3
|
-
A comprehensive, cycle-accurate emulator for the [A.C. Wright
|
|
3
|
+
A comprehensive, cycle-accurate emulator for the [A.C. Wright 6502](https://github.com/acwright/6502) computer system, built with TypeScript and Node.js.
|
|
4
4
|
|
|
5
5
|
## Overview
|
|
6
6
|
|
|
@@ -258,4 +258,4 @@ A.C. Wright
|
|
|
258
258
|
|
|
259
259
|
## Contributing
|
|
260
260
|
|
|
261
|
-
This project is part of the [A.C. Wright Design 6502](https://github.com/acwright/6502) hardware project. Contributions, issues, and feature requests are welcome!
|
|
261
|
+
This project is part of the [A.C. Wright Design 6502](https://github.com/acwright/6502) hardware project. Contributions, issues, and feature requests are welcome!
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.EmptyCard = void 0;
|
|
4
|
+
class EmptyCard {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.raiseIRQ = () => { };
|
|
7
|
+
this.raiseNMI = () => { };
|
|
8
|
+
}
|
|
9
|
+
read(address) {
|
|
10
|
+
return 0;
|
|
11
|
+
}
|
|
12
|
+
write(address, data) { }
|
|
13
|
+
tick(frequency) { }
|
|
14
|
+
reset(coldStart) { }
|
|
15
|
+
}
|
|
16
|
+
exports.EmptyCard = EmptyCard;
|
|
17
|
+
//# sourceMappingURL=EmptyCard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EmptyCard.js","sourceRoot":"","sources":["../../../src/components/IO/EmptyCard.ts"],"names":[],"mappings":";;;AAEA,MAAa,SAAS;IAAtB;QAEE,aAAQ,GAAG,GAAG,EAAE,GAAE,CAAC,CAAA;QACnB,aAAQ,GAAG,GAAG,EAAE,GAAE,CAAC,CAAA;IAUrB,CAAC;IARC,IAAI,CAAC,OAAe;QAClB,OAAO,CAAC,CAAA;IACV,CAAC;IAED,KAAK,CAAC,OAAe,EAAE,IAAY,IAAS,CAAC;IAC7C,IAAI,CAAC,SAAiB,IAAS,CAAC;IAChC,KAAK,CAAC,SAAkB,IAAS,CAAC;CAEnC;AAbD,8BAaC"}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.GPIOKeypadAttachment = void 0;
|
|
4
|
+
const GPIOAttachment_1 = require("./GPIOAttachment");
|
|
5
|
+
/**
|
|
6
|
+
* USB HID keycode to keypad value mapping
|
|
7
|
+
* Maps USB HID usage IDs to the 5-bit keypad codes ($00-$17) per the 6502 Keypad Mapping table
|
|
8
|
+
*
|
|
9
|
+
* Keypad layout (4 columns × 6 rows = 24 keys):
|
|
10
|
+
* $00 = ◄ $01=1 $02=2 $03=3
|
|
11
|
+
* $04 = 4 $05=5 $06=6 $07=7
|
|
12
|
+
* $08 = 8 $09=9 $0A=0 $0B=►
|
|
13
|
+
* $0C = F $0D=E $0E=D $0F=C
|
|
14
|
+
* $10 = ESC $11=INS $12=PGUP $13=A
|
|
15
|
+
* $14 = ▲/Enter $15=DEL $16=PGDN $17=B
|
|
16
|
+
*/
|
|
17
|
+
const USB_HID_TO_KEYPAD = {
|
|
18
|
+
0x50: 0x00, // Left Arrow → ◄
|
|
19
|
+
0x1E: 0x01, // 1
|
|
20
|
+
0x1F: 0x02, // 2
|
|
21
|
+
0x20: 0x03, // 3
|
|
22
|
+
0x21: 0x04, // 4
|
|
23
|
+
0x22: 0x05, // 5
|
|
24
|
+
0x23: 0x06, // 6
|
|
25
|
+
0x24: 0x07, // 7
|
|
26
|
+
0x25: 0x08, // 8
|
|
27
|
+
0x26: 0x09, // 9
|
|
28
|
+
0x27: 0x0A, // 0
|
|
29
|
+
0x4F: 0x0B, // Right Arrow → ►
|
|
30
|
+
0x09: 0x0C, // f → F
|
|
31
|
+
0x08: 0x0D, // e → E
|
|
32
|
+
0x07: 0x0E, // d → D
|
|
33
|
+
0x06: 0x0F, // c → C
|
|
34
|
+
0x29: 0x10, // Escape → ESC
|
|
35
|
+
0x49: 0x11, // Insert → INS
|
|
36
|
+
0x4B: 0x12, // Page Up → PGUP
|
|
37
|
+
0x04: 0x13, // a → A
|
|
38
|
+
0x52: 0x14, // Up Arrow → ▲
|
|
39
|
+
0x28: 0x14, // Enter → ▲
|
|
40
|
+
0x4C: 0x15, // Delete → DEL
|
|
41
|
+
0x4E: 0x16, // Page Down → PGDN
|
|
42
|
+
0x05: 0x17, // b → B
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* GPIOKeypadAttachment - Emulates a 4×6 matrix keypad with a built-in hardware encoder
|
|
46
|
+
*
|
|
47
|
+
* The encoder converts a key press into a 5-bit code (PA0–PA4) that appears on the GPIO
|
|
48
|
+
* port. Bits 5–7 are never driven by the keypad and always read as 0 when data is present.
|
|
49
|
+
*
|
|
50
|
+
* Behaviour mirrors a typical 74C922-style encoder:
|
|
51
|
+
* - On key press → the 5-bit keypad code is latched and a CA1/CB1 interrupt is asserted
|
|
52
|
+
* - On port read → the latched code is returned on bits 0–4 (bits 5–7 = 0)
|
|
53
|
+
* - clearInterrupts → clears the interrupt and the data-ready latch
|
|
54
|
+
* - Key releases → ignored (encoder only reports on the falling edge of a keypress)
|
|
55
|
+
*
|
|
56
|
+
* The attachment may be wired to either Port A or Port B via the constructor parameter.
|
|
57
|
+
* CA1/CB1 is the DA (Data Available) interrupt line from the 74C922.
|
|
58
|
+
* CA2/CB2 is connected to the 74C922 OE (Output Enable) pin; data is only driven onto the
|
|
59
|
+
* bus when OE is asserted LOW by the 6522.
|
|
60
|
+
*/
|
|
61
|
+
class GPIOKeypadAttachment extends GPIOAttachment_1.GPIOAttachmentBase {
|
|
62
|
+
constructor(attachToPortA = true, priority = 0) {
|
|
63
|
+
super(priority, false, false, false, false);
|
|
64
|
+
this.keypadValue = 0x00;
|
|
65
|
+
this.dataReady = false;
|
|
66
|
+
this.interruptPending = false;
|
|
67
|
+
// OE state: CA2 for Port A, CB2 for Port B. HIGH = output disabled (default).
|
|
68
|
+
this.oeState = true;
|
|
69
|
+
this.attachedToPortA = attachToPortA;
|
|
70
|
+
this.reset();
|
|
71
|
+
}
|
|
72
|
+
reset() {
|
|
73
|
+
super.reset();
|
|
74
|
+
this.keypadValue = 0x00;
|
|
75
|
+
this.dataReady = false;
|
|
76
|
+
this.interruptPending = false;
|
|
77
|
+
this.oeState = true; // OE disabled until explicitly asserted by the 6522
|
|
78
|
+
}
|
|
79
|
+
updateControlLines(ca1, ca2, cb1, cb2) {
|
|
80
|
+
// CA2 controls OE for Port A; CB2 controls OE for Port B.
|
|
81
|
+
// 74C922 OE is active-LOW, so a LOW signal enables the output.
|
|
82
|
+
this.oeState = this.attachedToPortA ? ca2 : cb2;
|
|
83
|
+
}
|
|
84
|
+
readPortA(ddr, or) {
|
|
85
|
+
// Only drive the bus when attached to Port A, OE is asserted (LOW), and data is latched
|
|
86
|
+
if (this.attachedToPortA && !this.oeState && this.dataReady) {
|
|
87
|
+
return this.keypadValue & 0x1F; // bits 0–4 only; bits 5–7 = 0
|
|
88
|
+
}
|
|
89
|
+
return 0xFF; // not driving the bus
|
|
90
|
+
}
|
|
91
|
+
readPortB(ddr, or) {
|
|
92
|
+
// Only drive the bus when attached to Port B, OE is asserted (LOW), and data is latched
|
|
93
|
+
if (!this.attachedToPortA && !this.oeState && this.dataReady) {
|
|
94
|
+
return this.keypadValue & 0x1F; // bits 0–4 only; bits 5–7 = 0
|
|
95
|
+
}
|
|
96
|
+
return 0xFF; // not driving the bus
|
|
97
|
+
}
|
|
98
|
+
hasCA1Interrupt() {
|
|
99
|
+
return this.attachedToPortA && this.interruptPending;
|
|
100
|
+
}
|
|
101
|
+
hasCB1Interrupt() {
|
|
102
|
+
return !this.attachedToPortA && this.interruptPending;
|
|
103
|
+
}
|
|
104
|
+
clearInterrupts(ca1, ca2, cb1, cb2) {
|
|
105
|
+
if ((this.attachedToPortA && ca1) || (!this.attachedToPortA && cb1)) {
|
|
106
|
+
this.interruptPending = false;
|
|
107
|
+
this.dataReady = false;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Notify the attachment of a USB HID key event.
|
|
112
|
+
* Key releases are ignored; only presses generate output on the GPIO port.
|
|
113
|
+
*
|
|
114
|
+
* @param usbHidKeycode - USB HID usage ID for the key
|
|
115
|
+
* @param pressed - true for key-down, false for key-up
|
|
116
|
+
*/
|
|
117
|
+
updateKey(usbHidKeycode, pressed) {
|
|
118
|
+
if (!pressed) {
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
const keypadCode = USB_HID_TO_KEYPAD[usbHidKeycode];
|
|
122
|
+
if (keypadCode === undefined) {
|
|
123
|
+
return; // key is not present on this keypad
|
|
124
|
+
}
|
|
125
|
+
this.keypadValue = keypadCode;
|
|
126
|
+
this.dataReady = true;
|
|
127
|
+
this.interruptPending = true;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Returns the current latched keypad code (bits 0–4) or 0xFF if no data is ready.
|
|
131
|
+
*/
|
|
132
|
+
getCurrentKey() {
|
|
133
|
+
return this.dataReady ? (this.keypadValue & 0x1F) : 0xFF;
|
|
134
|
+
}
|
|
135
|
+
/** Returns true when a key has been pressed and the latch has not yet been cleared. */
|
|
136
|
+
hasDataReady() {
|
|
137
|
+
return this.dataReady;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
exports.GPIOKeypadAttachment = GPIOKeypadAttachment;
|
|
141
|
+
//# sourceMappingURL=GPIOKeypadAttachment.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GPIOKeypadAttachment.js","sourceRoot":"","sources":["../../../../src/components/IO/GPIOAttachments/GPIOKeypadAttachment.ts"],"names":[],"mappings":"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"}
|