ac6502 1.2.0 → 1.4.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 (182) hide show
  1. package/README.md +12 -12
  2. package/dist/components/CPU.d.ts +162 -0
  3. package/dist/components/Cart.d.ts +9 -0
  4. package/dist/components/IO/ACIA.d.ts +76 -0
  5. package/dist/components/IO/ACIA.js +282 -0
  6. package/dist/components/IO/ACIA.js.map +1 -0
  7. package/dist/components/IO/Attachments/Attachment.d.ts +112 -0
  8. package/dist/components/IO/Attachments/Attachment.js +71 -0
  9. package/dist/components/IO/Attachments/Attachment.js.map +1 -0
  10. package/dist/components/IO/Attachments/JoystickAttachment.d.ts +53 -0
  11. package/dist/components/IO/Attachments/JoystickAttachment.js +90 -0
  12. package/dist/components/IO/Attachments/JoystickAttachment.js.map +1 -0
  13. package/dist/components/IO/Attachments/KeyboardEncoderAttachment.d.ts +63 -0
  14. package/dist/components/IO/Attachments/KeyboardEncoderAttachment.js +489 -0
  15. package/dist/components/IO/Attachments/KeyboardEncoderAttachment.js.map +1 -0
  16. package/dist/components/IO/Attachments/KeyboardMatrixAttachment.d.ts +44 -0
  17. package/dist/components/IO/Attachments/KeyboardMatrixAttachment.js +274 -0
  18. package/dist/components/IO/Attachments/KeyboardMatrixAttachment.js.map +1 -0
  19. package/dist/components/IO/Attachments/KeypadAttachment.d.ts +47 -0
  20. package/dist/components/IO/Attachments/KeypadAttachment.js +141 -0
  21. package/dist/components/IO/Attachments/KeypadAttachment.js.map +1 -0
  22. package/dist/components/IO/Attachments/LCDAttachment.d.ts +110 -0
  23. package/dist/components/IO/Attachments/LCDAttachment.js +716 -0
  24. package/dist/components/IO/Attachments/LCDAttachment.js.map +1 -0
  25. package/dist/components/IO/Attachments/SNESAttachment.d.ts +85 -0
  26. package/dist/components/IO/Attachments/SNESAttachment.js +184 -0
  27. package/dist/components/IO/Attachments/SNESAttachment.js.map +1 -0
  28. package/dist/components/IO/DevOutputBoard.d.ts +19 -0
  29. package/dist/components/IO/DevOutputBoard.js +33 -0
  30. package/dist/components/IO/DevOutputBoard.js.map +1 -0
  31. package/dist/components/IO/Empty.d.ts +9 -0
  32. package/dist/components/IO/Empty.js +5 -7
  33. package/dist/components/IO/Empty.js.map +1 -1
  34. package/dist/components/IO/EmptyCard.d.ts +9 -0
  35. package/dist/components/IO/GPIOAttachments/GPIOAttachment.d.ts +112 -0
  36. package/dist/components/IO/GPIOAttachments/GPIOJoystickAttachment.d.ts +53 -0
  37. package/dist/components/IO/GPIOAttachments/GPIOKeyboardEncoderAttachment.d.ts +63 -0
  38. package/dist/components/IO/GPIOAttachments/GPIOKeyboardMatrixAttachment.d.ts +44 -0
  39. package/dist/components/IO/GPIOAttachments/GPIOKeypadAttachment.d.ts +47 -0
  40. package/dist/components/IO/GPIOAttachments/GPIOLCDAttachment.d.ts +110 -0
  41. package/dist/components/IO/GPIOCard.d.ts +105 -0
  42. package/dist/components/IO/GPIOCard.js.map +1 -1
  43. package/dist/components/IO/RAMBank.d.ts +37 -0
  44. package/dist/components/IO/RAMBank.js +63 -0
  45. package/dist/components/IO/RAMBank.js.map +1 -0
  46. package/dist/components/IO/RAMCard.d.ts +37 -0
  47. package/dist/components/IO/RTC.d.ts +107 -0
  48. package/dist/components/IO/RTC.js +483 -0
  49. package/dist/components/IO/RTC.js.map +1 -0
  50. package/dist/components/IO/RTCCard.d.ts +107 -0
  51. package/dist/components/IO/SerialCard.d.ts +76 -0
  52. package/dist/components/IO/Sound.d.ts +120 -0
  53. package/dist/components/IO/Sound.js +622 -0
  54. package/dist/components/IO/Sound.js.map +1 -0
  55. package/dist/components/IO/SoundCard.d.ts +120 -0
  56. package/dist/components/IO/Storage.d.ts +74 -0
  57. package/dist/components/IO/Storage.js +409 -0
  58. package/dist/components/IO/Storage.js.map +1 -0
  59. package/dist/components/IO/StorageCard.d.ts +74 -0
  60. package/dist/components/IO/Terminal.d.ts +19 -0
  61. package/dist/components/IO/Terminal.js +33 -0
  62. package/dist/components/IO/Terminal.js.map +1 -0
  63. package/dist/components/IO/VIA.d.ts +105 -0
  64. package/dist/components/IO/VIA.js +597 -0
  65. package/dist/components/IO/VIA.js.map +1 -0
  66. package/dist/components/IO/Video.d.ts +141 -0
  67. package/dist/components/IO/Video.js +630 -0
  68. package/dist/components/IO/Video.js.map +1 -0
  69. package/dist/components/IO/VideoCard.d.ts +141 -0
  70. package/dist/components/IO.d.ts +8 -0
  71. package/dist/components/Machine.d.ts +62 -0
  72. package/dist/components/Machine.js +260 -153
  73. package/dist/components/Machine.js.map +1 -1
  74. package/dist/components/RAM.d.ts +9 -0
  75. package/dist/components/ROM.d.ts +9 -0
  76. package/dist/index.d.ts +2 -0
  77. package/dist/index.js +61 -28
  78. package/dist/index.js.map +1 -1
  79. package/dist/lib.d.ts +22 -0
  80. package/dist/lib.js +47 -0
  81. package/dist/lib.js.map +1 -0
  82. package/dist/tests/CPU.test.d.ts +1 -0
  83. package/dist/tests/Cart.test.d.ts +1 -0
  84. package/dist/tests/IO/ACIA.test.d.ts +1 -0
  85. package/dist/tests/IO/ACIA.test.js +423 -0
  86. package/dist/tests/IO/ACIA.test.js.map +1 -0
  87. package/dist/tests/IO/Attachments/Attachment.test.d.ts +1 -0
  88. package/dist/tests/IO/Attachments/Attachment.test.js +339 -0
  89. package/dist/tests/IO/Attachments/Attachment.test.js.map +1 -0
  90. package/dist/tests/IO/Attachments/JoystickAttachment.test.d.ts +1 -0
  91. package/dist/tests/IO/Attachments/JoystickAttachment.test.js +126 -0
  92. package/dist/tests/IO/Attachments/JoystickAttachment.test.js.map +1 -0
  93. package/dist/tests/IO/Attachments/KeyboardEncoderAttachment.test.d.ts +1 -0
  94. package/dist/tests/IO/Attachments/KeyboardEncoderAttachment.test.js +779 -0
  95. package/dist/tests/IO/Attachments/KeyboardEncoderAttachment.test.js.map +1 -0
  96. package/dist/tests/IO/Attachments/KeyboardMatrixAttachment.test.d.ts +1 -0
  97. package/dist/tests/IO/Attachments/KeyboardMatrixAttachment.test.js +355 -0
  98. package/dist/tests/IO/Attachments/KeyboardMatrixAttachment.test.js.map +1 -0
  99. package/dist/tests/IO/Attachments/KeypadAttachment.test.d.ts +1 -0
  100. package/dist/tests/IO/Attachments/KeypadAttachment.test.js +323 -0
  101. package/dist/tests/IO/Attachments/KeypadAttachment.test.js.map +1 -0
  102. package/dist/tests/IO/Attachments/LCDAttachment.test.d.ts +1 -0
  103. package/dist/tests/IO/Attachments/LCDAttachment.test.js +627 -0
  104. package/dist/tests/IO/Attachments/LCDAttachment.test.js.map +1 -0
  105. package/dist/tests/IO/Attachments/SNESAttachment.test.d.ts +1 -0
  106. package/dist/tests/IO/Attachments/SNESAttachment.test.js +331 -0
  107. package/dist/tests/IO/Attachments/SNESAttachment.test.js.map +1 -0
  108. package/dist/tests/IO/Empty.test.d.ts +1 -0
  109. package/dist/tests/IO/Empty.test.js +121 -0
  110. package/dist/tests/IO/Empty.test.js.map +1 -0
  111. package/dist/tests/IO/GPIOAttachments/GPIOAttachment.test.d.ts +1 -0
  112. package/dist/tests/IO/GPIOAttachments/GPIOJoystickAttachment.test.d.ts +1 -0
  113. package/dist/tests/IO/GPIOAttachments/GPIOKeyboardEncoderAttachment.test.d.ts +1 -0
  114. package/dist/tests/IO/GPIOAttachments/GPIOKeyboardMatrixAttachment.test.d.ts +1 -0
  115. package/dist/tests/IO/GPIOAttachments/GPIOKeypadAttachment.test.d.ts +1 -0
  116. package/dist/tests/IO/GPIOAttachments/GPIOLCDAttachment.test.d.ts +1 -0
  117. package/dist/tests/IO/GPIOCard.test.d.ts +1 -0
  118. package/dist/tests/IO/GPIOCard.test.js.map +1 -1
  119. package/dist/tests/IO/RAMBank.test.d.ts +1 -0
  120. package/dist/tests/IO/RAMBank.test.js +229 -0
  121. package/dist/tests/IO/RAMBank.test.js.map +1 -0
  122. package/dist/tests/IO/RAMCard.test.d.ts +1 -0
  123. package/dist/tests/IO/RTC.test.d.ts +1 -0
  124. package/dist/tests/IO/RTC.test.js +177 -0
  125. package/dist/tests/IO/RTC.test.js.map +1 -0
  126. package/dist/tests/IO/RTCCard.test.d.ts +1 -0
  127. package/dist/tests/IO/SerialCard.test.d.ts +1 -0
  128. package/dist/tests/IO/Sound.test.d.ts +1 -0
  129. package/dist/tests/IO/Sound.test.js +528 -0
  130. package/dist/tests/IO/Sound.test.js.map +1 -0
  131. package/dist/tests/IO/SoundCard.test.d.ts +1 -0
  132. package/dist/tests/IO/Storage.test.d.ts +1 -0
  133. package/dist/tests/IO/Storage.test.js +656 -0
  134. package/dist/tests/IO/Storage.test.js.map +1 -0
  135. package/dist/tests/IO/StorageCard.test.d.ts +1 -0
  136. package/dist/tests/IO/VIA.test.d.ts +1 -0
  137. package/dist/tests/IO/VIA.test.js +503 -0
  138. package/dist/tests/IO/VIA.test.js.map +1 -0
  139. package/dist/tests/IO/Video.test.d.ts +1 -0
  140. package/dist/tests/IO/Video.test.js +549 -0
  141. package/dist/tests/IO/Video.test.js.map +1 -0
  142. package/dist/tests/IO/VideoCard.test.d.ts +1 -0
  143. package/dist/tests/Machine.test.d.ts +1 -0
  144. package/dist/tests/Machine.test.js +27 -42
  145. package/dist/tests/Machine.test.js.map +1 -1
  146. package/dist/tests/RAM.test.d.ts +1 -0
  147. package/dist/tests/ROM.test.d.ts +1 -0
  148. package/package.json +5 -3
  149. package/src/components/IO/{SerialCard.ts → ACIA.ts} +2 -2
  150. package/src/components/IO/{GPIOAttachments/GPIOAttachment.ts → Attachments/Attachment.ts} +2 -2
  151. package/src/components/IO/{GPIOAttachments/GPIOJoystickAttachment.ts → Attachments/JoystickAttachment.ts} +3 -3
  152. package/src/components/IO/{GPIOAttachments/GPIOKeyboardEncoderAttachment.ts → Attachments/KeyboardEncoderAttachment.ts} +3 -3
  153. package/src/components/IO/{GPIOAttachments/GPIOKeyboardMatrixAttachment.ts → Attachments/KeyboardMatrixAttachment.ts} +5 -5
  154. package/src/components/IO/{GPIOAttachments/GPIOKeypadAttachment.ts → Attachments/KeypadAttachment.ts} +3 -3
  155. package/src/components/IO/{GPIOAttachments/GPIOLCDAttachment.ts → Attachments/LCDAttachment.ts} +7 -7
  156. package/src/components/IO/{EmptyCard.ts → Empty.ts} +1 -1
  157. package/src/components/IO/{RAMCard.ts → RAMBank.ts} +8 -8
  158. package/src/components/IO/{RTCCard.ts → RTC.ts} +1 -1
  159. package/src/components/IO/{SoundCard.ts → Sound.ts} +2 -2
  160. package/src/components/IO/{StorageCard.ts → Storage.ts} +70 -73
  161. package/src/components/IO/Terminal.ts +34 -0
  162. package/src/components/IO/{GPIOCard.ts → VIA.ts} +64 -64
  163. package/src/components/IO/{VideoCard.ts → Video.ts} +1 -1
  164. package/src/components/Machine.ts +286 -160
  165. package/src/index.ts +65 -35
  166. package/src/lib.ts +27 -0
  167. package/src/tests/IO/{SerialCard.test.ts → ACIA.test.ts} +5 -5
  168. package/src/tests/IO/{GPIOAttachments/GPIOAttachment.test.ts → Attachments/Attachment.test.ts} +12 -12
  169. package/src/tests/IO/{GPIOAttachments/GPIOJoystickAttachment.test.ts → Attachments/JoystickAttachment.test.ts} +23 -23
  170. package/src/tests/IO/{GPIOAttachments/GPIOKeyboardEncoderAttachment.test.ts → Attachments/KeyboardEncoderAttachment.test.ts} +4 -4
  171. package/src/tests/IO/{GPIOAttachments/GPIOKeyboardMatrixAttachment.test.ts → Attachments/KeyboardMatrixAttachment.test.ts} +5 -5
  172. package/src/tests/IO/{GPIOAttachments/GPIOKeypadAttachment.test.ts → Attachments/KeypadAttachment.test.ts} +38 -38
  173. package/src/tests/IO/{GPIOAttachments/GPIOLCDAttachment.test.ts → Attachments/LCDAttachment.test.ts} +12 -12
  174. package/src/tests/IO/Empty.test.ts +143 -0
  175. package/src/tests/IO/{RAMCard.test.ts → RAMBank.test.ts} +33 -33
  176. package/src/tests/IO/{RTCCard.test.ts → RTC.test.ts} +6 -6
  177. package/src/tests/IO/{SoundCard.test.ts → Sound.test.ts} +6 -6
  178. package/src/tests/IO/{StorageCard.test.ts → Storage.test.ts} +34 -25
  179. package/src/tests/IO/{GPIOCard.test.ts → VIA.test.ts} +7 -7
  180. package/src/tests/IO/{VideoCard.test.ts → Video.test.ts} +13 -13
  181. package/src/tests/Machine.test.ts +31 -38
  182. package/tsconfig.json +1 -0
@@ -1,9 +1,7 @@
1
1
  import { IO } from '../IO'
2
- import { readFile, writeFile } from 'fs/promises'
3
- import { existsSync } from 'fs'
4
2
 
5
3
  /**
6
- * StorageCard - Emulates a Compact Flash card in 8-bit IDE mode
4
+ * Storage - Emulates a Compact Flash card in 8-bit IDE mode
7
5
  *
8
6
  * Emulates a 128MB CF card with ATA-style register interface.
9
7
  * Uses LBA (Logical Block Addressing) for sector access.
@@ -25,12 +23,12 @@ import { existsSync } from 'fs'
25
23
  * 0xEC: Identify Drive
26
24
  * 0xEF: Set Features (accepted but not implemented)
27
25
  */
28
- export class StorageCard implements IO {
26
+ export class Storage implements IO {
29
27
 
30
28
  // Constants
31
29
  private static readonly STORAGE_SIZE = 128 * 1024 * 1024 // 128MB
32
30
  private static readonly SECTOR_SIZE = 512
33
- private static readonly SECTOR_COUNT = StorageCard.STORAGE_SIZE / StorageCard.SECTOR_SIZE // 262144 sectors
31
+ private static readonly SECTOR_COUNT = Storage.STORAGE_SIZE / Storage.SECTOR_SIZE // 262144 sectors
34
32
 
35
33
  // Status Register Flags
36
34
  private static readonly STATUS_ERR = 0x01 // Error
@@ -43,13 +41,13 @@ export class StorageCard implements IO {
43
41
  private static readonly ERR_IDNF = 0x10 // ID Not Found
44
42
 
45
43
  // Storage and Identity data (in-memory simulation)
46
- private storage: Buffer
47
- private identity: Buffer
44
+ private storage: Uint8Array
45
+ private identity: Uint8Array
48
46
 
49
47
  // Data buffer (512 bytes)
50
- private buffer: Buffer = Buffer.alloc(StorageCard.SECTOR_SIZE)
48
+ private buffer: Uint8Array = new Uint8Array(Storage.SECTOR_SIZE)
51
49
  private bufferIndex: number = 0
52
- private commandDataSize: number = StorageCard.SECTOR_SIZE
50
+ private commandDataSize: number = Storage.SECTOR_SIZE
53
51
  private sectorOffset: number = 0
54
52
 
55
53
  // Registers
@@ -72,8 +70,8 @@ export class StorageCard implements IO {
72
70
 
73
71
  constructor() {
74
72
  // Initialize storage and identity buffers
75
- this.storage = Buffer.alloc(StorageCard.STORAGE_SIZE, 0x00)
76
- this.identity = Buffer.alloc(StorageCard.SECTOR_SIZE)
73
+ this.storage = new Uint8Array(Storage.STORAGE_SIZE)
74
+ this.identity = new Uint8Array(Storage.SECTOR_SIZE)
77
75
  this.generateIdentity()
78
76
  this.reset(true)
79
77
  }
@@ -137,7 +135,7 @@ export class StorageCard implements IO {
137
135
 
138
136
  reset(coldStart: boolean): void {
139
137
  this.bufferIndex = 0x0000
140
- this.commandDataSize = StorageCard.SECTOR_SIZE
138
+ this.commandDataSize = Storage.SECTOR_SIZE
141
139
  this.sectorOffset = 0
142
140
 
143
141
  this.error = 0x00
@@ -147,7 +145,7 @@ export class StorageCard implements IO {
147
145
  this.lba1 = 0x00
148
146
  this.lba2 = 0x00
149
147
  this.lba3 = 0xE0
150
- this.status = 0x00 | StorageCard.STATUS_RDY
148
+ this.status = 0x00 | Storage.STATUS_RDY
151
149
  this.command = 0x00
152
150
 
153
151
  this.isIdentifying = false
@@ -162,36 +160,36 @@ export class StorageCard implements IO {
162
160
 
163
161
  private executeCommand(): void {
164
162
  // New command so clear errors and flags
165
- this.status &= ~StorageCard.STATUS_ERR
166
- this.status &= ~StorageCard.STATUS_DRQ
163
+ this.status &= ~Storage.STATUS_ERR
164
+ this.status &= ~Storage.STATUS_DRQ
167
165
  this.error = 0x00
168
- this.commandDataSize = StorageCard.SECTOR_SIZE * this.sectorCount
166
+ this.commandDataSize = Storage.SECTOR_SIZE * this.sectorCount
169
167
  this.bufferIndex = 0
170
168
  this.sectorOffset = 0
171
169
 
172
170
  // Check if already executing a command
173
171
  if (this.isTransferring || this.isIdentifying) {
174
- this.status |= StorageCard.STATUS_ERR
175
- this.error |= StorageCard.ERR_ABRT
172
+ this.status |= Storage.STATUS_ERR
173
+ this.error |= Storage.ERR_ABRT
176
174
  return
177
175
  }
178
176
 
179
177
  switch (this.command) {
180
178
  case 0xC0: { // Erase sector
181
179
  if (!this.sectorValid()) {
182
- this.status |= StorageCard.STATUS_ERR
183
- this.error |= StorageCard.ERR_ABRT | StorageCard.ERR_IDNF
180
+ this.status |= Storage.STATUS_ERR
181
+ this.error |= Storage.ERR_ABRT | Storage.ERR_IDNF
184
182
  } else {
185
- const offset = this.sectorIndex() * StorageCard.SECTOR_SIZE
186
- this.storage.fill(0x00, offset, offset + StorageCard.SECTOR_SIZE)
183
+ const offset = this.sectorIndex() * Storage.SECTOR_SIZE
184
+ this.storage.fill(0x00, offset, offset + Storage.SECTOR_SIZE)
187
185
  }
188
186
  break
189
187
  }
190
188
 
191
189
  case 0xEC: { // Identify drive
192
- this.identity.copy(this.buffer, 0, 0, StorageCard.SECTOR_SIZE)
193
- this.commandDataSize = StorageCard.SECTOR_SIZE
194
- this.status |= StorageCard.STATUS_DRQ
190
+ this.buffer.set(this.identity.subarray(0, Storage.SECTOR_SIZE))
191
+ this.commandDataSize = Storage.SECTOR_SIZE
192
+ this.status |= Storage.STATUS_DRQ
195
193
  this.isIdentifying = true
196
194
  break
197
195
  }
@@ -199,13 +197,13 @@ export class StorageCard implements IO {
199
197
  case 0x20: // Read sector
200
198
  case 0x21:
201
199
  if (!this.sectorValid()) {
202
- this.status |= StorageCard.STATUS_ERR
203
- this.error |= StorageCard.ERR_ABRT | StorageCard.ERR_IDNF
200
+ this.status |= Storage.STATUS_ERR
201
+ this.error |= Storage.ERR_ABRT | Storage.ERR_IDNF
204
202
  } else {
205
203
  // Load first sector into buffer
206
- const offset = this.sectorIndex() * StorageCard.SECTOR_SIZE
207
- this.storage.copy(this.buffer, 0, offset, offset + StorageCard.SECTOR_SIZE)
208
- this.status |= StorageCard.STATUS_DRQ
204
+ const offset = this.sectorIndex() * Storage.SECTOR_SIZE
205
+ this.buffer.set(this.storage.subarray(offset, offset + Storage.SECTOR_SIZE))
206
+ this.status |= Storage.STATUS_DRQ
209
207
  this.isTransferring = true
210
208
  }
211
209
  break
@@ -217,18 +215,18 @@ export class StorageCard implements IO {
217
215
  case 0x30: // Write sector
218
216
  case 0x31:
219
217
  if (!this.sectorValid()) {
220
- this.status |= StorageCard.STATUS_ERR
221
- this.error |= StorageCard.ERR_ABRT | StorageCard.ERR_IDNF
218
+ this.status |= Storage.STATUS_ERR
219
+ this.error |= Storage.ERR_ABRT | Storage.ERR_IDNF
222
220
  } else {
223
- this.status |= StorageCard.STATUS_DRQ
221
+ this.status |= Storage.STATUS_DRQ
224
222
  this.isTransferring = true
225
223
  }
226
224
  break
227
225
 
228
226
  default:
229
227
  // Unsupported command
230
- this.status |= StorageCard.STATUS_ERR
231
- this.error |= StorageCard.ERR_ABRT
228
+ this.status |= Storage.STATUS_ERR
229
+ this.error |= Storage.ERR_ABRT
232
230
  break
233
231
  }
234
232
  }
@@ -242,14 +240,14 @@ export class StorageCard implements IO {
242
240
  } else {
243
241
  this.bufferIndex = 0
244
242
  this.isIdentifying = false
245
- this.status &= ~StorageCard.STATUS_DRQ
243
+ this.status &= ~Storage.STATUS_DRQ
246
244
  }
247
245
 
248
246
  return data
249
247
  } else if (this.isTransferring) {
250
248
  const data = this.buffer[this.bufferIndex]
251
249
 
252
- if (this.bufferIndex < StorageCard.SECTOR_SIZE - 1) {
250
+ if (this.bufferIndex < Storage.SECTOR_SIZE - 1) {
253
251
  this.bufferIndex++
254
252
  } else {
255
253
  this.bufferIndex = 0
@@ -257,11 +255,11 @@ export class StorageCard implements IO {
257
255
 
258
256
  if (this.sectorOffset < this.sectorCount) {
259
257
  // Load the next sector
260
- const offset = (this.sectorIndex() + this.sectorOffset) * StorageCard.SECTOR_SIZE
261
- this.storage.copy(this.buffer, 0, offset, offset + StorageCard.SECTOR_SIZE)
258
+ const offset = (this.sectorIndex() + this.sectorOffset) * Storage.SECTOR_SIZE
259
+ this.buffer.set(this.storage.subarray(offset, offset + Storage.SECTOR_SIZE))
262
260
  } else {
263
261
  this.isTransferring = false
264
- this.status &= ~StorageCard.STATUS_DRQ
262
+ this.status &= ~Storage.STATUS_DRQ
265
263
  }
266
264
  }
267
265
 
@@ -274,21 +272,21 @@ export class StorageCard implements IO {
274
272
  private writeBuffer(value: number): void {
275
273
  this.buffer[this.bufferIndex] = value
276
274
 
277
- if (this.bufferIndex < StorageCard.SECTOR_SIZE - 1) {
275
+ if (this.bufferIndex < Storage.SECTOR_SIZE - 1) {
278
276
  this.bufferIndex++
279
277
  } else {
280
278
  this.bufferIndex = 0
281
279
 
282
280
  // Write the current sector to storage
283
- const offset = (this.sectorIndex() + this.sectorOffset) * StorageCard.SECTOR_SIZE
284
- this.buffer.copy(this.storage, offset, 0, StorageCard.SECTOR_SIZE)
281
+ const offset = (this.sectorIndex() + this.sectorOffset) * Storage.SECTOR_SIZE
282
+ this.storage.set(this.buffer.subarray(0, Storage.SECTOR_SIZE), offset)
285
283
 
286
284
  this.sectorOffset++
287
285
 
288
286
  // Check if all sectors have been written
289
287
  if (this.sectorOffset >= this.sectorCount) {
290
288
  this.isTransferring = false
291
- this.status &= ~StorageCard.STATUS_DRQ
289
+ this.status &= ~Storage.STATUS_DRQ
292
290
  }
293
291
  }
294
292
  }
@@ -298,7 +296,7 @@ export class StorageCard implements IO {
298
296
  }
299
297
 
300
298
  private sectorValid(): boolean {
301
- return this.sectorIndex() < StorageCard.SECTOR_COUNT
299
+ return this.sectorIndex() < Storage.SECTOR_COUNT
302
300
  }
303
301
 
304
302
  private generateIdentity(): void {
@@ -434,40 +432,39 @@ export class StorageCard implements IO {
434
432
  }
435
433
 
436
434
  /**
437
- * Load storage data from a file
438
- * If the file doesn't exist, storage remains empty (initialized to 0x00)
435
+ * Load storage data from a Uint8Array, ArrayBuffer, or number array
436
+ * If data is not provided or wrong size, storage remains empty
439
437
  */
440
- async loadFromFile(filePath: string): Promise<void> {
441
- try {
442
- if (existsSync(filePath)) {
443
- const data = await readFile(filePath)
444
- // Ensure the file is exactly the expected size
445
- if (data.length === StorageCard.STORAGE_SIZE) {
446
- data.copy(this.storage, 0, 0, StorageCard.STORAGE_SIZE)
447
- console.log(`Storage loaded from: ${filePath}`)
448
- } else {
449
- console.warn(`Warning: Storage file size mismatch. Expected ${StorageCard.STORAGE_SIZE} bytes, got ${data.length} bytes.`)
450
- console.warn('Storage will remain empty.')
451
- }
452
- } else {
453
- console.log(`Storage file not found: ${filePath}`)
454
- console.log('A new storage file will be created on exit.')
455
- }
456
- } catch (error) {
457
- console.error('Error loading storage file:', error)
438
+ loadData(data: Uint8Array | ArrayBuffer | number[] | null): void {
439
+ if (!data) {
440
+ console.log('No storage data provided. Storage will remain empty.')
441
+ return
442
+ }
443
+
444
+ let uint8Data: Uint8Array
445
+ if (data instanceof ArrayBuffer) {
446
+ uint8Data = new Uint8Array(data)
447
+ } else if (data instanceof Uint8Array) {
448
+ uint8Data = data
449
+ } else {
450
+ uint8Data = new Uint8Array(data)
451
+ }
452
+
453
+ // Ensure the data is exactly the expected size
454
+ if (uint8Data.length === Storage.STORAGE_SIZE) {
455
+ this.storage.set(uint8Data)
456
+ console.log(`Storage loaded (${Storage.STORAGE_SIZE} bytes)`)
457
+ } else {
458
+ console.warn(`Warning: Storage data size mismatch. Expected ${Storage.STORAGE_SIZE} bytes, got ${uint8Data.length} bytes.`)
459
+ console.warn('Storage will remain empty.')
458
460
  }
459
461
  }
460
462
 
461
463
  /**
462
- * Save storage data to a file
464
+ * Get storage data as Uint8Array for saving
463
465
  */
464
- async saveToFile(filePath: string): Promise<void> {
465
- try {
466
- await writeFile(filePath, this.storage)
467
- console.log(`Storage saved to: ${filePath}`)
468
- } catch (error) {
469
- console.error('Error saving storage file:', error)
470
- }
466
+ getData(): Uint8Array {
467
+ return new Uint8Array(this.storage)
471
468
  }
472
469
 
473
470
  }
@@ -0,0 +1,34 @@
1
+ import { IO } from '../IO'
2
+ import { VTAC } from 'vtac-terminal'
3
+
4
+ /**
5
+ * Terminal - Emulates the VTAC fantasy terminal
6
+ *
7
+ * Register Map:
8
+ * $00: Data / Status Register
9
+ * Write: sends byte to VTAC for processing
10
+ * Read: always returns 0 (bit 7 is a busy flag on the real device; busy is never set here)
11
+ */
12
+ export class Terminal implements IO {
13
+
14
+ raiseIRQ = () => {}
15
+ raiseNMI = () => {}
16
+
17
+ readonly vtac: VTAC = new VTAC()
18
+
19
+ read(address: number): number {
20
+ // Status register: bit 7 is busy flag on real device, never busy in emulation
21
+ return 0
22
+ }
23
+
24
+ write(address: number, data: number): void {
25
+ const register = address & 0x00
26
+ if (register === 0x00) {
27
+ this.vtac.parse(data)
28
+ }
29
+ }
30
+
31
+ tick(frequency: number): void {}
32
+ reset(coldStart: boolean): void {}
33
+
34
+ }