ac6502 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +261 -0
- package/dist/components/CPU.js +1170 -0
- package/dist/components/CPU.js.map +1 -0
- package/dist/components/Cart.js +23 -0
- package/dist/components/Cart.js.map +1 -0
- package/dist/components/IO/Empty.js +19 -0
- package/dist/components/IO/Empty.js.map +1 -0
- package/dist/components/IO/GPIOAttachments/GPIOAttachment.js +71 -0
- package/dist/components/IO/GPIOAttachments/GPIOAttachment.js.map +1 -0
- package/dist/components/IO/GPIOAttachments/GPIOJoystickAttachment.js +90 -0
- package/dist/components/IO/GPIOAttachments/GPIOJoystickAttachment.js.map +1 -0
- package/dist/components/IO/GPIOAttachments/GPIOKeyboardEncoderAttachment.js +489 -0
- package/dist/components/IO/GPIOAttachments/GPIOKeyboardEncoderAttachment.js.map +1 -0
- package/dist/components/IO/GPIOAttachments/GPIOKeyboardMatrixAttachment.js +274 -0
- package/dist/components/IO/GPIOAttachments/GPIOKeyboardMatrixAttachment.js.map +1 -0
- package/dist/components/IO/GPIOCard.js +597 -0
- package/dist/components/IO/GPIOCard.js.map +1 -0
- package/dist/components/IO/InputBoard.js +19 -0
- package/dist/components/IO/InputBoard.js.map +1 -0
- package/dist/components/IO/LCDCard.js +19 -0
- package/dist/components/IO/LCDCard.js.map +1 -0
- package/dist/components/IO/RAMCard.js +63 -0
- package/dist/components/IO/RAMCard.js.map +1 -0
- package/dist/components/IO/RTCCard.js +483 -0
- package/dist/components/IO/RTCCard.js.map +1 -0
- package/dist/components/IO/SerialCard.js +282 -0
- package/dist/components/IO/SerialCard.js.map +1 -0
- package/dist/components/IO/SoundCard.js +620 -0
- package/dist/components/IO/SoundCard.js.map +1 -0
- package/dist/components/IO/StorageCard.js +428 -0
- package/dist/components/IO/StorageCard.js.map +1 -0
- package/dist/components/IO/VGACard.js +9 -0
- package/dist/components/IO/VGACard.js.map +1 -0
- package/dist/components/IO/VideoCard.js +623 -0
- package/dist/components/IO/VideoCard.js.map +1 -0
- package/dist/components/IO.js +3 -0
- package/dist/components/IO.js.map +1 -0
- package/dist/components/Machine.js +310 -0
- package/dist/components/Machine.js.map +1 -0
- package/dist/components/RAM.js +24 -0
- package/dist/components/RAM.js.map +1 -0
- package/dist/components/ROM.js +23 -0
- package/dist/components/ROM.js.map +1 -0
- package/dist/index.js +441 -0
- package/dist/index.js.map +1 -0
- package/dist/tests/CPU.test.js +1626 -0
- package/dist/tests/CPU.test.js.map +1 -0
- package/dist/tests/Cart.test.js +119 -0
- package/dist/tests/Cart.test.js.map +1 -0
- package/dist/tests/IO/GPIOAttachments/GPIOAttachment.test.js +339 -0
- package/dist/tests/IO/GPIOAttachments/GPIOAttachment.test.js.map +1 -0
- package/dist/tests/IO/GPIOAttachments/GPIOJoystickAttachment.test.js +126 -0
- package/dist/tests/IO/GPIOAttachments/GPIOJoystickAttachment.test.js.map +1 -0
- package/dist/tests/IO/GPIOAttachments/GPIOKeyboardEncoderAttachment.test.js +779 -0
- package/dist/tests/IO/GPIOAttachments/GPIOKeyboardEncoderAttachment.test.js.map +1 -0
- package/dist/tests/IO/GPIOAttachments/GPIOKeyboardMatrixAttachment.test.js +355 -0
- package/dist/tests/IO/GPIOAttachments/GPIOKeyboardMatrixAttachment.test.js.map +1 -0
- package/dist/tests/IO/GPIOCard.test.js +503 -0
- package/dist/tests/IO/GPIOCard.test.js.map +1 -0
- package/dist/tests/IO/RAMCard.test.js +229 -0
- package/dist/tests/IO/RAMCard.test.js.map +1 -0
- package/dist/tests/IO/RTCCard.test.js +177 -0
- package/dist/tests/IO/RTCCard.test.js.map +1 -0
- package/dist/tests/IO/SerialCard.test.js +423 -0
- package/dist/tests/IO/SerialCard.test.js.map +1 -0
- package/dist/tests/IO/SoundCard.test.js +528 -0
- package/dist/tests/IO/SoundCard.test.js.map +1 -0
- package/dist/tests/IO/StorageCard.test.js +647 -0
- package/dist/tests/IO/StorageCard.test.js.map +1 -0
- package/dist/tests/IO/VideoCard.test.js +549 -0
- package/dist/tests/IO/VideoCard.test.js.map +1 -0
- package/dist/tests/Machine.test.js +383 -0
- package/dist/tests/Machine.test.js.map +1 -0
- package/dist/tests/RAM.test.js +160 -0
- package/dist/tests/RAM.test.js.map +1 -0
- package/dist/tests/ROM.test.js +123 -0
- package/dist/tests/ROM.test.js.map +1 -0
- package/jest.config.cjs +9 -0
- package/package.json +43 -0
- package/src/components/CPU.ts +1371 -0
- package/src/components/Cart.ts +20 -0
- package/src/components/IO/GPIOAttachments/GPIOAttachment.ts +189 -0
- package/src/components/IO/GPIOAttachments/GPIOJoystickAttachment.ts +99 -0
- package/src/components/IO/GPIOAttachments/GPIOKeyboardEncoderAttachment.ts +465 -0
- package/src/components/IO/GPIOAttachments/GPIOKeyboardMatrixAttachment.ts +287 -0
- package/src/components/IO/GPIOCard.ts +677 -0
- package/src/components/IO/RAMCard.ts +68 -0
- package/src/components/IO/RTCCard.ts +518 -0
- package/src/components/IO/SerialCard.ts +335 -0
- package/src/components/IO/SoundCard.ts +711 -0
- package/src/components/IO/StorageCard.ts +473 -0
- package/src/components/IO/VideoCard.ts +730 -0
- package/src/components/IO.ts +11 -0
- package/src/components/Machine.ts +364 -0
- package/src/components/RAM.ts +23 -0
- package/src/components/ROM.ts +19 -0
- package/src/index.ts +474 -0
- package/src/tests/CPU.test.ts +2045 -0
- package/src/tests/Cart.test.ts +149 -0
- package/src/tests/IO/GPIOAttachments/GPIOAttachment.test.ts +413 -0
- package/src/tests/IO/GPIOAttachments/GPIOJoystickAttachment.test.ts +147 -0
- package/src/tests/IO/GPIOAttachments/GPIOKeyboardEncoderAttachment.test.ts +961 -0
- package/src/tests/IO/GPIOAttachments/GPIOKeyboardMatrixAttachment.test.ts +449 -0
- package/src/tests/IO/GPIOCard.test.ts +644 -0
- package/src/tests/IO/RAMCard.test.ts +284 -0
- package/src/tests/IO/RTCCard.test.ts +222 -0
- package/src/tests/IO/SerialCard.test.ts +530 -0
- package/src/tests/IO/SoundCard.test.ts +659 -0
- package/src/tests/IO/StorageCard.test.ts +787 -0
- package/src/tests/IO/VideoCard.test.ts +668 -0
- package/src/tests/Machine.test.ts +437 -0
- package/src/tests/RAM.test.ts +196 -0
- package/src/tests/ROM.test.ts +154 -0
- package/tsconfig.json +12 -0
|
@@ -0,0 +1,787 @@
|
|
|
1
|
+
import { StorageCard } from '../../components/IO/StorageCard'
|
|
2
|
+
import { writeFile, unlink, readFile } from 'fs/promises'
|
|
3
|
+
import { existsSync } from 'fs'
|
|
4
|
+
import { tmpdir } from 'os'
|
|
5
|
+
import { join } from 'path'
|
|
6
|
+
|
|
7
|
+
describe('StorageCard (Compact Flash in IDE Mode)', () => {
|
|
8
|
+
let storageCard: StorageCard
|
|
9
|
+
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
storageCard = new StorageCard()
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
describe('Initialization', () => {
|
|
15
|
+
it('should initialize with correct default register values', () => {
|
|
16
|
+
expect(storageCard.read(0x01)).toBe(0x00) // Error Register
|
|
17
|
+
expect(storageCard.read(0x02)).toBe(0x00) // Sector Count
|
|
18
|
+
expect(storageCard.read(0x03)).toBe(0x00) // LBA0
|
|
19
|
+
expect(storageCard.read(0x04)).toBe(0x00) // LBA1
|
|
20
|
+
expect(storageCard.read(0x05)).toBe(0x00) // LBA2
|
|
21
|
+
expect(storageCard.read(0x06)).toBe(0xE0) // LBA3 (with mode bits)
|
|
22
|
+
expect(storageCard.read(0x07) & 0x40).toBe(0x40) // Status (RDY bit)
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
it('should have IRQ and NMI callbacks', () => {
|
|
26
|
+
expect(typeof storageCard.raiseIRQ).toBe('function')
|
|
27
|
+
expect(typeof storageCard.raiseNMI).toBe('function')
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
it('should initialize with all storage zeroed', () => {
|
|
31
|
+
// Verify first sector is all zeros
|
|
32
|
+
storageCard.write(0x02, 1) // Sector count = 1
|
|
33
|
+
storageCard.write(0x03, 0) // LBA = 0
|
|
34
|
+
storageCard.write(0x07, 0x20) // Read sector command
|
|
35
|
+
|
|
36
|
+
for (let i = 0; i < 512; i++) {
|
|
37
|
+
expect(storageCard.read(0x00)).toBe(0x00)
|
|
38
|
+
}
|
|
39
|
+
})
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
describe('Register Operations', () => {
|
|
43
|
+
describe('Address Masking', () => {
|
|
44
|
+
it('should mask address to lower 3 bits', () => {
|
|
45
|
+
storageCard.write(0x02, 0x42) // Sector count register
|
|
46
|
+
expect(storageCard.read(0x0A)).toBe(0x42) // 0x0A & 0x07 = 0x02
|
|
47
|
+
expect(storageCard.read(0x12)).toBe(0x42) // 0x12 & 0x07 = 0x02
|
|
48
|
+
expect(storageCard.read(0x1A)).toBe(0x42) // 0x1A & 0x07 = 0x02
|
|
49
|
+
})
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
describe('LBA Registers', () => {
|
|
53
|
+
it('should write and read LBA0', () => {
|
|
54
|
+
storageCard.write(0x03, 0xAB)
|
|
55
|
+
expect(storageCard.read(0x03)).toBe(0xAB)
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
it('should write and read LBA1', () => {
|
|
59
|
+
storageCard.write(0x04, 0xCD)
|
|
60
|
+
expect(storageCard.read(0x04)).toBe(0xCD)
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
it('should write and read LBA2', () => {
|
|
64
|
+
storageCard.write(0x05, 0xEF)
|
|
65
|
+
expect(storageCard.read(0x05)).toBe(0xEF)
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
it('should mask LBA3 to lower 4 bits and set mode bits', () => {
|
|
69
|
+
storageCard.write(0x06, 0xFF)
|
|
70
|
+
expect(storageCard.read(0x06)).toBe(0xEF) // 0xFF & 0x0F | 0xE0
|
|
71
|
+
|
|
72
|
+
storageCard.write(0x06, 0x05)
|
|
73
|
+
expect(storageCard.read(0x06)).toBe(0xE5) // 0x05 & 0x0F | 0xE0
|
|
74
|
+
})
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
describe('Sector Count Register', () => {
|
|
78
|
+
it('should write and read sector count', () => {
|
|
79
|
+
storageCard.write(0x02, 1)
|
|
80
|
+
expect(storageCard.read(0x02)).toBe(1)
|
|
81
|
+
|
|
82
|
+
storageCard.write(0x02, 10)
|
|
83
|
+
expect(storageCard.read(0x02)).toBe(10)
|
|
84
|
+
})
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
describe('Feature/Error Register', () => {
|
|
88
|
+
it('should read error register', () => {
|
|
89
|
+
const error = storageCard.read(0x01)
|
|
90
|
+
expect(error).toBe(0x00) // No error initially
|
|
91
|
+
})
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
describe('Status Register', () => {
|
|
95
|
+
it('should have RDY bit set initially', () => {
|
|
96
|
+
const status = storageCard.read(0x07)
|
|
97
|
+
expect(status & 0x40).toBe(0x40) // RDY bit
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
it('should not have ERR bit set initially', () => {
|
|
101
|
+
const status = storageCard.read(0x07)
|
|
102
|
+
expect(status & 0x01).toBe(0x00) // ERR bit
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
it('should not have DRQ bit set initially', () => {
|
|
106
|
+
const status = storageCard.read(0x07)
|
|
107
|
+
expect(status & 0x08).toBe(0x00) // DRQ bit
|
|
108
|
+
})
|
|
109
|
+
})
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
describe('Identify Drive Command (0xEC)', () => {
|
|
113
|
+
it('should set DRQ flag after identify command', () => {
|
|
114
|
+
storageCard.write(0x07, 0xEC)
|
|
115
|
+
const status = storageCard.read(0x07)
|
|
116
|
+
expect(status & 0x08).toBe(0x08) // DRQ set
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
it('should return 512 bytes of identity data', () => {
|
|
120
|
+
storageCard.write(0x07, 0xEC)
|
|
121
|
+
|
|
122
|
+
let byteCount = 0
|
|
123
|
+
while (storageCard.read(0x07) & 0x08) { // While DRQ is set
|
|
124
|
+
storageCard.read(0x00)
|
|
125
|
+
byteCount++
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
expect(byteCount).toBe(512)
|
|
129
|
+
})
|
|
130
|
+
|
|
131
|
+
it('should clear DRQ flag after reading all identity data', () => {
|
|
132
|
+
storageCard.write(0x07, 0xEC)
|
|
133
|
+
|
|
134
|
+
// Read all 512 bytes
|
|
135
|
+
for (let i = 0; i < 512; i++) {
|
|
136
|
+
storageCard.read(0x00)
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const status = storageCard.read(0x07)
|
|
140
|
+
expect(status & 0x08).toBe(0x00) // DRQ cleared
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
it('should contain valid identity data', () => {
|
|
144
|
+
storageCard.write(0x07, 0xEC)
|
|
145
|
+
|
|
146
|
+
const identity: number[] = []
|
|
147
|
+
for (let i = 0; i < 512; i++) {
|
|
148
|
+
identity.push(storageCard.read(0x00))
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Check general configuration (word 0)
|
|
152
|
+
expect(identity[0]).toBe(0x84)
|
|
153
|
+
expect(identity[1]).toBe(0x8A)
|
|
154
|
+
|
|
155
|
+
// Check serial number starts at byte 20
|
|
156
|
+
const serial = String.fromCharCode(...identity.slice(20, 40))
|
|
157
|
+
expect(serial).toBe('ACWD6502EMUCF1010101')
|
|
158
|
+
|
|
159
|
+
// Check firmware revision starts at byte 46
|
|
160
|
+
const firmware = String.fromCharCode(...identity.slice(46, 54))
|
|
161
|
+
expect(firmware).toBe('1.0 ')
|
|
162
|
+
|
|
163
|
+
// Check model number starts at byte 54
|
|
164
|
+
const model = String.fromCharCode(...identity.slice(54, 94))
|
|
165
|
+
expect(model).toContain('ACWD6502EMUCF')
|
|
166
|
+
})
|
|
167
|
+
})
|
|
168
|
+
|
|
169
|
+
describe('Read Sector Command (0x20/0x21)', () => {
|
|
170
|
+
it('should set DRQ flag after read sector command', () => {
|
|
171
|
+
storageCard.write(0x02, 1) // 1 sector
|
|
172
|
+
storageCard.write(0x03, 0) // LBA = 0
|
|
173
|
+
storageCard.write(0x07, 0x20) // Read sector
|
|
174
|
+
|
|
175
|
+
const status = storageCard.read(0x07)
|
|
176
|
+
expect(status & 0x08).toBe(0x08) // DRQ set
|
|
177
|
+
})
|
|
178
|
+
|
|
179
|
+
it('should read a single sector', () => {
|
|
180
|
+
storageCard.write(0x02, 1)
|
|
181
|
+
storageCard.write(0x03, 0)
|
|
182
|
+
storageCard.write(0x07, 0x20)
|
|
183
|
+
|
|
184
|
+
let byteCount = 0
|
|
185
|
+
while (storageCard.read(0x07) & 0x08) {
|
|
186
|
+
storageCard.read(0x00)
|
|
187
|
+
byteCount++
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
expect(byteCount).toBe(512)
|
|
191
|
+
})
|
|
192
|
+
|
|
193
|
+
it('should clear DRQ after reading all sector data', () => {
|
|
194
|
+
storageCard.write(0x02, 1)
|
|
195
|
+
storageCard.write(0x03, 0)
|
|
196
|
+
storageCard.write(0x07, 0x20)
|
|
197
|
+
|
|
198
|
+
for (let i = 0; i < 512; i++) {
|
|
199
|
+
storageCard.read(0x00)
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
expect(storageCard.read(0x07) & 0x08).toBe(0x00)
|
|
203
|
+
})
|
|
204
|
+
|
|
205
|
+
it('should report error for invalid sector (too high)', () => {
|
|
206
|
+
storageCard.write(0x02, 1)
|
|
207
|
+
storageCard.write(0x03, 0xFF) // LBA = 0x0FFFFFFF (invalid)
|
|
208
|
+
storageCard.write(0x04, 0xFF)
|
|
209
|
+
storageCard.write(0x05, 0xFF)
|
|
210
|
+
storageCard.write(0x06, 0xFF)
|
|
211
|
+
storageCard.write(0x07, 0x20)
|
|
212
|
+
|
|
213
|
+
const status = storageCard.read(0x07)
|
|
214
|
+
const error = storageCard.read(0x01)
|
|
215
|
+
|
|
216
|
+
expect(status & 0x01).toBe(0x01) // ERR bit set
|
|
217
|
+
expect(error & 0x10).toBe(0x10) // IDNF error
|
|
218
|
+
})
|
|
219
|
+
|
|
220
|
+
it('should read multiple sectors', () => {
|
|
221
|
+
storageCard.write(0x02, 3) // 3 sectors
|
|
222
|
+
storageCard.write(0x03, 0)
|
|
223
|
+
storageCard.write(0x07, 0x20)
|
|
224
|
+
|
|
225
|
+
let byteCount = 0
|
|
226
|
+
while (storageCard.read(0x07) & 0x08) {
|
|
227
|
+
storageCard.read(0x00)
|
|
228
|
+
byteCount++
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
expect(byteCount).toBe(512 * 3)
|
|
232
|
+
})
|
|
233
|
+
|
|
234
|
+
it('should work with command 0x21', () => {
|
|
235
|
+
storageCard.write(0x02, 1)
|
|
236
|
+
storageCard.write(0x03, 0)
|
|
237
|
+
storageCard.write(0x07, 0x21) // Alternate read command
|
|
238
|
+
|
|
239
|
+
expect(storageCard.read(0x07) & 0x08).toBe(0x08) // DRQ set
|
|
240
|
+
})
|
|
241
|
+
})
|
|
242
|
+
|
|
243
|
+
describe('Write Sector Command (0x30/0x31)', () => {
|
|
244
|
+
it('should set DRQ flag after write sector command', () => {
|
|
245
|
+
storageCard.write(0x02, 1)
|
|
246
|
+
storageCard.write(0x03, 0)
|
|
247
|
+
storageCard.write(0x07, 0x30) // Write sector
|
|
248
|
+
|
|
249
|
+
const status = storageCard.read(0x07)
|
|
250
|
+
expect(status & 0x08).toBe(0x08) // DRQ set
|
|
251
|
+
})
|
|
252
|
+
|
|
253
|
+
it('should write and read back a single sector', () => {
|
|
254
|
+
// Write sector 0
|
|
255
|
+
storageCard.write(0x02, 1)
|
|
256
|
+
storageCard.write(0x03, 0)
|
|
257
|
+
storageCard.write(0x07, 0x30)
|
|
258
|
+
|
|
259
|
+
for (let i = 0; i < 512; i++) {
|
|
260
|
+
storageCard.write(0x00, i & 0xFF)
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// Read sector 0
|
|
264
|
+
storageCard.write(0x02, 1)
|
|
265
|
+
storageCard.write(0x03, 0)
|
|
266
|
+
storageCard.write(0x07, 0x20)
|
|
267
|
+
|
|
268
|
+
for (let i = 0; i < 512; i++) {
|
|
269
|
+
expect(storageCard.read(0x00)).toBe(i & 0xFF)
|
|
270
|
+
}
|
|
271
|
+
})
|
|
272
|
+
|
|
273
|
+
it('should clear DRQ after writing all sector data', () => {
|
|
274
|
+
storageCard.write(0x02, 1)
|
|
275
|
+
storageCard.write(0x03, 0)
|
|
276
|
+
storageCard.write(0x07, 0x30)
|
|
277
|
+
|
|
278
|
+
for (let i = 0; i < 512; i++) {
|
|
279
|
+
storageCard.write(0x00, 0xFF)
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
expect(storageCard.read(0x07) & 0x08).toBe(0x00)
|
|
283
|
+
})
|
|
284
|
+
|
|
285
|
+
it('should report error for invalid sector', () => {
|
|
286
|
+
storageCard.write(0x02, 1)
|
|
287
|
+
storageCard.write(0x03, 0xFF)
|
|
288
|
+
storageCard.write(0x04, 0xFF)
|
|
289
|
+
storageCard.write(0x05, 0xFF)
|
|
290
|
+
storageCard.write(0x06, 0xFF)
|
|
291
|
+
storageCard.write(0x07, 0x30)
|
|
292
|
+
|
|
293
|
+
const status = storageCard.read(0x07)
|
|
294
|
+
expect(status & 0x01).toBe(0x01) // ERR bit
|
|
295
|
+
})
|
|
296
|
+
|
|
297
|
+
it('should write multiple sectors', () => {
|
|
298
|
+
storageCard.write(0x02, 2)
|
|
299
|
+
storageCard.write(0x03, 0)
|
|
300
|
+
storageCard.write(0x07, 0x30)
|
|
301
|
+
|
|
302
|
+
for (let i = 0; i < 512 * 2; i++) {
|
|
303
|
+
storageCard.write(0x00, 0xAA)
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// Verify data was written
|
|
307
|
+
storageCard.write(0x02, 2)
|
|
308
|
+
storageCard.write(0x03, 0)
|
|
309
|
+
storageCard.write(0x07, 0x20)
|
|
310
|
+
|
|
311
|
+
for (let i = 0; i < 512 * 2; i++) {
|
|
312
|
+
expect(storageCard.read(0x00)).toBe(0xAA)
|
|
313
|
+
}
|
|
314
|
+
})
|
|
315
|
+
|
|
316
|
+
it('should work with command 0x31', () => {
|
|
317
|
+
storageCard.write(0x02, 1)
|
|
318
|
+
storageCard.write(0x03, 0)
|
|
319
|
+
storageCard.write(0x07, 0x31) // Alternate write command
|
|
320
|
+
|
|
321
|
+
expect(storageCard.read(0x07) & 0x08).toBe(0x08) // DRQ set
|
|
322
|
+
})
|
|
323
|
+
})
|
|
324
|
+
|
|
325
|
+
describe('Erase Sector Command (0xC0)', () => {
|
|
326
|
+
it('should erase a sector', () => {
|
|
327
|
+
// First write some data
|
|
328
|
+
storageCard.write(0x02, 1)
|
|
329
|
+
storageCard.write(0x03, 5) // Sector 5
|
|
330
|
+
storageCard.write(0x07, 0x30)
|
|
331
|
+
|
|
332
|
+
for (let i = 0; i < 512; i++) {
|
|
333
|
+
storageCard.write(0x00, 0xFF)
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// Erase the sector
|
|
337
|
+
storageCard.write(0x02, 1)
|
|
338
|
+
storageCard.write(0x03, 5)
|
|
339
|
+
storageCard.write(0x07, 0xC0)
|
|
340
|
+
|
|
341
|
+
// Read back and verify zeros
|
|
342
|
+
storageCard.write(0x02, 1)
|
|
343
|
+
storageCard.write(0x03, 5)
|
|
344
|
+
storageCard.write(0x07, 0x20)
|
|
345
|
+
|
|
346
|
+
for (let i = 0; i < 512; i++) {
|
|
347
|
+
expect(storageCard.read(0x00)).toBe(0x00)
|
|
348
|
+
}
|
|
349
|
+
})
|
|
350
|
+
|
|
351
|
+
it('should report error for invalid sector', () => {
|
|
352
|
+
storageCard.write(0x02, 1)
|
|
353
|
+
storageCard.write(0x03, 0xFF)
|
|
354
|
+
storageCard.write(0x04, 0xFF)
|
|
355
|
+
storageCard.write(0x05, 0xFF)
|
|
356
|
+
storageCard.write(0x06, 0xFF)
|
|
357
|
+
storageCard.write(0x07, 0xC0)
|
|
358
|
+
|
|
359
|
+
const status = storageCard.read(0x07)
|
|
360
|
+
expect(status & 0x01).toBe(0x01) // ERR bit
|
|
361
|
+
})
|
|
362
|
+
|
|
363
|
+
it('should not set DRQ flag', () => {
|
|
364
|
+
storageCard.write(0x02, 1)
|
|
365
|
+
storageCard.write(0x03, 0)
|
|
366
|
+
storageCard.write(0x07, 0xC0)
|
|
367
|
+
|
|
368
|
+
expect(storageCard.read(0x07) & 0x08).toBe(0x00) // DRQ not set
|
|
369
|
+
})
|
|
370
|
+
})
|
|
371
|
+
|
|
372
|
+
describe('Set Features Command (0xEF)', () => {
|
|
373
|
+
it('should accept command without error', () => {
|
|
374
|
+
storageCard.write(0x07, 0xEF)
|
|
375
|
+
|
|
376
|
+
const status = storageCard.read(0x07)
|
|
377
|
+
expect(status & 0x01).toBe(0x00) // No error
|
|
378
|
+
})
|
|
379
|
+
|
|
380
|
+
it('should not set DRQ flag', () => {
|
|
381
|
+
storageCard.write(0x07, 0xEF)
|
|
382
|
+
|
|
383
|
+
expect(storageCard.read(0x07) & 0x08).toBe(0x00)
|
|
384
|
+
})
|
|
385
|
+
})
|
|
386
|
+
|
|
387
|
+
describe('Unsupported Commands', () => {
|
|
388
|
+
it('should report error for unsupported command', () => {
|
|
389
|
+
storageCard.write(0x07, 0xFF) // Invalid command
|
|
390
|
+
|
|
391
|
+
const status = storageCard.read(0x07)
|
|
392
|
+
const error = storageCard.read(0x01)
|
|
393
|
+
|
|
394
|
+
expect(status & 0x01).toBe(0x01) // ERR bit
|
|
395
|
+
expect(error & 0x04).toBe(0x04) // ABRT error
|
|
396
|
+
})
|
|
397
|
+
|
|
398
|
+
it('should not set DRQ for unsupported command', () => {
|
|
399
|
+
storageCard.write(0x07, 0x99)
|
|
400
|
+
|
|
401
|
+
expect(storageCard.read(0x07) & 0x08).toBe(0x00)
|
|
402
|
+
})
|
|
403
|
+
})
|
|
404
|
+
|
|
405
|
+
describe('LBA Addressing', () => {
|
|
406
|
+
it('should correctly calculate 28-bit LBA address', () => {
|
|
407
|
+
// Write pattern to sector at LBA 0x00000045 (using valid low address)
|
|
408
|
+
storageCard.write(0x02, 1)
|
|
409
|
+
storageCard.write(0x03, 0x45) // LBA0
|
|
410
|
+
storageCard.write(0x04, 0x00) // LBA1
|
|
411
|
+
storageCard.write(0x05, 0x00) // LBA2
|
|
412
|
+
storageCard.write(0x06, 0x00) // LBA3 (0x00 & 0x0F | 0xE0 = 0xE0)
|
|
413
|
+
storageCard.write(0x07, 0x30)
|
|
414
|
+
|
|
415
|
+
for (let i = 0; i < 512; i++) {
|
|
416
|
+
storageCard.write(0x00, 0xCC)
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
// Read back
|
|
420
|
+
storageCard.write(0x02, 1)
|
|
421
|
+
storageCard.write(0x03, 0x45)
|
|
422
|
+
storageCard.write(0x04, 0x00)
|
|
423
|
+
storageCard.write(0x05, 0x00)
|
|
424
|
+
storageCard.write(0x06, 0x00)
|
|
425
|
+
storageCard.write(0x07, 0x20)
|
|
426
|
+
|
|
427
|
+
expect(storageCard.read(0x00)).toBe(0xCC)
|
|
428
|
+
})
|
|
429
|
+
|
|
430
|
+
it('should isolate different sectors', () => {
|
|
431
|
+
// Write to sector 0
|
|
432
|
+
storageCard.write(0x02, 1)
|
|
433
|
+
storageCard.write(0x03, 0)
|
|
434
|
+
storageCard.write(0x07, 0x30)
|
|
435
|
+
for (let i = 0; i < 512; i++) {
|
|
436
|
+
storageCard.write(0x00, 0x11)
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
// Write to sector 1
|
|
440
|
+
storageCard.write(0x02, 1)
|
|
441
|
+
storageCard.write(0x03, 1)
|
|
442
|
+
storageCard.write(0x07, 0x30)
|
|
443
|
+
for (let i = 0; i < 512; i++) {
|
|
444
|
+
storageCard.write(0x00, 0x22)
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
// Read sector 0 (must read all bytes to complete transfer)
|
|
448
|
+
storageCard.write(0x02, 1)
|
|
449
|
+
storageCard.write(0x03, 0)
|
|
450
|
+
storageCard.write(0x07, 0x20)
|
|
451
|
+
const firstByte0 = storageCard.read(0x00)
|
|
452
|
+
for (let i = 1; i < 512; i++) {
|
|
453
|
+
storageCard.read(0x00)
|
|
454
|
+
}
|
|
455
|
+
expect(firstByte0).toBe(0x11)
|
|
456
|
+
|
|
457
|
+
// Read sector 1 (must read all bytes to complete transfer)
|
|
458
|
+
storageCard.write(0x02, 1)
|
|
459
|
+
storageCard.write(0x03, 1)
|
|
460
|
+
storageCard.write(0x07, 0x20)
|
|
461
|
+
const firstByte1 = storageCard.read(0x00)
|
|
462
|
+
for (let i = 1; i < 512; i++) {
|
|
463
|
+
storageCard.read(0x00)
|
|
464
|
+
}
|
|
465
|
+
expect(firstByte1).toBe(0x22)
|
|
466
|
+
})
|
|
467
|
+
})
|
|
468
|
+
|
|
469
|
+
describe('Error Conditions', () => {
|
|
470
|
+
it('should abort if command issued while transferring', () => {
|
|
471
|
+
storageCard.write(0x02, 1)
|
|
472
|
+
storageCard.write(0x03, 0)
|
|
473
|
+
storageCard.write(0x07, 0x20) // Start read
|
|
474
|
+
|
|
475
|
+
// Issue another command while first is active
|
|
476
|
+
storageCard.write(0x07, 0x20)
|
|
477
|
+
|
|
478
|
+
const status = storageCard.read(0x07)
|
|
479
|
+
const error = storageCard.read(0x01)
|
|
480
|
+
|
|
481
|
+
expect(status & 0x01).toBe(0x01) // ERR bit
|
|
482
|
+
expect(error & 0x04).toBe(0x04) // ABRT error
|
|
483
|
+
})
|
|
484
|
+
|
|
485
|
+
it('should abort if command issued while identifying', () => {
|
|
486
|
+
storageCard.write(0x07, 0xEC) // Start identify
|
|
487
|
+
|
|
488
|
+
// Issue another command
|
|
489
|
+
storageCard.write(0x07, 0x20)
|
|
490
|
+
|
|
491
|
+
const status = storageCard.read(0x07)
|
|
492
|
+
const error = storageCard.read(0x01)
|
|
493
|
+
|
|
494
|
+
expect(status & 0x01).toBe(0x01) // ERR bit
|
|
495
|
+
expect(error & 0x04).toBe(0x04) // ABRT error
|
|
496
|
+
})
|
|
497
|
+
|
|
498
|
+
it('should clear error flags on new valid command', () => {
|
|
499
|
+
// Trigger an error
|
|
500
|
+
storageCard.write(0x07, 0xFF) // Invalid command
|
|
501
|
+
expect(storageCard.read(0x07) & 0x01).toBe(0x01)
|
|
502
|
+
|
|
503
|
+
// Issue valid command
|
|
504
|
+
storageCard.write(0x02, 1)
|
|
505
|
+
storageCard.write(0x03, 0)
|
|
506
|
+
storageCard.write(0x07, 0x20)
|
|
507
|
+
|
|
508
|
+
const status = storageCard.read(0x07)
|
|
509
|
+
expect(status & 0x01).toBe(0x00) // ERR cleared
|
|
510
|
+
})
|
|
511
|
+
})
|
|
512
|
+
|
|
513
|
+
describe('Reset', () => {
|
|
514
|
+
it('should reset all registers to default values', () => {
|
|
515
|
+
// Modify registers
|
|
516
|
+
storageCard.write(0x02, 0x42)
|
|
517
|
+
storageCard.write(0x03, 0x11)
|
|
518
|
+
storageCard.write(0x04, 0x22)
|
|
519
|
+
storageCard.write(0x05, 0x33)
|
|
520
|
+
|
|
521
|
+
storageCard.reset(true)
|
|
522
|
+
|
|
523
|
+
expect(storageCard.read(0x01)).toBe(0x00) // Error
|
|
524
|
+
expect(storageCard.read(0x02)).toBe(0x00) // Sector Count
|
|
525
|
+
expect(storageCard.read(0x03)).toBe(0x00) // LBA0
|
|
526
|
+
expect(storageCard.read(0x04)).toBe(0x00) // LBA1
|
|
527
|
+
expect(storageCard.read(0x05)).toBe(0x00) // LBA2
|
|
528
|
+
expect(storageCard.read(0x06)).toBe(0xE0) // LBA3
|
|
529
|
+
expect(storageCard.read(0x07) & 0x40).toBe(0x40) // Status RDY
|
|
530
|
+
})
|
|
531
|
+
|
|
532
|
+
it('should clear transfer state', () => {
|
|
533
|
+
storageCard.write(0x02, 1)
|
|
534
|
+
storageCard.write(0x03, 0)
|
|
535
|
+
storageCard.write(0x07, 0x20) // Start transfer
|
|
536
|
+
|
|
537
|
+
storageCard.reset(true)
|
|
538
|
+
|
|
539
|
+
expect(storageCard.read(0x07) & 0x08).toBe(0x00) // DRQ cleared
|
|
540
|
+
})
|
|
541
|
+
})
|
|
542
|
+
|
|
543
|
+
describe('Tick', () => {
|
|
544
|
+
it('should have tick method that does nothing', () => {
|
|
545
|
+
expect(() => {
|
|
546
|
+
storageCard.tick(1000000)
|
|
547
|
+
}).not.toThrow()
|
|
548
|
+
})
|
|
549
|
+
})
|
|
550
|
+
|
|
551
|
+
describe('IO Interface Implementation', () => {
|
|
552
|
+
it('should implement IO interface methods', () => {
|
|
553
|
+
expect(typeof storageCard.read).toBe('function')
|
|
554
|
+
expect(typeof storageCard.write).toBe('function')
|
|
555
|
+
expect(typeof storageCard.tick).toBe('function')
|
|
556
|
+
expect(typeof storageCard.reset).toBe('function')
|
|
557
|
+
expect(typeof storageCard.raiseIRQ).toBe('function')
|
|
558
|
+
expect(typeof storageCard.raiseNMI).toBe('function')
|
|
559
|
+
})
|
|
560
|
+
})
|
|
561
|
+
|
|
562
|
+
describe('Storage Persistence', () => {
|
|
563
|
+
const testDir = tmpdir()
|
|
564
|
+
const testFile = join(testDir, `storage-test-${Date.now()}.bin`)
|
|
565
|
+
const invalidSizeFile = join(testDir, `storage-invalid-${Date.now()}.bin`)
|
|
566
|
+
const nonExistentFile = join(testDir, `storage-nonexistent-${Date.now()}.bin`)
|
|
567
|
+
|
|
568
|
+
afterEach(async () => {
|
|
569
|
+
// Cleanup test files
|
|
570
|
+
const filesToClean = [testFile, invalidSizeFile, nonExistentFile]
|
|
571
|
+
for (const file of filesToClean) {
|
|
572
|
+
if (existsSync(file)) {
|
|
573
|
+
await unlink(file)
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
})
|
|
577
|
+
|
|
578
|
+
describe('saveToFile', () => {
|
|
579
|
+
it('should save storage data to a file', async () => {
|
|
580
|
+
// Write some known data to storage
|
|
581
|
+
storageCard.write(0x02, 1) // 1 sector
|
|
582
|
+
storageCard.write(0x03, 0) // LBA = 0
|
|
583
|
+
storageCard.write(0x07, 0x30) // Write sector command
|
|
584
|
+
|
|
585
|
+
for (let i = 0; i < 512; i++) {
|
|
586
|
+
storageCard.write(0x00, i & 0xFF)
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
// Save to file
|
|
590
|
+
await storageCard.saveToFile(testFile)
|
|
591
|
+
|
|
592
|
+
// Verify file exists
|
|
593
|
+
expect(existsSync(testFile)).toBe(true)
|
|
594
|
+
|
|
595
|
+
// Verify file size is 128MB
|
|
596
|
+
const fileData = await readFile(testFile)
|
|
597
|
+
expect(fileData.length).toBe(128 * 1024 * 1024)
|
|
598
|
+
})
|
|
599
|
+
|
|
600
|
+
it('should save complete storage contents', async () => {
|
|
601
|
+
// Write to multiple sectors
|
|
602
|
+
for (let sector = 0; sector < 5; sector++) {
|
|
603
|
+
storageCard.write(0x02, 1)
|
|
604
|
+
storageCard.write(0x03, sector)
|
|
605
|
+
storageCard.write(0x07, 0x30)
|
|
606
|
+
|
|
607
|
+
for (let i = 0; i < 512; i++) {
|
|
608
|
+
storageCard.write(0x00, (sector + i) & 0xFF)
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
await storageCard.saveToFile(testFile)
|
|
613
|
+
|
|
614
|
+
// Read file directly and verify
|
|
615
|
+
const fileData = await readFile(testFile)
|
|
616
|
+
|
|
617
|
+
// Check first sector
|
|
618
|
+
for (let i = 0; i < 512; i++) {
|
|
619
|
+
expect(fileData[i]).toBe(i & 0xFF)
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
// Check second sector
|
|
623
|
+
for (let i = 0; i < 512; i++) {
|
|
624
|
+
expect(fileData[512 + i]).toBe((1 + i) & 0xFF)
|
|
625
|
+
}
|
|
626
|
+
})
|
|
627
|
+
})
|
|
628
|
+
|
|
629
|
+
describe('loadFromFile', () => {
|
|
630
|
+
it('should load storage data from an existing file', async () => {
|
|
631
|
+
// Create a test file with known data
|
|
632
|
+
const testData = Buffer.alloc(128 * 1024 * 1024, 0x00)
|
|
633
|
+
|
|
634
|
+
// Fill first sector with pattern
|
|
635
|
+
for (let i = 0; i < 512; i++) {
|
|
636
|
+
testData[i] = (0xAA + i) & 0xFF
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
await writeFile(testFile, testData)
|
|
640
|
+
|
|
641
|
+
// Load into storage card
|
|
642
|
+
await storageCard.loadFromFile(testFile)
|
|
643
|
+
|
|
644
|
+
// Verify data was loaded
|
|
645
|
+
storageCard.write(0x02, 1)
|
|
646
|
+
storageCard.write(0x03, 0)
|
|
647
|
+
storageCard.write(0x07, 0x20) // Read sector
|
|
648
|
+
|
|
649
|
+
for (let i = 0; i < 512; i++) {
|
|
650
|
+
expect(storageCard.read(0x00)).toBe((0xAA + i) & 0xFF)
|
|
651
|
+
}
|
|
652
|
+
})
|
|
653
|
+
|
|
654
|
+
it('should handle non-existent file gracefully', async () => {
|
|
655
|
+
// Try to load from a file that doesn't exist
|
|
656
|
+
await expect(storageCard.loadFromFile(nonExistentFile)).resolves.not.toThrow()
|
|
657
|
+
|
|
658
|
+
// Storage should remain empty (zeros)
|
|
659
|
+
storageCard.write(0x02, 1)
|
|
660
|
+
storageCard.write(0x03, 0)
|
|
661
|
+
storageCard.write(0x07, 0x20)
|
|
662
|
+
|
|
663
|
+
for (let i = 0; i < 512; i++) {
|
|
664
|
+
expect(storageCard.read(0x00)).toBe(0x00)
|
|
665
|
+
}
|
|
666
|
+
})
|
|
667
|
+
|
|
668
|
+
it('should reject file with incorrect size', async () => {
|
|
669
|
+
// Create a file that's too small
|
|
670
|
+
const smallData = Buffer.alloc(1024, 0xFF) // Only 1KB
|
|
671
|
+
await writeFile(invalidSizeFile, smallData)
|
|
672
|
+
|
|
673
|
+
await storageCard.loadFromFile(invalidSizeFile)
|
|
674
|
+
|
|
675
|
+
// Storage should remain empty (zeros)
|
|
676
|
+
storageCard.write(0x02, 1)
|
|
677
|
+
storageCard.write(0x03, 0)
|
|
678
|
+
storageCard.write(0x07, 0x20)
|
|
679
|
+
|
|
680
|
+
for (let i = 0; i < 512; i++) {
|
|
681
|
+
expect(storageCard.read(0x00)).toBe(0x00)
|
|
682
|
+
}
|
|
683
|
+
})
|
|
684
|
+
|
|
685
|
+
it('should load multiple sectors correctly', async () => {
|
|
686
|
+
const testData = Buffer.alloc(128 * 1024 * 1024, 0x00)
|
|
687
|
+
|
|
688
|
+
// Fill sectors with different patterns
|
|
689
|
+
for (let sector = 0; sector < 10; sector++) {
|
|
690
|
+
for (let i = 0; i < 512; i++) {
|
|
691
|
+
testData[sector * 512 + i] = (sector * 16 + i) & 0xFF
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
await writeFile(testFile, testData)
|
|
696
|
+
await storageCard.loadFromFile(testFile)
|
|
697
|
+
|
|
698
|
+
// Verify each sector
|
|
699
|
+
for (let sector = 0; sector < 10; sector++) {
|
|
700
|
+
storageCard.write(0x02, 1)
|
|
701
|
+
storageCard.write(0x03, sector)
|
|
702
|
+
storageCard.write(0x07, 0x20)
|
|
703
|
+
|
|
704
|
+
for (let i = 0; i < 512; i++) {
|
|
705
|
+
expect(storageCard.read(0x00)).toBe((sector * 16 + i) & 0xFF)
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
})
|
|
709
|
+
})
|
|
710
|
+
|
|
711
|
+
describe('Round-trip persistence', () => {
|
|
712
|
+
it('should save and load data without loss', async () => {
|
|
713
|
+
// Write unique pattern to storage
|
|
714
|
+
for (let sector = 0; sector < 100; sector++) {
|
|
715
|
+
storageCard.write(0x02, 1)
|
|
716
|
+
storageCard.write(0x03, sector)
|
|
717
|
+
storageCard.write(0x07, 0x30)
|
|
718
|
+
|
|
719
|
+
for (let i = 0; i < 512; i++) {
|
|
720
|
+
storageCard.write(0x00, ((sector * 7 + i * 3) ^ 0x55) & 0xFF)
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
// Save to file
|
|
725
|
+
await storageCard.saveToFile(testFile)
|
|
726
|
+
|
|
727
|
+
// Create new storage card and load
|
|
728
|
+
const newStorageCard = new StorageCard()
|
|
729
|
+
await newStorageCard.loadFromFile(testFile)
|
|
730
|
+
|
|
731
|
+
// Verify all sectors match
|
|
732
|
+
for (let sector = 0; sector < 100; sector++) {
|
|
733
|
+
newStorageCard.write(0x02, 1)
|
|
734
|
+
newStorageCard.write(0x03, sector)
|
|
735
|
+
newStorageCard.write(0x07, 0x20)
|
|
736
|
+
|
|
737
|
+
for (let i = 0; i < 512; i++) {
|
|
738
|
+
expect(newStorageCard.read(0x00)).toBe(((sector * 7 + i * 3) ^ 0x55) & 0xFF)
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
})
|
|
742
|
+
|
|
743
|
+
it('should preserve data across multiple save/load cycles', async () => {
|
|
744
|
+
// Initial write
|
|
745
|
+
storageCard.write(0x02, 1)
|
|
746
|
+
storageCard.write(0x03, 42)
|
|
747
|
+
storageCard.write(0x07, 0x30)
|
|
748
|
+
for (let i = 0; i < 512; i++) {
|
|
749
|
+
storageCard.write(0x00, 0xCC)
|
|
750
|
+
}
|
|
751
|
+
await storageCard.saveToFile(testFile)
|
|
752
|
+
|
|
753
|
+
// Load and modify
|
|
754
|
+
const card2 = new StorageCard()
|
|
755
|
+
await card2.loadFromFile(testFile)
|
|
756
|
+
card2.write(0x02, 1)
|
|
757
|
+
card2.write(0x03, 43)
|
|
758
|
+
card2.write(0x07, 0x30)
|
|
759
|
+
for (let i = 0; i < 512; i++) {
|
|
760
|
+
card2.write(0x00, 0xDD)
|
|
761
|
+
}
|
|
762
|
+
await card2.saveToFile(testFile)
|
|
763
|
+
|
|
764
|
+
// Load again and verify both sectors
|
|
765
|
+
const card3 = new StorageCard()
|
|
766
|
+
await card3.loadFromFile(testFile)
|
|
767
|
+
|
|
768
|
+
// Check sector 42
|
|
769
|
+
card3.write(0x02, 1)
|
|
770
|
+
card3.write(0x03, 42)
|
|
771
|
+
card3.write(0x07, 0x20)
|
|
772
|
+
expect(card3.read(0x00)).toBe(0xCC)
|
|
773
|
+
|
|
774
|
+
// Complete reading sector 42
|
|
775
|
+
for (let i = 1; i < 512; i++) {
|
|
776
|
+
card3.read(0x00)
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
// Check sector 43
|
|
780
|
+
card3.write(0x02, 1)
|
|
781
|
+
card3.write(0x03, 43)
|
|
782
|
+
card3.write(0x07, 0x20)
|
|
783
|
+
expect(card3.read(0x00)).toBe(0xDD)
|
|
784
|
+
})
|
|
785
|
+
})
|
|
786
|
+
})
|
|
787
|
+
})
|