ac6502 1.1.1 → 1.3.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/dist/components/CPU.d.ts +162 -0
- package/dist/components/Cart.d.ts +9 -0
- package/dist/components/IO/DevOutputBoard.d.ts +19 -0
- package/dist/components/IO/DevOutputBoard.js +33 -0
- package/dist/components/IO/DevOutputBoard.js.map +1 -0
- package/dist/components/IO/EmptyCard.d.ts +9 -0
- package/dist/components/IO/GPIOAttachments/GPIOAttachment.d.ts +112 -0
- package/dist/components/IO/GPIOAttachments/GPIOJoystickAttachment.d.ts +53 -0
- package/dist/components/IO/GPIOAttachments/GPIOKeyboardEncoderAttachment.d.ts +63 -0
- package/dist/components/IO/GPIOAttachments/GPIOKeyboardMatrixAttachment.d.ts +44 -0
- package/dist/components/IO/GPIOAttachments/GPIOKeypadAttachment.d.ts +47 -0
- package/dist/components/IO/GPIOAttachments/GPIOLCDAttachment.d.ts +110 -0
- package/dist/components/IO/GPIOCard.d.ts +105 -0
- package/dist/components/IO/RAMCard.d.ts +37 -0
- package/dist/components/IO/RTCCard.d.ts +107 -0
- package/dist/components/IO/SerialCard.d.ts +76 -0
- package/dist/components/IO/SoundCard.d.ts +120 -0
- package/dist/components/IO/SoundCard.js +2 -0
- package/dist/components/IO/SoundCard.js.map +1 -1
- package/dist/components/IO/StorageCard.d.ts +74 -0
- package/dist/components/IO/VideoCard.d.ts +141 -0
- package/dist/components/IO/VideoCard.js +19 -12
- package/dist/components/IO/VideoCard.js.map +1 -1
- package/dist/components/IO.d.ts +8 -0
- package/dist/components/Machine.d.ts +66 -0
- package/dist/components/Machine.js +38 -6
- package/dist/components/Machine.js.map +1 -1
- package/dist/components/RAM.d.ts +9 -0
- package/dist/components/ROM.d.ts +9 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +35 -16
- package/dist/index.js.map +1 -1
- package/dist/lib.d.ts +22 -0
- package/dist/lib.js +47 -0
- package/dist/lib.js.map +1 -0
- package/dist/tests/CPU.test.d.ts +1 -0
- package/dist/tests/Cart.test.d.ts +1 -0
- package/dist/tests/IO/GPIOAttachments/GPIOAttachment.test.d.ts +1 -0
- package/dist/tests/IO/GPIOAttachments/GPIOJoystickAttachment.test.d.ts +1 -0
- package/dist/tests/IO/GPIOAttachments/GPIOKeyboardEncoderAttachment.test.d.ts +1 -0
- package/dist/tests/IO/GPIOAttachments/GPIOKeyboardMatrixAttachment.test.d.ts +1 -0
- package/dist/tests/IO/GPIOAttachments/GPIOKeypadAttachment.test.d.ts +1 -0
- package/dist/tests/IO/GPIOAttachments/GPIOLCDAttachment.test.d.ts +1 -0
- package/dist/tests/IO/GPIOCard.test.d.ts +1 -0
- package/dist/tests/IO/RAMCard.test.d.ts +1 -0
- package/dist/tests/IO/RTCCard.test.d.ts +1 -0
- package/dist/tests/IO/SerialCard.test.d.ts +1 -0
- package/dist/tests/IO/SoundCard.test.d.ts +1 -0
- package/dist/tests/IO/StorageCard.test.d.ts +1 -0
- package/dist/tests/IO/VideoCard.test.d.ts +1 -0
- package/dist/tests/Machine.test.d.ts +1 -0
- package/dist/tests/RAM.test.d.ts +1 -0
- package/dist/tests/ROM.test.d.ts +1 -0
- package/package.json +5 -3
- package/src/components/IO/DevOutputBoard.ts +34 -0
- package/src/components/IO/SoundCard.ts +3 -0
- package/src/components/IO/VideoCard.ts +21 -12
- package/src/components/Machine.ts +40 -7
- package/src/index.ts +35 -18
- package/src/lib.ts +27 -0
- package/tsconfig.json +1 -0
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
export interface CPUInstruction {
|
|
2
|
+
name: string;
|
|
3
|
+
cycles: number;
|
|
4
|
+
opcode: () => number;
|
|
5
|
+
addrMode: () => number;
|
|
6
|
+
}
|
|
7
|
+
export declare class CPU {
|
|
8
|
+
static C: number;
|
|
9
|
+
static Z: number;
|
|
10
|
+
static I: number;
|
|
11
|
+
static D: number;
|
|
12
|
+
static B: number;
|
|
13
|
+
static U: number;
|
|
14
|
+
static V: number;
|
|
15
|
+
static N: number;
|
|
16
|
+
private fetched;
|
|
17
|
+
private temp;
|
|
18
|
+
private addrAbs;
|
|
19
|
+
private addrRel;
|
|
20
|
+
private opcode;
|
|
21
|
+
cyclesRem: number;
|
|
22
|
+
cycles: number;
|
|
23
|
+
a: number;
|
|
24
|
+
x: number;
|
|
25
|
+
y: number;
|
|
26
|
+
pc: number;
|
|
27
|
+
sp: number;
|
|
28
|
+
st: number;
|
|
29
|
+
read: (address: number) => number;
|
|
30
|
+
write: (address: number, data: number) => void;
|
|
31
|
+
constructor(read: (address: number) => number, write: (address: number, data: number) => void);
|
|
32
|
+
reset(): void;
|
|
33
|
+
irq(): void;
|
|
34
|
+
nmi(): void;
|
|
35
|
+
tick(): void;
|
|
36
|
+
step(): number;
|
|
37
|
+
private fetch;
|
|
38
|
+
private getFlag;
|
|
39
|
+
private setFlag;
|
|
40
|
+
private incPC;
|
|
41
|
+
private decPC;
|
|
42
|
+
private incSP;
|
|
43
|
+
private decSP;
|
|
44
|
+
private IMP;
|
|
45
|
+
private IMM;
|
|
46
|
+
private ZP0;
|
|
47
|
+
private ZPX;
|
|
48
|
+
private ZPY;
|
|
49
|
+
private REL;
|
|
50
|
+
private ABS;
|
|
51
|
+
private ABX;
|
|
52
|
+
private ABY;
|
|
53
|
+
private IND;
|
|
54
|
+
private IZX;
|
|
55
|
+
private IZY;
|
|
56
|
+
private IAX;
|
|
57
|
+
private ZPR;
|
|
58
|
+
private ADC;
|
|
59
|
+
private AND;
|
|
60
|
+
private ASL;
|
|
61
|
+
private BCC;
|
|
62
|
+
private BCS;
|
|
63
|
+
private BEQ;
|
|
64
|
+
private BIT;
|
|
65
|
+
private BMI;
|
|
66
|
+
private BNE;
|
|
67
|
+
private BPL;
|
|
68
|
+
private BRK;
|
|
69
|
+
private BVC;
|
|
70
|
+
private BVS;
|
|
71
|
+
private CLC;
|
|
72
|
+
private CLD;
|
|
73
|
+
private CLI;
|
|
74
|
+
private CLV;
|
|
75
|
+
private CMP;
|
|
76
|
+
private CPX;
|
|
77
|
+
private CPY;
|
|
78
|
+
private DEC;
|
|
79
|
+
private DEX;
|
|
80
|
+
private DEY;
|
|
81
|
+
private EOR;
|
|
82
|
+
private INC;
|
|
83
|
+
private INX;
|
|
84
|
+
private INY;
|
|
85
|
+
private JMP;
|
|
86
|
+
private JSR;
|
|
87
|
+
private LDA;
|
|
88
|
+
private LDX;
|
|
89
|
+
private LDY;
|
|
90
|
+
private LSR;
|
|
91
|
+
private NOP;
|
|
92
|
+
private ORA;
|
|
93
|
+
private PHA;
|
|
94
|
+
private PHP;
|
|
95
|
+
private PLA;
|
|
96
|
+
private PLP;
|
|
97
|
+
private ROL;
|
|
98
|
+
private ROR;
|
|
99
|
+
private RTI;
|
|
100
|
+
private RTS;
|
|
101
|
+
private SBC;
|
|
102
|
+
private SEC;
|
|
103
|
+
private SED;
|
|
104
|
+
private SEI;
|
|
105
|
+
private STA;
|
|
106
|
+
private STX;
|
|
107
|
+
private STY;
|
|
108
|
+
private TAX;
|
|
109
|
+
private TAY;
|
|
110
|
+
private TSX;
|
|
111
|
+
private TXA;
|
|
112
|
+
private TXS;
|
|
113
|
+
private TYA;
|
|
114
|
+
private BRA;
|
|
115
|
+
private PHX;
|
|
116
|
+
private PHY;
|
|
117
|
+
private PLX;
|
|
118
|
+
private PLY;
|
|
119
|
+
private STZ;
|
|
120
|
+
private TRB;
|
|
121
|
+
private TSB;
|
|
122
|
+
private STP;
|
|
123
|
+
private WAI;
|
|
124
|
+
private BBR;
|
|
125
|
+
private BBR0;
|
|
126
|
+
private BBR1;
|
|
127
|
+
private BBR2;
|
|
128
|
+
private BBR3;
|
|
129
|
+
private BBR4;
|
|
130
|
+
private BBR5;
|
|
131
|
+
private BBR6;
|
|
132
|
+
private BBR7;
|
|
133
|
+
private BBS;
|
|
134
|
+
private BBS0;
|
|
135
|
+
private BBS1;
|
|
136
|
+
private BBS2;
|
|
137
|
+
private BBS3;
|
|
138
|
+
private BBS4;
|
|
139
|
+
private BBS5;
|
|
140
|
+
private BBS6;
|
|
141
|
+
private BBS7;
|
|
142
|
+
private RMB;
|
|
143
|
+
private RMB0;
|
|
144
|
+
private RMB1;
|
|
145
|
+
private RMB2;
|
|
146
|
+
private RMB3;
|
|
147
|
+
private RMB4;
|
|
148
|
+
private RMB5;
|
|
149
|
+
private RMB6;
|
|
150
|
+
private RMB7;
|
|
151
|
+
private SMB;
|
|
152
|
+
private SMB0;
|
|
153
|
+
private SMB1;
|
|
154
|
+
private SMB2;
|
|
155
|
+
private SMB3;
|
|
156
|
+
private SMB4;
|
|
157
|
+
private SMB5;
|
|
158
|
+
private SMB6;
|
|
159
|
+
private SMB7;
|
|
160
|
+
private XXX;
|
|
161
|
+
instructionTable: CPUInstruction[];
|
|
162
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { IO } from '../IO';
|
|
2
|
+
import { VTAC } from 'vtac-terminal';
|
|
3
|
+
/**
|
|
4
|
+
* DevOutputBoard - Development output board using a VTAC terminal controller
|
|
5
|
+
*
|
|
6
|
+
* Register Map:
|
|
7
|
+
* $00: Data / Status Register
|
|
8
|
+
* Write: sends byte to VTAC for processing
|
|
9
|
+
* Read: always returns 0 (bit 7 is a busy flag on the real device; busy is never set here)
|
|
10
|
+
*/
|
|
11
|
+
export declare class DevOutputBoard implements IO {
|
|
12
|
+
raiseIRQ: () => void;
|
|
13
|
+
raiseNMI: () => void;
|
|
14
|
+
readonly vtac: VTAC;
|
|
15
|
+
read(address: number): number;
|
|
16
|
+
write(address: number, data: number): void;
|
|
17
|
+
tick(frequency: number): void;
|
|
18
|
+
reset(coldStart: boolean): void;
|
|
19
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DevOutputBoard = void 0;
|
|
4
|
+
const vtac_terminal_1 = require("vtac-terminal");
|
|
5
|
+
/**
|
|
6
|
+
* DevOutputBoard - Development output board using a VTAC terminal controller
|
|
7
|
+
*
|
|
8
|
+
* Register Map:
|
|
9
|
+
* $00: Data / Status Register
|
|
10
|
+
* Write: sends byte to VTAC for processing
|
|
11
|
+
* Read: always returns 0 (bit 7 is a busy flag on the real device; busy is never set here)
|
|
12
|
+
*/
|
|
13
|
+
class DevOutputBoard {
|
|
14
|
+
constructor() {
|
|
15
|
+
this.raiseIRQ = () => { };
|
|
16
|
+
this.raiseNMI = () => { };
|
|
17
|
+
this.vtac = new vtac_terminal_1.VTAC();
|
|
18
|
+
}
|
|
19
|
+
read(address) {
|
|
20
|
+
// Status register: bit 7 is busy flag on real device, never busy in emulation
|
|
21
|
+
return 0;
|
|
22
|
+
}
|
|
23
|
+
write(address, data) {
|
|
24
|
+
const register = address & 0x00;
|
|
25
|
+
if (register === 0x00) {
|
|
26
|
+
this.vtac.parse(data);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
tick(frequency) { }
|
|
30
|
+
reset(coldStart) { }
|
|
31
|
+
}
|
|
32
|
+
exports.DevOutputBoard = DevOutputBoard;
|
|
33
|
+
//# sourceMappingURL=DevOutputBoard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DevOutputBoard.js","sourceRoot":"","sources":["../../../src/components/IO/DevOutputBoard.ts"],"names":[],"mappings":";;;AACA,iDAAoC;AAEpC;;;;;;;GAOG;AACH,MAAa,cAAc;IAA3B;QAEE,aAAQ,GAAG,GAAG,EAAE,GAAE,CAAC,CAAA;QACnB,aAAQ,GAAG,GAAG,EAAE,GAAE,CAAC,CAAA;QAEV,SAAI,GAAS,IAAI,oBAAI,EAAE,CAAA;IAiBlC,CAAC;IAfC,IAAI,CAAC,OAAe;QAClB,8EAA8E;QAC9E,OAAO,CAAC,CAAA;IACV,CAAC;IAED,KAAK,CAAC,OAAe,EAAE,IAAY;QACjC,MAAM,QAAQ,GAAG,OAAO,GAAG,IAAI,CAAA;QAC/B,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;YACtB,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QACvB,CAAC;IACH,CAAC;IAED,IAAI,CAAC,SAAiB,IAAS,CAAC;IAChC,KAAK,CAAC,SAAkB,IAAS,CAAC;CAEnC;AAtBD,wCAsBC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { IO } from '../IO';
|
|
2
|
+
export declare class EmptyCard implements IO {
|
|
3
|
+
raiseIRQ: () => void;
|
|
4
|
+
raiseNMI: () => void;
|
|
5
|
+
read(address: number): number;
|
|
6
|
+
write(address: number, data: number): void;
|
|
7
|
+
tick(frequency: number): void;
|
|
8
|
+
reset(coldStart: boolean): void;
|
|
9
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
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
|
+
* Update the attachment state based on CPU clock ticks
|
|
11
|
+
* @param cpuFrequency - The CPU frequency in Hz
|
|
12
|
+
*/
|
|
13
|
+
tick(cpuFrequency: number): void;
|
|
14
|
+
/**
|
|
15
|
+
* Read data from Port A
|
|
16
|
+
* @param ddr - Data Direction Register value
|
|
17
|
+
* @param or - Output Register value
|
|
18
|
+
* @returns The data to be read from the port
|
|
19
|
+
*/
|
|
20
|
+
readPortA(ddr: number, or: number): number;
|
|
21
|
+
/**
|
|
22
|
+
* Read data from Port B
|
|
23
|
+
* @param ddr - Data Direction Register value
|
|
24
|
+
* @param or - Output Register value
|
|
25
|
+
* @returns The data to be read from the port
|
|
26
|
+
*/
|
|
27
|
+
readPortB(ddr: number, or: number): number;
|
|
28
|
+
/**
|
|
29
|
+
* Write data to Port A
|
|
30
|
+
* @param value - The value being written
|
|
31
|
+
* @param ddr - Data Direction Register value
|
|
32
|
+
*/
|
|
33
|
+
writePortA(value: number, ddr: number): void;
|
|
34
|
+
/**
|
|
35
|
+
* Write data to Port B
|
|
36
|
+
* @param value - The value being written
|
|
37
|
+
* @param ddr - Data Direction Register value
|
|
38
|
+
*/
|
|
39
|
+
writePortB(value: number, ddr: number): void;
|
|
40
|
+
/**
|
|
41
|
+
* Check if the attachment is enabled
|
|
42
|
+
* @returns true if enabled, false otherwise
|
|
43
|
+
*/
|
|
44
|
+
isEnabled(): boolean;
|
|
45
|
+
/**
|
|
46
|
+
* Get the priority of this attachment (lower values = higher priority)
|
|
47
|
+
* @returns The priority value
|
|
48
|
+
*/
|
|
49
|
+
getPriority(): number;
|
|
50
|
+
/**
|
|
51
|
+
* Clear interrupt flags
|
|
52
|
+
* @param ca1 - Clear CA1 interrupt
|
|
53
|
+
* @param ca2 - Clear CA2 interrupt
|
|
54
|
+
* @param cb1 - Clear CB1 interrupt
|
|
55
|
+
* @param cb2 - Clear CB2 interrupt
|
|
56
|
+
*/
|
|
57
|
+
clearInterrupts(ca1: boolean, ca2: boolean, cb1: boolean, cb2: boolean): void;
|
|
58
|
+
/**
|
|
59
|
+
* Update control line states
|
|
60
|
+
* @param ca1 - CA1 control line state
|
|
61
|
+
* @param ca2 - CA2 control line state
|
|
62
|
+
* @param cb1 - CB1 control line state
|
|
63
|
+
* @param cb2 - CB2 control line state
|
|
64
|
+
*/
|
|
65
|
+
updateControlLines(ca1: boolean, ca2: boolean, cb1: boolean, cb2: boolean): void;
|
|
66
|
+
/**
|
|
67
|
+
* Check if CA1 interrupt is pending
|
|
68
|
+
* @returns true if interrupt is pending
|
|
69
|
+
*/
|
|
70
|
+
hasCA1Interrupt(): boolean;
|
|
71
|
+
/**
|
|
72
|
+
* Check if CA2 interrupt is pending
|
|
73
|
+
* @returns true if interrupt is pending
|
|
74
|
+
*/
|
|
75
|
+
hasCA2Interrupt(): boolean;
|
|
76
|
+
/**
|
|
77
|
+
* Check if CB1 interrupt is pending
|
|
78
|
+
* @returns true if interrupt is pending
|
|
79
|
+
*/
|
|
80
|
+
hasCB1Interrupt(): boolean;
|
|
81
|
+
/**
|
|
82
|
+
* Check if CB2 interrupt is pending
|
|
83
|
+
* @returns true if interrupt is pending
|
|
84
|
+
*/
|
|
85
|
+
hasCB2Interrupt(): boolean;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Base abstract class for GPIO attachments with common functionality
|
|
89
|
+
*/
|
|
90
|
+
export declare abstract class GPIOAttachmentBase implements GPIOAttachment {
|
|
91
|
+
protected priority: number;
|
|
92
|
+
protected enabled: boolean;
|
|
93
|
+
protected ca1Interrupt: boolean;
|
|
94
|
+
protected ca2Interrupt: boolean;
|
|
95
|
+
protected cb1Interrupt: boolean;
|
|
96
|
+
protected cb2Interrupt: boolean;
|
|
97
|
+
constructor(priority: number, ca1Interrupt?: boolean, ca2Interrupt?: boolean, cb1Interrupt?: boolean, cb2Interrupt?: boolean);
|
|
98
|
+
reset(): void;
|
|
99
|
+
tick(cpuFrequency: number): void;
|
|
100
|
+
readPortA(ddr: number, or: number): number;
|
|
101
|
+
readPortB(ddr: number, or: number): number;
|
|
102
|
+
writePortA(value: number, ddr: number): void;
|
|
103
|
+
writePortB(value: number, ddr: number): void;
|
|
104
|
+
isEnabled(): boolean;
|
|
105
|
+
getPriority(): number;
|
|
106
|
+
clearInterrupts(ca1: boolean, ca2: boolean, cb1: boolean, cb2: boolean): void;
|
|
107
|
+
updateControlLines(ca1: boolean, ca2: boolean, cb1: boolean, cb2: boolean): void;
|
|
108
|
+
hasCA1Interrupt(): boolean;
|
|
109
|
+
hasCA2Interrupt(): boolean;
|
|
110
|
+
hasCB1Interrupt(): boolean;
|
|
111
|
+
hasCB2Interrupt(): boolean;
|
|
112
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { GPIOAttachmentBase } from './GPIOAttachment';
|
|
2
|
+
/**
|
|
3
|
+
* GPIOJoystickAttachment - Emulates a joystick/gamepad connected to GPIO port
|
|
4
|
+
*
|
|
5
|
+
* Buttons are active-low (0 = pressed, 1 = released)
|
|
6
|
+
* Can be attached to either Port A or Port B
|
|
7
|
+
*/
|
|
8
|
+
export declare class GPIOJoystickAttachment extends GPIOAttachmentBase {
|
|
9
|
+
static readonly BUTTON_UP = 1;
|
|
10
|
+
static readonly BUTTON_DOWN = 2;
|
|
11
|
+
static readonly BUTTON_LEFT = 4;
|
|
12
|
+
static readonly BUTTON_RIGHT = 8;
|
|
13
|
+
static readonly BUTTON_A = 16;
|
|
14
|
+
static readonly BUTTON_B = 32;
|
|
15
|
+
static readonly BUTTON_SELECT = 64;
|
|
16
|
+
static readonly BUTTON_START = 128;
|
|
17
|
+
private buttonState;
|
|
18
|
+
private attachedToPortA;
|
|
19
|
+
constructor(attachToPortA?: boolean, priority?: number);
|
|
20
|
+
reset(): void;
|
|
21
|
+
readPortA(ddr: number, or: number): number;
|
|
22
|
+
readPortB(ddr: number, or: number): number;
|
|
23
|
+
/**
|
|
24
|
+
* Update the joystick button state
|
|
25
|
+
* @param buttons - Button state byte (1 = pressed, 0 = released)
|
|
26
|
+
*/
|
|
27
|
+
updateJoystick(buttons: number): void;
|
|
28
|
+
/**
|
|
29
|
+
* Get the current button state
|
|
30
|
+
* @returns The button state byte
|
|
31
|
+
*/
|
|
32
|
+
getButtonState(): number;
|
|
33
|
+
/**
|
|
34
|
+
* Check if a specific button is pressed
|
|
35
|
+
* @param button - Button bit mask to check
|
|
36
|
+
* @returns true if button is pressed
|
|
37
|
+
*/
|
|
38
|
+
isButtonPressed(button: number): boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Press a button (set its bit)
|
|
41
|
+
* @param button - Button bit mask to press
|
|
42
|
+
*/
|
|
43
|
+
pressButton(button: number): void;
|
|
44
|
+
/**
|
|
45
|
+
* Release a button (clear its bit)
|
|
46
|
+
* @param button - Button bit mask to release
|
|
47
|
+
*/
|
|
48
|
+
releaseButton(button: number): void;
|
|
49
|
+
/**
|
|
50
|
+
* Clear all button presses
|
|
51
|
+
*/
|
|
52
|
+
releaseAllButtons(): void;
|
|
53
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { GPIOAttachmentBase } from './GPIOAttachment';
|
|
2
|
+
/**
|
|
3
|
+
* GPIOKeyboardEncoderAttachment - Emulates a keyboard encoder that provides ASCII-encoded
|
|
4
|
+
* key data on both GPIO ports A and B.
|
|
5
|
+
*
|
|
6
|
+
* This attachment uses the VIA control lines to signal data availability:
|
|
7
|
+
* - CA2 LOW enables Port A
|
|
8
|
+
* - CB2 LOW enables Port B
|
|
9
|
+
* - CA1 interrupt signals data ready on Port A
|
|
10
|
+
* - CB1 interrupt signals data ready on Port B
|
|
11
|
+
*
|
|
12
|
+
* The encoder supports extensive modifier key combinations:
|
|
13
|
+
* - MENU key: 0x80 (alone), 0x90 (with Alt)
|
|
14
|
+
* - Function keys F1-F15: 0x81-0x8F (alone), 0x91-0x9F (with Alt)
|
|
15
|
+
* - Ctrl combinations: Control codes 0x00-0x1F
|
|
16
|
+
* - Alt+Shift: Extended character set 0xA0-0xFF
|
|
17
|
+
* - Alt: Extended character set 0xE0-0xFF
|
|
18
|
+
* - Shift: Uppercase letters and shifted symbols
|
|
19
|
+
*/
|
|
20
|
+
export declare class GPIOKeyboardEncoderAttachment extends GPIOAttachmentBase {
|
|
21
|
+
private asciiDataA;
|
|
22
|
+
private dataReadyA;
|
|
23
|
+
private interruptPendingA;
|
|
24
|
+
private enabledA;
|
|
25
|
+
private asciiDataB;
|
|
26
|
+
private dataReadyB;
|
|
27
|
+
private interruptPendingB;
|
|
28
|
+
private enabledB;
|
|
29
|
+
private shiftPressed;
|
|
30
|
+
private ctrlPressed;
|
|
31
|
+
private altPressed;
|
|
32
|
+
private menuPressed;
|
|
33
|
+
private stateCA1;
|
|
34
|
+
private stateCA2;
|
|
35
|
+
private stateCB1;
|
|
36
|
+
private stateCB2;
|
|
37
|
+
constructor(priority?: number);
|
|
38
|
+
reset(): void;
|
|
39
|
+
readPortA(ddrA: number, orA: number): number;
|
|
40
|
+
readPortB(ddrB: number, orB: number): number;
|
|
41
|
+
updateControlLines(ca1: boolean, ca2: boolean, cb1: boolean, cb2: boolean): void;
|
|
42
|
+
hasCA1Interrupt(): boolean;
|
|
43
|
+
hasCB1Interrupt(): boolean;
|
|
44
|
+
clearInterrupts(ca1: boolean, ca2: boolean, cb1: boolean, cb2: boolean): void;
|
|
45
|
+
/**
|
|
46
|
+
* Map a USB HID keycode to ASCII with modifier keys applied
|
|
47
|
+
*/
|
|
48
|
+
private mapKeyWithModifiers;
|
|
49
|
+
/**
|
|
50
|
+
* Update the keyboard state based on a USB HID key press or release
|
|
51
|
+
* @param usbHidKeycode USB HID keycode
|
|
52
|
+
* @param pressed true for key press, false for key release
|
|
53
|
+
*/
|
|
54
|
+
updateKey(usbHidKeycode: number, pressed: boolean): void;
|
|
55
|
+
/**
|
|
56
|
+
* Check if Port A has data ready
|
|
57
|
+
*/
|
|
58
|
+
hasDataReadyA(): boolean;
|
|
59
|
+
/**
|
|
60
|
+
* Check if Port B has data ready
|
|
61
|
+
*/
|
|
62
|
+
hasDataReadyB(): boolean;
|
|
63
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { GPIOAttachmentBase } from './GPIOAttachment';
|
|
2
|
+
/**
|
|
3
|
+
* GPIOKeyboardMatrixAttachment - Emulates a keyboard matrix connected to GPIO ports
|
|
4
|
+
*
|
|
5
|
+
* The keyboard matrix uses:
|
|
6
|
+
* - Port A (PA0-PA7): Rows (8 rows)
|
|
7
|
+
* - Port B (PB0-PB7): Columns (8 columns)
|
|
8
|
+
*
|
|
9
|
+
* Keys are active-low: when a key is pressed, the corresponding row/column intersection
|
|
10
|
+
* pulls the row line low when the column is selected (low).
|
|
11
|
+
*/
|
|
12
|
+
export declare class GPIOKeyboardMatrixAttachment extends GPIOAttachmentBase {
|
|
13
|
+
private static readonly KEYBOARD_LAYOUT;
|
|
14
|
+
private keyboardMatrix;
|
|
15
|
+
private selectedColumns;
|
|
16
|
+
constructor(priority?: number);
|
|
17
|
+
reset(): void;
|
|
18
|
+
readPortA(ddr: number, or: number): number;
|
|
19
|
+
readPortB(ddr: number, or: number): number;
|
|
20
|
+
writePortB(value: number, ddr: number): void;
|
|
21
|
+
/**
|
|
22
|
+
* Update a key state based on USB HID keycode
|
|
23
|
+
* @param usbHidKeycode - USB HID usage ID for the key
|
|
24
|
+
* @param pressed - true if key is pressed, false if released
|
|
25
|
+
*/
|
|
26
|
+
updateKey(usbHidKeycode: number, pressed: boolean): void;
|
|
27
|
+
/**
|
|
28
|
+
* Update a specific matrix position directly
|
|
29
|
+
* @param row - Row index (0-7)
|
|
30
|
+
* @param col - Column index (0-7)
|
|
31
|
+
* @param pressed - true if key is pressed, false if released
|
|
32
|
+
*/
|
|
33
|
+
updateMatrixPosition(row: number, col: number, pressed: boolean): void;
|
|
34
|
+
/**
|
|
35
|
+
* Get the current state of the keyboard matrix
|
|
36
|
+
* @returns Array of 8 bytes representing the matrix state
|
|
37
|
+
*/
|
|
38
|
+
getMatrixState(): number[];
|
|
39
|
+
/**
|
|
40
|
+
* Get the currently selected columns
|
|
41
|
+
* @returns Byte representing selected columns
|
|
42
|
+
*/
|
|
43
|
+
getSelectedColumns(): number;
|
|
44
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { GPIOAttachmentBase } from './GPIOAttachment';
|
|
2
|
+
/**
|
|
3
|
+
* GPIOKeypadAttachment - Emulates a 4×6 matrix keypad with a built-in hardware encoder
|
|
4
|
+
*
|
|
5
|
+
* The encoder converts a key press into a 5-bit code (PA0–PA4) that appears on the GPIO
|
|
6
|
+
* port. Bits 5–7 are never driven by the keypad and always read as 0 when data is present.
|
|
7
|
+
*
|
|
8
|
+
* Behaviour mirrors a typical 74C922-style encoder:
|
|
9
|
+
* - On key press → the 5-bit keypad code is latched and a CA1/CB1 interrupt is asserted
|
|
10
|
+
* - On port read → the latched code is returned on bits 0–4 (bits 5–7 = 0)
|
|
11
|
+
* - clearInterrupts → clears the interrupt and the data-ready latch
|
|
12
|
+
* - Key releases → ignored (encoder only reports on the falling edge of a keypress)
|
|
13
|
+
*
|
|
14
|
+
* The attachment may be wired to either Port A or Port B via the constructor parameter.
|
|
15
|
+
* CA1/CB1 is the DA (Data Available) interrupt line from the 74C922.
|
|
16
|
+
* CA2/CB2 is connected to the 74C922 OE (Output Enable) pin; data is only driven onto the
|
|
17
|
+
* bus when OE is asserted LOW by the 6522.
|
|
18
|
+
*/
|
|
19
|
+
export declare class GPIOKeypadAttachment extends GPIOAttachmentBase {
|
|
20
|
+
private keypadValue;
|
|
21
|
+
private dataReady;
|
|
22
|
+
private interruptPending;
|
|
23
|
+
private readonly attachedToPortA;
|
|
24
|
+
private oeState;
|
|
25
|
+
constructor(attachToPortA?: boolean, priority?: number);
|
|
26
|
+
reset(): void;
|
|
27
|
+
updateControlLines(ca1: boolean, ca2: boolean, cb1: boolean, cb2: boolean): void;
|
|
28
|
+
readPortA(ddr: number, or: number): number;
|
|
29
|
+
readPortB(ddr: number, or: number): number;
|
|
30
|
+
hasCA1Interrupt(): boolean;
|
|
31
|
+
hasCB1Interrupt(): boolean;
|
|
32
|
+
clearInterrupts(ca1: boolean, ca2: boolean, cb1: boolean, cb2: boolean): void;
|
|
33
|
+
/**
|
|
34
|
+
* Notify the attachment of a USB HID key event.
|
|
35
|
+
* Key releases are ignored; only presses generate output on the GPIO port.
|
|
36
|
+
*
|
|
37
|
+
* @param usbHidKeycode - USB HID usage ID for the key
|
|
38
|
+
* @param pressed - true for key-down, false for key-up
|
|
39
|
+
*/
|
|
40
|
+
updateKey(usbHidKeycode: number, pressed: boolean): void;
|
|
41
|
+
/**
|
|
42
|
+
* Returns the current latched keypad code (bits 0–4) or 0xFF if no data is ready.
|
|
43
|
+
*/
|
|
44
|
+
getCurrentKey(): number;
|
|
45
|
+
/** Returns true when a key has been pressed and the latch has not yet been cleared. */
|
|
46
|
+
hasDataReady(): boolean;
|
|
47
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { GPIOAttachmentBase } from './GPIOAttachment';
|
|
2
|
+
/**
|
|
3
|
+
* HD44780 LCD Controller Emulation — GPIO Attachment
|
|
4
|
+
*
|
|
5
|
+
* Emulates a 16×2 (or configurable) character LCD with HD44780 controller
|
|
6
|
+
* connected via 8-bit parallel interface on a 65C22 VIA.
|
|
7
|
+
*
|
|
8
|
+
* Pin mapping (accent on VIA ports):
|
|
9
|
+
* Port B (D0–D7): 8-bit data bus
|
|
10
|
+
* Port A bit 5: RS (Register Select — 0 = command, 1 = data)
|
|
11
|
+
* Port A bit 6: RW (Read/Write — 0 = write, 1 = read)
|
|
12
|
+
* Port A bit 7: E (Enable — active-high strobe, latched on falling edge)
|
|
13
|
+
*
|
|
14
|
+
* Display modes:
|
|
15
|
+
* Standard character display with 5×8 pixel characters
|
|
16
|
+
* Supports CGRAM for up to 8 user-defined characters
|
|
17
|
+
*
|
|
18
|
+
* Output: pixel buffer (cols*(5+1)-1) × (rows*(8+1)-1) with values:
|
|
19
|
+
* -1 = no pixel (inter-character gap)
|
|
20
|
+
* 0 = pixel off
|
|
21
|
+
* 1 = pixel on
|
|
22
|
+
*
|
|
23
|
+
* Reference: vrEmuLcd by Troy Schrapel
|
|
24
|
+
* https://github.com/visrealm/vrEmuLcd
|
|
25
|
+
*/
|
|
26
|
+
export declare const LCD_CMD_CLEAR = 1;
|
|
27
|
+
export declare const LCD_CMD_HOME = 2;
|
|
28
|
+
export declare const LCD_CMD_ENTRY_MODE = 4;
|
|
29
|
+
export declare const LCD_CMD_ENTRY_MODE_INCREMENT = 2;
|
|
30
|
+
export declare const LCD_CMD_ENTRY_MODE_SHIFT = 1;
|
|
31
|
+
export declare const LCD_CMD_DISPLAY = 8;
|
|
32
|
+
export declare const LCD_CMD_DISPLAY_ON = 4;
|
|
33
|
+
export declare const LCD_CMD_DISPLAY_CURSOR = 2;
|
|
34
|
+
export declare const LCD_CMD_DISPLAY_CURSOR_BLINK = 1;
|
|
35
|
+
export declare const LCD_CMD_SHIFT = 16;
|
|
36
|
+
export declare const LCD_CMD_SHIFT_DISPLAY = 8;
|
|
37
|
+
export declare const LCD_CMD_SHIFT_RIGHT = 4;
|
|
38
|
+
export declare const LCD_CMD_FUNCTION = 32;
|
|
39
|
+
export declare const LCD_CMD_FUNCTION_LCD_2LINE = 8;
|
|
40
|
+
export declare const LCD_CMD_SET_CGRAM_ADDR = 64;
|
|
41
|
+
export declare const LCD_CMD_SET_DRAM_ADDR = 128;
|
|
42
|
+
export declare class GPIOLCDAttachment extends GPIOAttachmentBase {
|
|
43
|
+
readonly cols: number;
|
|
44
|
+
readonly rows: number;
|
|
45
|
+
private entryModeFlags;
|
|
46
|
+
private displayFlags;
|
|
47
|
+
private scrollOffset;
|
|
48
|
+
/** 128-byte Display Data RAM */
|
|
49
|
+
private ddRam;
|
|
50
|
+
/** Current DDRAM pointer offset */
|
|
51
|
+
private ddPtr;
|
|
52
|
+
private dataWidthCols;
|
|
53
|
+
/** Character Generator RAM — 16 characters × 8 rows, stored column-major
|
|
54
|
+
* as 16 × CHAR_WIDTH_PX bytes (matching vrEmuLcd cgRam layout) */
|
|
55
|
+
private cgRam;
|
|
56
|
+
/** Current CGRAM pointer (null when not in CGRAM mode) */
|
|
57
|
+
private cgPtr;
|
|
58
|
+
/** Pixel buffer: each byte is -1 (gap), 0 (off) or 1 (on) */
|
|
59
|
+
buffer: Int8Array;
|
|
60
|
+
readonly pixelsWidth: number;
|
|
61
|
+
readonly pixelsHeight: number;
|
|
62
|
+
private blinkAccumulator;
|
|
63
|
+
private blinkState;
|
|
64
|
+
private static readonly BLINK_PERIOD_MS;
|
|
65
|
+
private lastPortA;
|
|
66
|
+
private lastE;
|
|
67
|
+
constructor(cols?: number, rows?: number, priority?: number);
|
|
68
|
+
reset(): void;
|
|
69
|
+
tick(cpuFrequency: number): void;
|
|
70
|
+
/**
|
|
71
|
+
* Port A carries the control signals.
|
|
72
|
+
* We detect E falling edge to latch the bus.
|
|
73
|
+
*/
|
|
74
|
+
writePortA(value: number, ddr: number): void;
|
|
75
|
+
readPortA(ddr: number, or: number): number;
|
|
76
|
+
readPortB(ddr: number, or: number): number;
|
|
77
|
+
private latchBus;
|
|
78
|
+
private lastPortBValue;
|
|
79
|
+
writePortB(value: number, ddr: number): void;
|
|
80
|
+
sendCommand(command: number): void;
|
|
81
|
+
writeByte(data: number): void;
|
|
82
|
+
private readByte;
|
|
83
|
+
readAddress(): number;
|
|
84
|
+
private incrementDdPtr;
|
|
85
|
+
private decrementDdPtr;
|
|
86
|
+
private doShift;
|
|
87
|
+
/**
|
|
88
|
+
* Get the 5-column font data for a character.
|
|
89
|
+
* Characters 0–15 come from CGRAM; 16–255 from ROM.
|
|
90
|
+
*/
|
|
91
|
+
private charBits;
|
|
92
|
+
private getDataOffset;
|
|
93
|
+
updatePixels(): void;
|
|
94
|
+
/** Get the raw DDRAM contents */
|
|
95
|
+
getDDRam(): Uint8Array;
|
|
96
|
+
/** Get the current DDRAM address pointer */
|
|
97
|
+
getDDPtr(): number;
|
|
98
|
+
/** Get the display flags */
|
|
99
|
+
getDisplayFlags(): number;
|
|
100
|
+
/** Get the entry mode flags */
|
|
101
|
+
getEntryModeFlags(): number;
|
|
102
|
+
/** Get scroll offset */
|
|
103
|
+
getScrollOffset(): number;
|
|
104
|
+
/** Get CGRAM pointer (null if not in CGRAM mode) */
|
|
105
|
+
getCGPtr(): number | null;
|
|
106
|
+
/** Read the text content of a specific display row */
|
|
107
|
+
getRowText(row: number): string;
|
|
108
|
+
/** Pixel state at a given coordinate: -1 (gap), 0 (off), 1 (on) */
|
|
109
|
+
pixelState(x: number, y: number): number;
|
|
110
|
+
}
|