ac6502 1.3.0 → 1.4.1

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 (141) hide show
  1. package/README.md +139 -32
  2. package/dist/components/IO/ACIA.d.ts +76 -0
  3. package/dist/components/IO/ACIA.js +282 -0
  4. package/dist/components/IO/ACIA.js.map +1 -0
  5. package/dist/components/IO/Attachments/Attachment.d.ts +112 -0
  6. package/dist/components/IO/Attachments/Attachment.js +71 -0
  7. package/dist/components/IO/Attachments/Attachment.js.map +1 -0
  8. package/dist/components/IO/Attachments/JoystickAttachment.d.ts +53 -0
  9. package/dist/components/IO/Attachments/JoystickAttachment.js +90 -0
  10. package/dist/components/IO/Attachments/JoystickAttachment.js.map +1 -0
  11. package/dist/components/IO/Attachments/KeyboardEncoderAttachment.d.ts +63 -0
  12. package/dist/components/IO/Attachments/KeyboardEncoderAttachment.js +489 -0
  13. package/dist/components/IO/Attachments/KeyboardEncoderAttachment.js.map +1 -0
  14. package/dist/components/IO/Attachments/KeyboardMatrixAttachment.d.ts +44 -0
  15. package/dist/components/IO/Attachments/KeyboardMatrixAttachment.js +274 -0
  16. package/dist/components/IO/Attachments/KeyboardMatrixAttachment.js.map +1 -0
  17. package/dist/components/IO/Attachments/KeypadAttachment.d.ts +47 -0
  18. package/dist/components/IO/Attachments/KeypadAttachment.js +141 -0
  19. package/dist/components/IO/Attachments/KeypadAttachment.js.map +1 -0
  20. package/dist/components/IO/Attachments/LCDAttachment.d.ts +110 -0
  21. package/dist/components/IO/Attachments/LCDAttachment.js +716 -0
  22. package/dist/components/IO/Attachments/LCDAttachment.js.map +1 -0
  23. package/dist/components/IO/Attachments/SNESAttachment.d.ts +85 -0
  24. package/dist/components/IO/Attachments/SNESAttachment.js +184 -0
  25. package/dist/components/IO/Attachments/SNESAttachment.js.map +1 -0
  26. package/dist/components/IO/Empty.d.ts +9 -0
  27. package/dist/components/IO/Empty.js +5 -7
  28. package/dist/components/IO/Empty.js.map +1 -1
  29. package/dist/components/IO/GPIOCard.d.ts +5 -5
  30. package/dist/components/IO/GPIOCard.js.map +1 -1
  31. package/dist/components/IO/RAMBank.d.ts +37 -0
  32. package/dist/components/IO/RAMBank.js +63 -0
  33. package/dist/components/IO/RAMBank.js.map +1 -0
  34. package/dist/components/IO/RTC.d.ts +107 -0
  35. package/dist/components/IO/RTC.js +483 -0
  36. package/dist/components/IO/RTC.js.map +1 -0
  37. package/dist/components/IO/Sound.d.ts +120 -0
  38. package/dist/components/IO/Sound.js +622 -0
  39. package/dist/components/IO/Sound.js.map +1 -0
  40. package/dist/components/IO/Storage.d.ts +74 -0
  41. package/dist/components/IO/Storage.js +409 -0
  42. package/dist/components/IO/Storage.js.map +1 -0
  43. package/dist/components/IO/Terminal.d.ts +19 -0
  44. package/dist/components/IO/Terminal.js +33 -0
  45. package/dist/components/IO/Terminal.js.map +1 -0
  46. package/dist/components/IO/VIA.d.ts +105 -0
  47. package/dist/components/IO/VIA.js +597 -0
  48. package/dist/components/IO/VIA.js.map +1 -0
  49. package/dist/components/IO/Video.d.ts +141 -0
  50. package/dist/components/IO/Video.js +630 -0
  51. package/dist/components/IO/Video.js.map +1 -0
  52. package/dist/components/Machine.d.ts +20 -24
  53. package/dist/components/Machine.js +249 -166
  54. package/dist/components/Machine.js.map +1 -1
  55. package/dist/index.js +28 -14
  56. package/dist/index.js.map +1 -1
  57. package/dist/lib.d.ts +16 -16
  58. package/dist/lib.js +32 -32
  59. package/dist/lib.js.map +1 -1
  60. package/dist/tests/IO/ACIA.test.d.ts +1 -0
  61. package/dist/tests/IO/ACIA.test.js +423 -0
  62. package/dist/tests/IO/ACIA.test.js.map +1 -0
  63. package/dist/tests/IO/Attachments/Attachment.test.d.ts +1 -0
  64. package/dist/tests/IO/Attachments/Attachment.test.js +339 -0
  65. package/dist/tests/IO/Attachments/Attachment.test.js.map +1 -0
  66. package/dist/tests/IO/Attachments/JoystickAttachment.test.d.ts +1 -0
  67. package/dist/tests/IO/Attachments/JoystickAttachment.test.js +126 -0
  68. package/dist/tests/IO/Attachments/JoystickAttachment.test.js.map +1 -0
  69. package/dist/tests/IO/Attachments/KeyboardEncoderAttachment.test.d.ts +1 -0
  70. package/dist/tests/IO/Attachments/KeyboardEncoderAttachment.test.js +779 -0
  71. package/dist/tests/IO/Attachments/KeyboardEncoderAttachment.test.js.map +1 -0
  72. package/dist/tests/IO/Attachments/KeyboardMatrixAttachment.test.d.ts +1 -0
  73. package/dist/tests/IO/Attachments/KeyboardMatrixAttachment.test.js +355 -0
  74. package/dist/tests/IO/Attachments/KeyboardMatrixAttachment.test.js.map +1 -0
  75. package/dist/tests/IO/Attachments/KeypadAttachment.test.d.ts +1 -0
  76. package/dist/tests/IO/Attachments/KeypadAttachment.test.js +323 -0
  77. package/dist/tests/IO/Attachments/KeypadAttachment.test.js.map +1 -0
  78. package/dist/tests/IO/Attachments/LCDAttachment.test.d.ts +1 -0
  79. package/dist/tests/IO/Attachments/LCDAttachment.test.js +627 -0
  80. package/dist/tests/IO/Attachments/LCDAttachment.test.js.map +1 -0
  81. package/dist/tests/IO/Attachments/SNESAttachment.test.d.ts +1 -0
  82. package/dist/tests/IO/Attachments/SNESAttachment.test.js +331 -0
  83. package/dist/tests/IO/Attachments/SNESAttachment.test.js.map +1 -0
  84. package/dist/tests/IO/Empty.test.d.ts +1 -0
  85. package/dist/tests/IO/Empty.test.js +121 -0
  86. package/dist/tests/IO/Empty.test.js.map +1 -0
  87. package/dist/tests/IO/GPIOCard.test.js.map +1 -1
  88. package/dist/tests/IO/RAMBank.test.d.ts +1 -0
  89. package/dist/tests/IO/RAMBank.test.js +229 -0
  90. package/dist/tests/IO/RAMBank.test.js.map +1 -0
  91. package/dist/tests/IO/RTC.test.d.ts +1 -0
  92. package/dist/tests/IO/RTC.test.js +177 -0
  93. package/dist/tests/IO/RTC.test.js.map +1 -0
  94. package/dist/tests/IO/Sound.test.d.ts +1 -0
  95. package/dist/tests/IO/Sound.test.js +528 -0
  96. package/dist/tests/IO/Sound.test.js.map +1 -0
  97. package/dist/tests/IO/Storage.test.d.ts +1 -0
  98. package/dist/tests/IO/Storage.test.js +656 -0
  99. package/dist/tests/IO/Storage.test.js.map +1 -0
  100. package/dist/tests/IO/VIA.test.d.ts +1 -0
  101. package/dist/tests/IO/VIA.test.js +503 -0
  102. package/dist/tests/IO/VIA.test.js.map +1 -0
  103. package/dist/tests/IO/Video.test.d.ts +1 -0
  104. package/dist/tests/IO/Video.test.js +549 -0
  105. package/dist/tests/IO/Video.test.js.map +1 -0
  106. package/dist/tests/Machine.test.js +27 -42
  107. package/dist/tests/Machine.test.js.map +1 -1
  108. package/package.json +1 -1
  109. package/src/components/IO/{SerialCard.ts → ACIA.ts} +2 -2
  110. package/src/components/IO/{GPIOAttachments/GPIOAttachment.ts → Attachments/Attachment.ts} +2 -2
  111. package/src/components/IO/{GPIOAttachments/GPIOJoystickAttachment.ts → Attachments/JoystickAttachment.ts} +3 -3
  112. package/src/components/IO/{GPIOAttachments/GPIOKeyboardEncoderAttachment.ts → Attachments/KeyboardEncoderAttachment.ts} +3 -3
  113. package/src/components/IO/{GPIOAttachments/GPIOKeyboardMatrixAttachment.ts → Attachments/KeyboardMatrixAttachment.ts} +5 -5
  114. package/src/components/IO/{GPIOAttachments/GPIOKeypadAttachment.ts → Attachments/KeypadAttachment.ts} +3 -3
  115. package/src/components/IO/{GPIOAttachments/GPIOLCDAttachment.ts → Attachments/LCDAttachment.ts} +7 -7
  116. package/src/components/IO/{EmptyCard.ts → Empty.ts} +1 -1
  117. package/src/components/IO/{RAMCard.ts → RAMBank.ts} +8 -8
  118. package/src/components/IO/{RTCCard.ts → RTC.ts} +1 -1
  119. package/src/components/IO/{SoundCard.ts → Sound.ts} +2 -2
  120. package/src/components/IO/{StorageCard.ts → Storage.ts} +70 -73
  121. package/src/components/IO/{DevOutputBoard.ts → Terminal.ts} +2 -2
  122. package/src/components/IO/{GPIOCard.ts → VIA.ts} +64 -64
  123. package/src/components/IO/{VideoCard.ts → Video.ts} +1 -1
  124. package/src/components/Machine.ts +276 -176
  125. package/src/index.ts +34 -21
  126. package/src/lib.ts +16 -16
  127. package/src/tests/IO/{SerialCard.test.ts → ACIA.test.ts} +5 -5
  128. package/src/tests/IO/{GPIOAttachments/GPIOAttachment.test.ts → Attachments/Attachment.test.ts} +12 -12
  129. package/src/tests/IO/{GPIOAttachments/GPIOJoystickAttachment.test.ts → Attachments/JoystickAttachment.test.ts} +23 -23
  130. package/src/tests/IO/{GPIOAttachments/GPIOKeyboardEncoderAttachment.test.ts → Attachments/KeyboardEncoderAttachment.test.ts} +4 -4
  131. package/src/tests/IO/{GPIOAttachments/GPIOKeyboardMatrixAttachment.test.ts → Attachments/KeyboardMatrixAttachment.test.ts} +5 -5
  132. package/src/tests/IO/{GPIOAttachments/GPIOKeypadAttachment.test.ts → Attachments/KeypadAttachment.test.ts} +38 -38
  133. package/src/tests/IO/{GPIOAttachments/GPIOLCDAttachment.test.ts → Attachments/LCDAttachment.test.ts} +12 -12
  134. package/src/tests/IO/Empty.test.ts +143 -0
  135. package/src/tests/IO/{RAMCard.test.ts → RAMBank.test.ts} +33 -33
  136. package/src/tests/IO/{RTCCard.test.ts → RTC.test.ts} +6 -6
  137. package/src/tests/IO/{SoundCard.test.ts → Sound.test.ts} +6 -6
  138. package/src/tests/IO/{StorageCard.test.ts → Storage.test.ts} +34 -25
  139. package/src/tests/IO/{GPIOCard.test.ts → VIA.test.ts} +7 -7
  140. package/src/tests/IO/{VideoCard.test.ts → Video.test.ts} +13 -13
  141. package/src/tests/Machine.test.ts +31 -38
@@ -2,57 +2,54 @@ import { CPU } from './CPU';
2
2
  import { RAM } from './RAM';
3
3
  import { ROM } from './ROM';
4
4
  import { Cart } from './Cart';
5
- import { SerialCard } from './IO/SerialCard';
6
- import { GPIOKeyboardMatrixAttachment } from './IO/GPIOAttachments/GPIOKeyboardMatrixAttachment';
7
- import { GPIOKeyboardEncoderAttachment } from './IO/GPIOAttachments/GPIOKeyboardEncoderAttachment';
8
- import { GPIOJoystickAttachment } from './IO/GPIOAttachments/GPIOJoystickAttachment';
9
- import { GPIOLCDAttachment } from './IO/GPIOAttachments/GPIOLCDAttachment';
10
- import { GPIOKeypadAttachment } from './IO/GPIOAttachments/GPIOKeypadAttachment';
5
+ import { KeyboardMatrixAttachment } from './IO/Attachments/KeyboardMatrixAttachment';
6
+ import { KeyboardEncoderAttachment } from './IO/Attachments/KeyboardEncoderAttachment';
7
+ import { JoystickAttachment } from './IO/Attachments/JoystickAttachment';
8
+ import { LCDAttachment } from './IO/Attachments/LCDAttachment';
9
+ import { KeypadAttachment } from './IO/Attachments/KeypadAttachment';
11
10
  import { IO } from './IO';
12
11
  export declare class Machine {
13
12
  static MAX_FPS: number;
14
13
  static FRAME_INTERVAL_MS: number;
15
14
  private ioCycleAccumulator;
16
15
  private ioTickInterval;
16
+ private loopHandle?;
17
17
  cpu: CPU;
18
18
  ram: RAM;
19
19
  rom: ROM;
20
+ cart?: Cart;
20
21
  io1: IO;
21
22
  io2: IO;
22
23
  io3: IO;
23
24
  io4: IO;
24
- io5: SerialCard;
25
+ io5: IO;
25
26
  io6: IO;
26
27
  io7: IO;
27
28
  io8: IO;
28
- cart?: Cart;
29
+ keyboardMatrixAttachment?: KeyboardMatrixAttachment;
30
+ keyboardEncoderAttachment?: KeyboardEncoderAttachment;
31
+ joystickAttachmentA?: JoystickAttachment;
32
+ joystickAttachmentB?: JoystickAttachment;
33
+ lcdAttachment?: LCDAttachment;
34
+ keypadAttachment?: KeypadAttachment;
29
35
  target: string;
30
- keyboardMatrixAttachment: GPIOKeyboardMatrixAttachment;
31
- keyboardEncoderAttachment: GPIOKeyboardEncoderAttachment;
32
- joystickAttachmentA: GPIOJoystickAttachment;
33
- joystickAttachmentB: GPIOJoystickAttachment;
34
- lcdAttachment?: GPIOLCDAttachment;
35
- keypadAttachment?: GPIOKeypadAttachment;
36
- isAlive: boolean;
37
36
  isRunning: boolean;
38
37
  frequency: number;
39
38
  scale: number;
40
39
  frames: number;
41
- frameDelay: number;
42
- frameDelayCount: number;
43
40
  startTime: number;
44
41
  previousTime: number;
45
42
  transmit?: (data: number) => void;
46
43
  render?: () => void;
47
- pushAudioSamples?: (samples: Float32Array) => void;
48
- constructor(target?: string);
49
- loadROM: (path: string) => Promise<void>;
50
- loadCart: (path: string) => Promise<void>;
51
- start(): void;
52
- end(): void;
44
+ play?: (samples: Float32Array) => void;
45
+ constructor(target: string);
46
+ configureTarget(target: string): void;
47
+ loadROM: (data: Uint8Array | number[] | ArrayBuffer) => void;
48
+ loadCart: (data: Uint8Array | number[] | ArrayBuffer) => void;
53
49
  run(): void;
54
50
  stop(): void;
55
51
  step(): void;
52
+ reset(coldStart: boolean): void;
56
53
  tick(): void;
57
54
  onReceive(data: number): void;
58
55
  onKeyDown(scancode: number): void;
@@ -60,7 +57,6 @@ export declare class Machine {
60
57
  onJoystickA(buttons: number): void;
61
58
  onJoystickB(buttons: number): void;
62
59
  private loop;
63
- reset(coldStart: boolean): void;
64
60
  read(address: number): number;
65
61
  write(address: number, data: number): void;
66
62
  }
@@ -1,197 +1,273 @@
1
1
  "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
2
  Object.defineProperty(exports, "__esModule", { value: true });
12
3
  exports.Machine = void 0;
13
4
  const CPU_1 = require("./CPU");
14
5
  const RAM_1 = require("./RAM");
15
6
  const ROM_1 = require("./ROM");
16
7
  const Cart_1 = require("./Cart");
17
- const GPIOCard_1 = require("./IO/GPIOCard");
18
- const RAMCard_1 = require("./IO/RAMCard");
19
- const RTCCard_1 = require("./IO/RTCCard");
20
- const SerialCard_1 = require("./IO/SerialCard");
21
- const SoundCard_1 = require("./IO/SoundCard");
22
- const StorageCard_1 = require("./IO/StorageCard");
23
- const VideoCard_1 = require("./IO/VideoCard");
24
- const GPIOKeyboardMatrixAttachment_1 = require("./IO/GPIOAttachments/GPIOKeyboardMatrixAttachment");
25
- const GPIOKeyboardEncoderAttachment_1 = require("./IO/GPIOAttachments/GPIOKeyboardEncoderAttachment");
26
- const GPIOJoystickAttachment_1 = require("./IO/GPIOAttachments/GPIOJoystickAttachment");
27
- const GPIOLCDAttachment_1 = require("./IO/GPIOAttachments/GPIOLCDAttachment");
28
- const GPIOKeypadAttachment_1 = require("./IO/GPIOAttachments/GPIOKeypadAttachment");
29
- const EmptyCard_1 = require("./IO/EmptyCard");
30
- const DevOutputBoard_1 = require("./IO/DevOutputBoard");
31
- const promises_1 = require("fs/promises");
8
+ const VIA_1 = require("./IO/VIA");
9
+ const RAMBank_1 = require("./IO/RAMBank");
10
+ const RTC_1 = require("./IO/RTC");
11
+ const ACIA_1 = require("./IO/ACIA");
12
+ const Sound_1 = require("./IO/Sound");
13
+ const Storage_1 = require("./IO/Storage");
14
+ const Video_1 = require("./IO/Video");
15
+ const KeyboardMatrixAttachment_1 = require("./IO/Attachments/KeyboardMatrixAttachment");
16
+ const KeyboardEncoderAttachment_1 = require("./IO/Attachments/KeyboardEncoderAttachment");
17
+ const JoystickAttachment_1 = require("./IO/Attachments/JoystickAttachment");
18
+ const LCDAttachment_1 = require("./IO/Attachments/LCDAttachment");
19
+ const KeypadAttachment_1 = require("./IO/Attachments/KeypadAttachment");
20
+ const Empty_1 = require("./IO/Empty");
21
+ const Terminal_1 = require("./IO/Terminal");
32
22
  class Machine {
33
23
  //
34
24
  // Initialization
35
25
  //
36
- constructor(target = 'cob') {
26
+ constructor(target) {
37
27
  this.ioCycleAccumulator = 0;
38
28
  this.ioTickInterval = 128; // adjust (64/128/256)
39
- this.isAlive = false;
40
29
  this.isRunning = false;
41
30
  this.frequency = 2000000; // 2 MHz
42
31
  this.scale = 2;
43
32
  this.frames = 0;
44
- this.frameDelay = 0;
45
- this.frameDelayCount = 0;
46
33
  this.startTime = Date.now();
47
34
  this.previousTime = performance.now();
48
35
  //
49
36
  // Methods
50
37
  //
51
- this.loadROM = (path) => __awaiter(this, void 0, void 0, function* () {
52
- try {
53
- this.rom.load(Array.from(new Uint8Array(yield (0, promises_1.readFile)(path))));
38
+ this.loadROM = (data) => {
39
+ if (data instanceof ArrayBuffer) {
40
+ this.rom.load(Array.from(new Uint8Array(data)));
54
41
  }
55
- catch (error) {
56
- console.error('Error reading file:', error);
42
+ else if (data instanceof Uint8Array) {
43
+ this.rom.load(Array.from(data));
57
44
  }
58
- });
59
- this.loadCart = (path) => __awaiter(this, void 0, void 0, function* () {
60
- try {
61
- const data = Array.from(new Uint8Array(yield (0, promises_1.readFile)(path)));
62
- const cart = new Cart_1.Cart();
63
- cart.load(data);
64
- this.cart = cart;
45
+ else {
46
+ this.rom.load(data);
65
47
  }
66
- catch (error) {
67
- console.error('Error reading file:', error);
48
+ };
49
+ this.loadCart = (data) => {
50
+ let dataArray;
51
+ if (data instanceof ArrayBuffer) {
52
+ dataArray = Array.from(new Uint8Array(data));
53
+ }
54
+ else if (data instanceof Uint8Array) {
55
+ dataArray = Array.from(data);
56
+ }
57
+ else {
58
+ dataArray = data;
68
59
  }
69
- });
60
+ const cart = new Cart_1.Cart();
61
+ cart.load(dataArray);
62
+ this.cart = cart;
63
+ };
70
64
  this.target = target;
71
65
  this.cpu = new CPU_1.CPU(this.read.bind(this), this.write.bind(this));
72
66
  this.ram = new RAM_1.RAM();
73
67
  this.rom = new ROM_1.ROM();
74
- this.io5 = new SerialCard_1.SerialCard();
75
- // Connect SerialCard IRQ/NMI to CPU
76
- this.io5.raiseIRQ = () => this.cpu.irq();
77
- this.io5.raiseNMI = () => this.cpu.nmi();
78
- // Connect SerialCard transmit callback
79
- this.io5.transmit = (data) => {
80
- if (this.transmit) {
81
- this.transmit(data);
82
- }
83
- };
84
- // Always create standard GPIO attachments (for type stability)
85
- this.keyboardMatrixAttachment = new GPIOKeyboardMatrixAttachment_1.GPIOKeyboardMatrixAttachment(10);
86
- this.keyboardEncoderAttachment = new GPIOKeyboardEncoderAttachment_1.GPIOKeyboardEncoderAttachment(20);
87
- this.joystickAttachmentA = new GPIOJoystickAttachment_1.GPIOJoystickAttachment(false, 100);
88
- this.joystickAttachmentB = new GPIOJoystickAttachment_1.GPIOJoystickAttachment(false, 100);
68
+ this.io1 = new Empty_1.Empty();
69
+ this.io2 = new Empty_1.Empty();
70
+ this.io3 = new Empty_1.Empty();
71
+ this.io4 = new Empty_1.Empty();
72
+ this.io5 = new Empty_1.Empty();
73
+ this.io6 = new Empty_1.Empty();
74
+ this.io7 = new Empty_1.Empty();
75
+ this.io8 = new Empty_1.Empty();
76
+ this.configureTarget(target);
77
+ this.startTime = Date.now();
78
+ this.cpu.reset();
79
+ }
80
+ configureTarget(target) {
89
81
  if (target === 'kim') {
90
- this.io1 = new EmptyCard_1.EmptyCard();
91
- this.io2 = new EmptyCard_1.EmptyCard();
92
- this.io3 = new EmptyCard_1.EmptyCard();
93
- this.io4 = new EmptyCard_1.EmptyCard();
94
- this.io6 = new EmptyCard_1.EmptyCard();
95
- this.io7 = new EmptyCard_1.EmptyCard();
96
- const gpioCard = new GPIOCard_1.GPIOCard();
97
- this.io8 = gpioCard;
98
- // Connect GPIOCard IRQ/NMI to CPU
99
- gpioCard.raiseIRQ = () => this.cpu.irq();
100
- gpioCard.raiseNMI = () => this.cpu.nmi();
82
+ const acia = new ACIA_1.ACIA();
83
+ this.io5 = acia;
84
+ // Connect ACIA IRQ/NMI to CPU
85
+ acia.raiseIRQ = () => this.cpu.irq();
86
+ acia.raiseNMI = () => this.cpu.nmi();
87
+ // Connect ACIA transmit callback
88
+ acia.transmit = (data) => {
89
+ if (this.transmit) {
90
+ this.transmit(data);
91
+ }
92
+ };
93
+ this.io1 = new Empty_1.Empty();
94
+ this.io2 = new Empty_1.Empty();
95
+ this.io3 = new Empty_1.Empty();
96
+ this.io4 = new Empty_1.Empty();
97
+ this.io6 = new Empty_1.Empty();
98
+ this.io7 = new Empty_1.Empty();
99
+ const via = new VIA_1.VIA();
100
+ this.io8 = via;
101
+ // Connect VIA IRQ/NMI to CPU
102
+ via.raiseIRQ = () => this.cpu.irq();
103
+ via.raiseNMI = () => this.cpu.nmi();
101
104
  // Create KIM GPIO Attachments
102
- this.lcdAttachment = new GPIOLCDAttachment_1.GPIOLCDAttachment(16, 2, 10);
103
- this.keypadAttachment = new GPIOKeypadAttachment_1.GPIOKeypadAttachment(true, 20);
105
+ this.lcdAttachment = new LCDAttachment_1.LCDAttachment(16, 2, 10);
106
+ this.keypadAttachment = new KeypadAttachment_1.KeypadAttachment(true, 20);
104
107
  // Attach LCD to Port A (control: RS/RW/E on bits 5-7) and Port B (data bus)
105
- gpioCard.attachToPortA(this.lcdAttachment);
106
- gpioCard.attachToPortB(this.lcdAttachment);
108
+ via.attachToPortA(this.lcdAttachment);
109
+ via.attachToPortB(this.lcdAttachment);
107
110
  // Attach keypad to Port A (bits 0-4)
108
- gpioCard.attachToPortA(this.keypadAttachment);
111
+ via.attachToPortA(this.keypadAttachment);
109
112
  }
110
113
  else if (target === 'dev') {
111
- const rtcCard = new RTCCard_1.RTCCard();
112
- const storageCard = new StorageCard_1.StorageCard();
113
- const gpioCard = new GPIOCard_1.GPIOCard();
114
- this.io1 = new RAMCard_1.RAMCard();
115
- this.io2 = new RAMCard_1.RAMCard();
116
- this.io3 = rtcCard;
117
- this.io4 = storageCard;
118
- this.io6 = gpioCard;
119
- this.io7 = new EmptyCard_1.EmptyCard();
120
- this.io8 = new DevOutputBoard_1.DevOutputBoard();
121
- // Connect RTCCard IRQ/NMI to CPU
122
- rtcCard.raiseIRQ = () => this.cpu.irq();
123
- rtcCard.raiseNMI = () => this.cpu.nmi();
114
+ const acia = new ACIA_1.ACIA();
115
+ this.io5 = acia;
116
+ // Connect ACIA IRQ/NMI to CPU
117
+ acia.raiseIRQ = () => this.cpu.irq();
118
+ acia.raiseNMI = () => this.cpu.nmi();
119
+ // Connect ACIA transmit callback
120
+ acia.transmit = (data) => {
121
+ if (this.transmit) {
122
+ this.transmit(data);
123
+ }
124
+ };
125
+ const rtc = new RTC_1.RTC();
126
+ const storage = new Storage_1.Storage();
127
+ const via = new VIA_1.VIA();
128
+ this.io1 = new RAMBank_1.RAMBank();
129
+ this.io2 = new RAMBank_1.RAMBank();
130
+ this.io3 = rtc;
131
+ this.io4 = storage;
132
+ this.io6 = via;
133
+ this.io7 = new Empty_1.Empty();
134
+ this.io8 = new Terminal_1.Terminal();
135
+ // Connect RTC IRQ/NMI to CPU
136
+ rtc.raiseIRQ = () => this.cpu.irq();
137
+ rtc.raiseNMI = () => this.cpu.nmi();
138
+ // Create standard GPIO attachments
139
+ this.keyboardMatrixAttachment = new KeyboardMatrixAttachment_1.KeyboardMatrixAttachment(10);
140
+ this.keyboardEncoderAttachment = new KeyboardEncoderAttachment_1.KeyboardEncoderAttachment(20);
141
+ this.joystickAttachmentA = new JoystickAttachment_1.JoystickAttachment(false, 100);
142
+ this.joystickAttachmentB = new JoystickAttachment_1.JoystickAttachment(false, 100);
124
143
  // Attach peripherals to GPIO Card
125
- gpioCard.attachToPortA(this.keyboardMatrixAttachment);
126
- gpioCard.attachToPortB(this.keyboardMatrixAttachment);
127
- gpioCard.attachToPortA(this.keyboardEncoderAttachment);
128
- gpioCard.attachToPortB(this.keyboardEncoderAttachment);
129
- gpioCard.attachToPortA(this.joystickAttachmentA);
130
- gpioCard.attachToPortB(this.joystickAttachmentB);
144
+ via.attachToPortA(this.keyboardMatrixAttachment);
145
+ via.attachToPortB(this.keyboardMatrixAttachment);
146
+ via.attachToPortA(this.keyboardEncoderAttachment);
147
+ via.attachToPortB(this.keyboardEncoderAttachment);
148
+ via.attachToPortA(this.joystickAttachmentA);
149
+ via.attachToPortB(this.joystickAttachmentB);
131
150
  }
132
- else {
133
- // COB / VCS
134
- const rtcCard = new RTCCard_1.RTCCard();
135
- const storageCard = new StorageCard_1.StorageCard();
136
- const gpioCard = new GPIOCard_1.GPIOCard();
137
- const soundCard = new SoundCard_1.SoundCard();
138
- const videoCard = new VideoCard_1.VideoCard();
139
- this.io1 = new RAMCard_1.RAMCard();
140
- this.io2 = new RAMCard_1.RAMCard();
141
- this.io3 = rtcCard;
142
- this.io4 = storageCard;
143
- this.io6 = gpioCard;
144
- this.io7 = soundCard;
145
- this.io8 = videoCard;
146
- // Connect RTCCard IRQ/NMI to CPU
147
- rtcCard.raiseIRQ = () => this.cpu.irq();
148
- rtcCard.raiseNMI = () => this.cpu.nmi();
149
- // Connect VideoCard IRQ/NMI to CPU
150
- videoCard.raiseIRQ = () => this.cpu.irq();
151
- videoCard.raiseNMI = () => this.cpu.nmi();
152
- // Connect SoundCard pushSamples callback
153
- soundCard.pushSamples = (samples) => {
154
- if (this.pushAudioSamples) {
155
- this.pushAudioSamples(samples);
151
+ else if (target === 'vcs') {
152
+ this.io5 = new Empty_1.Empty();
153
+ const via = new VIA_1.VIA();
154
+ const sound = new Sound_1.Sound();
155
+ const video = new Video_1.Video();
156
+ this.io1 = new Empty_1.Empty();
157
+ this.io2 = new Empty_1.Empty();
158
+ this.io3 = new Empty_1.Empty();
159
+ this.io4 = new Empty_1.Empty();
160
+ this.io6 = via;
161
+ this.io7 = sound;
162
+ this.io8 = video;
163
+ // Connect Video IRQ/NMI to CPU
164
+ video.raiseIRQ = () => this.cpu.irq();
165
+ video.raiseNMI = () => this.cpu.nmi();
166
+ // Connect Sound pushSamples callback
167
+ sound.pushSamples = (samples) => {
168
+ if (this.play) {
169
+ this.play(samples);
156
170
  }
157
171
  };
172
+ // Create standard GPIO attachments
173
+ this.keyboardMatrixAttachment = new KeyboardMatrixAttachment_1.KeyboardMatrixAttachment(10);
174
+ this.keyboardEncoderAttachment = new KeyboardEncoderAttachment_1.KeyboardEncoderAttachment(20);
175
+ this.joystickAttachmentA = new JoystickAttachment_1.JoystickAttachment(false, 100);
176
+ this.joystickAttachmentB = new JoystickAttachment_1.JoystickAttachment(false, 100);
158
177
  // Attach peripherals to GPIO Card
159
- gpioCard.attachToPortA(this.keyboardMatrixAttachment);
160
- gpioCard.attachToPortB(this.keyboardMatrixAttachment);
161
- gpioCard.attachToPortA(this.keyboardEncoderAttachment);
162
- gpioCard.attachToPortB(this.keyboardEncoderAttachment);
163
- gpioCard.attachToPortA(this.joystickAttachmentA);
164
- gpioCard.attachToPortB(this.joystickAttachmentB);
178
+ via.attachToPortA(this.keyboardMatrixAttachment);
179
+ via.attachToPortB(this.keyboardMatrixAttachment);
180
+ via.attachToPortA(this.keyboardEncoderAttachment);
181
+ via.attachToPortB(this.keyboardEncoderAttachment);
182
+ via.attachToPortA(this.joystickAttachmentA);
183
+ via.attachToPortB(this.joystickAttachmentB);
184
+ }
185
+ else if (target === 'cob') {
186
+ const acia = new ACIA_1.ACIA();
187
+ this.io5 = acia;
188
+ // Connect ACIA IRQ/NMI to CPU
189
+ acia.raiseIRQ = () => this.cpu.irq();
190
+ acia.raiseNMI = () => this.cpu.nmi();
191
+ // Connect ACIA transmit callback
192
+ acia.transmit = (data) => {
193
+ if (this.transmit) {
194
+ this.transmit(data);
195
+ }
196
+ };
197
+ const rtc = new RTC_1.RTC();
198
+ const storage = new Storage_1.Storage();
199
+ const gpio = new VIA_1.VIA();
200
+ const sound = new Sound_1.Sound();
201
+ const video = new Video_1.Video();
202
+ this.io1 = new RAMBank_1.RAMBank();
203
+ this.io2 = new RAMBank_1.RAMBank();
204
+ this.io3 = rtc;
205
+ this.io4 = storage;
206
+ this.io6 = gpio;
207
+ this.io7 = sound;
208
+ this.io8 = video;
209
+ // Connect RTC IRQ/NMI to CPU
210
+ rtc.raiseIRQ = () => this.cpu.irq();
211
+ rtc.raiseNMI = () => this.cpu.nmi();
212
+ // Connect Video IRQ/NMI to CPU
213
+ video.raiseIRQ = () => this.cpu.irq();
214
+ video.raiseNMI = () => this.cpu.nmi();
215
+ // Connect Sound pushSamples callback
216
+ sound.pushSamples = (samples) => {
217
+ if (this.play) {
218
+ this.play(samples);
219
+ }
220
+ };
221
+ // Create standard GPIO attachments
222
+ this.keyboardMatrixAttachment = new KeyboardMatrixAttachment_1.KeyboardMatrixAttachment(10);
223
+ this.keyboardEncoderAttachment = new KeyboardEncoderAttachment_1.KeyboardEncoderAttachment(20);
224
+ this.joystickAttachmentA = new JoystickAttachment_1.JoystickAttachment(false, 100);
225
+ this.joystickAttachmentB = new JoystickAttachment_1.JoystickAttachment(false, 100);
226
+ // Attach peripherals to GPIO Card
227
+ gpio.attachToPortA(this.keyboardMatrixAttachment);
228
+ gpio.attachToPortB(this.keyboardMatrixAttachment);
229
+ gpio.attachToPortA(this.keyboardEncoderAttachment);
230
+ gpio.attachToPortB(this.keyboardEncoderAttachment);
231
+ gpio.attachToPortA(this.joystickAttachmentA);
232
+ gpio.attachToPortB(this.joystickAttachmentB);
233
+ }
234
+ else {
235
+ this.io1 = new Empty_1.Empty();
236
+ this.io2 = new Empty_1.Empty();
237
+ this.io3 = new Empty_1.Empty();
238
+ this.io4 = new Empty_1.Empty();
239
+ this.io5 = new Empty_1.Empty();
240
+ this.io6 = new Empty_1.Empty();
241
+ this.io7 = new Empty_1.Empty();
242
+ this.io8 = new Empty_1.Empty();
165
243
  }
166
- this.cpu.reset();
167
- }
168
- start() {
169
- this.cpu.reset();
170
- this.startTime = Date.now();
171
- this.isRunning = true;
172
- this.isAlive = true;
173
- this.loop();
174
- }
175
- end() {
176
- this.isRunning = false;
177
- this.isAlive = false;
178
244
  }
179
245
  run() {
180
246
  this.isRunning = true;
247
+ this.loop();
181
248
  }
182
249
  stop() {
183
250
  this.isRunning = false;
251
+ if (this.loopHandle) {
252
+ if (typeof clearImmediate !== 'undefined') {
253
+ clearImmediate(this.loopHandle);
254
+ }
255
+ else {
256
+ clearTimeout(this.loopHandle);
257
+ }
258
+ this.loopHandle = undefined;
259
+ }
184
260
  }
185
261
  step() {
186
262
  // Step through one complete instruction
187
263
  const cyclesExecuted = this.cpu.step();
188
264
  // Tick IO cards for each cycle of the instruction
189
265
  for (let i = 0; i < cyclesExecuted; i++) {
190
- // SerialCard must be cycle-accurate
266
+ // ACIA must be cycle-accurate
191
267
  this.io5.tick(this.frequency);
192
268
  this.ioCycleAccumulator++;
193
269
  if (this.ioCycleAccumulator >= this.ioTickInterval) {
194
- // Skip ticking RAMCard IO1 and IO2 since they have no timing behavior
270
+ // Skip ticking RAMBank IO1 and IO2 since they have no timing behavior
195
271
  this.io3.tick(this.frequency);
196
272
  this.io4.tick(this.frequency);
197
273
  this.io6.tick(this.frequency);
@@ -201,15 +277,27 @@ class Machine {
201
277
  }
202
278
  }
203
279
  }
280
+ reset(coldStart) {
281
+ this.cpu.reset();
282
+ this.ram.reset(coldStart);
283
+ this.io1.reset(coldStart);
284
+ this.io2.reset(coldStart);
285
+ this.io3.reset(coldStart);
286
+ this.io4.reset(coldStart);
287
+ this.io5.reset(coldStart);
288
+ this.io6.reset(coldStart);
289
+ this.io7.reset(coldStart);
290
+ this.io8.reset(coldStart);
291
+ }
204
292
  tick() {
205
293
  // Execute one CPU clock cycle
206
294
  this.cpu.tick();
207
- // SerialCard must be cycle-accurate
295
+ // ACIA must be cycle-accurate
208
296
  this.io5.tick(this.frequency);
209
297
  // Tick other IO cards at intervals
210
298
  this.ioCycleAccumulator++;
211
299
  if (this.ioCycleAccumulator >= this.ioTickInterval) {
212
- // Skip ticking RAMCard IO1 and IO2 since they have no timing behavior
300
+ // Skip ticking RAMBank IO1 and IO2 since they have no timing behavior
213
301
  this.io3.tick(this.frequency);
214
302
  this.io4.tick(this.frequency);
215
303
  this.io6.tick(this.frequency);
@@ -219,22 +307,25 @@ class Machine {
219
307
  }
220
308
  }
221
309
  onReceive(data) {
222
- this.io5.onData(data); // Pass data to Serial card
310
+ if (this.target !== 'vcs') {
311
+ this.io5.onData(data); // Pass data to Serial card
312
+ }
223
313
  }
224
314
  onKeyDown(scancode) {
225
- var _a;
315
+ var _a, _b, _c;
226
316
  if (this.target === 'kim') {
227
317
  (_a = this.keypadAttachment) === null || _a === void 0 ? void 0 : _a.updateKey(scancode, true);
228
318
  }
229
319
  else {
230
- this.keyboardMatrixAttachment.updateKey(scancode, true);
231
- this.keyboardEncoderAttachment.updateKey(scancode, true);
320
+ (_b = this.keyboardMatrixAttachment) === null || _b === void 0 ? void 0 : _b.updateKey(scancode, true);
321
+ (_c = this.keyboardEncoderAttachment) === null || _c === void 0 ? void 0 : _c.updateKey(scancode, true);
232
322
  }
233
323
  }
234
324
  onKeyUp(scancode) {
325
+ var _a, _b;
235
326
  if (this.target !== 'kim') {
236
- this.keyboardMatrixAttachment.updateKey(scancode, false);
237
- this.keyboardEncoderAttachment.updateKey(scancode, false);
327
+ (_a = this.keyboardMatrixAttachment) === null || _a === void 0 ? void 0 : _a.updateKey(scancode, false);
328
+ (_b = this.keyboardEncoderAttachment) === null || _b === void 0 ? void 0 : _b.updateKey(scancode, false);
238
329
  }
239
330
  }
240
331
  onJoystickA(buttons) {
@@ -250,9 +341,6 @@ class Machine {
250
341
  //
251
342
  loop() {
252
343
  var _a;
253
- if (!this.isAlive) {
254
- return;
255
- }
256
344
  const now = performance.now();
257
345
  const elapsedMs = now - this.previousTime;
258
346
  this.previousTime = now;
@@ -267,11 +355,11 @@ class Machine {
267
355
  if (ticksToRun > 0) {
268
356
  for (let i = 0; i < ticksToRun; i++) {
269
357
  this.cpu.tick();
270
- // SerialCard must be cycle-accurate
358
+ // ACIA must be cycle-accurate
271
359
  this.io5.tick(this.frequency);
272
360
  this.ioCycleAccumulator++;
273
361
  if (this.ioCycleAccumulator >= this.ioTickInterval) {
274
- // Skip ticking RAMCard IO1 and IO2 since they have no timing behavior
362
+ // Skip ticking RAMBank IO1 and IO2 since they have no timing behavior
275
363
  this.io3.tick(this.frequency);
276
364
  this.io4.tick(this.frequency);
277
365
  this.io6.tick(this.frequency);
@@ -289,30 +377,25 @@ class Machine {
289
377
  this.frames += 1;
290
378
  }
291
379
  else if (this.render && (this.target === 'cob' || this.target === 'vcs')) {
292
- const videoCard = this.io8;
293
- if (videoCard.frameReady) {
294
- videoCard.frameReady = false;
380
+ const Video = this.io8;
381
+ if (Video.frameReady) {
382
+ Video.frameReady = false;
295
383
  this.render();
296
384
  this.frames += 1;
297
385
  }
298
386
  }
299
- setImmediate(() => this.loop());
387
+ if (this.isRunning) {
388
+ if (typeof setImmediate !== 'undefined') {
389
+ this.loopHandle = setImmediate(() => this.loop());
390
+ }
391
+ else {
392
+ this.loopHandle = setTimeout(() => this.loop(), 0);
393
+ }
394
+ }
300
395
  }
301
396
  //
302
397
  // Bus Operations
303
398
  //
304
- reset(coldStart) {
305
- this.cpu.reset();
306
- this.ram.reset(coldStart);
307
- this.io1.reset(coldStart);
308
- this.io2.reset(coldStart);
309
- this.io3.reset(coldStart);
310
- this.io4.reset(coldStart);
311
- this.io5.reset(coldStart);
312
- this.io6.reset(coldStart);
313
- this.io7.reset(coldStart);
314
- this.io8.reset(coldStart);
315
- }
316
399
  read(address) {
317
400
  switch (true) {
318
401
  case (this.cart && address >= Cart_1.Cart.CODE && address <= Cart_1.Cart.END):