Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/platforms/tec1g/sd-spi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,8 @@ export class SdSpi {
}
}
// Data response token: 0bxxx00101 = 0x05 (accepted).
this.enqueueResponse([0x05, 0xff]);
this.pendingResponse = [0x05, 0xff];
this.delayBytes = 1;
this.writeState = null;
}
}
93 changes: 71 additions & 22 deletions tests/platforms/tec1g/sd-spi-runtime.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,12 @@
const MOSI_BIT = 0x01;
const CLK_BIT = 0x02;

function makeRuntime(image?: Uint8Array) {
type Tec1gRuntimeHandle = {
rt: ReturnType<typeof createTec1gRuntime>;
sdImagePath?: string;
};

function makeRuntime(image?: Uint8Array): Tec1gRuntimeHandle {
let sdImagePath: string | undefined;
if (image) {
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'debug80-sd-'));
Expand All @@ -32,33 +37,33 @@
rtcEnabled: false,
sdEnabled: true,
sdHighCapacity: true,
...(sdImagePath ? { sdImagePath } : {}),

Check failure on line 40 in tests/platforms/tec1g/sd-spi-runtime.test.ts

View workflow job for this annotation

GitHub Actions / test (windows-latest)

Unexpected nullable string value in conditional. Please handle the nullish/empty cases explicitly

Check failure on line 40 in tests/platforms/tec1g/sd-spi-runtime.test.ts

View workflow job for this annotation

GitHub Actions / test (ubuntu-latest)

Unexpected nullable string value in conditional. Please handle the nullish/empty cases explicitly
};
return createTec1gRuntime(config, () => {});
return { rt: createTec1gRuntime(config, () => {}), sdImagePath };
}

function writePort(rt: ReturnType<typeof makeRuntime>, value: number): void {
function writePort(rt: ReturnType<typeof createTec1gRuntime>, value: number): void {
rt.ioHandlers.write(0xfd, value & 0xff);
}

function readPort(rt: ReturnType<typeof makeRuntime>): number {
function readPort(rt: ReturnType<typeof createTec1gRuntime>): number {
return rt.ioHandlers.read(0xfd) & 0xff;
}

function pulse(rt: ReturnType<typeof makeRuntime>, bit: number): void {
function pulse(rt: ReturnType<typeof createTec1gRuntime>, bit: number): void {
const io = bit ? MOSI_BIT : 0;
writePort(rt, io);
writePort(rt, io | CLK_BIT);
writePort(rt, io);
}

function writeByte(rt: ReturnType<typeof makeRuntime>, value: number): void {
function writeByte(rt: ReturnType<typeof createTec1gRuntime>, value: number): void {
for (let i = 7; i >= 0; i -= 1) {
pulse(rt, (value >> i) & 1);
}
}

function readByte(rt: ReturnType<typeof makeRuntime>): number {
function readByte(rt: ReturnType<typeof createTec1gRuntime>): number {
let value = 0;
for (let i = 0; i < 8; i += 1) {
writePort(rt, MOSI_BIT);
Expand All @@ -70,7 +75,7 @@
return value & 0xff;
}

function readResponse(rt: ReturnType<typeof makeRuntime>): number {
function readResponse(rt: ReturnType<typeof createTec1gRuntime>): number {
for (let i = 0; i < 8; i += 1) {
const value = readByte(rt);
if (value !== 0xff) {
Expand All @@ -80,31 +85,75 @@
return 0xff;
}

function sendCommand(rt: ReturnType<typeof makeRuntime>, bytes: number[]): void {
function sendCommand(rt: ReturnType<typeof createTec1gRuntime>, bytes: number[]): void {
bytes.forEach((byte) => writeByte(rt, byte));
}

function initHighCapacity(rt: ReturnType<typeof createTec1gRuntime>): void {
writePort(rt, 0x00);
sendCommand(rt, [0x40, 0x00, 0x00, 0x00, 0x00, 0x95]);
expect(readResponse(rt)).toBe(0x01);
sendCommand(rt, [0x48, 0x00, 0x00, 0x01, 0xaa, 0x87]);
expect(readResponse(rt)).toBe(0x01);
expect(readByte(rt)).toBe(0x00);
expect(readByte(rt)).toBe(0x00);
expect(readByte(rt)).toBe(0x01);
expect(readByte(rt)).toBe(0xaa);
sendCommand(rt, [0x77, 0x00, 0x00, 0x00, 0x00, 0x65]);
expect(readResponse(rt)).toBe(0x01);
sendCommand(rt, [0x69, 0x40, 0x00, 0x00, 0x00, 0x77]);
expect(readResponse(rt)).toBe(0x01);
sendCommand(rt, [0x77, 0x00, 0x00, 0x00, 0x00, 0x65]);
expect(readResponse(rt)).toBe(0x01);
sendCommand(rt, [0x69, 0x40, 0x00, 0x00, 0x00, 0x77]);
expect(readResponse(rt)).toBe(0x00);
sendCommand(rt, [0x7a, 0x00, 0x00, 0x00, 0x00, 0xfd]);
expect(readResponse(rt)).toBe(0x00);
expect(readByte(rt)).toBe(0x40);
expect(readByte(rt)).toBe(0x00);
expect(readByte(rt)).toBe(0x00);
expect(readByte(rt)).toBe(0x00);
}

function writeDataBlock(rt: ReturnType<typeof createTec1gRuntime>, payload: Uint8Array): void {
writeByte(rt, 0xfe);
for (let i = 0; i < payload.length; i += 1) {
writeByte(rt, payload[i] ?? 0x00);
}
writeByte(rt, 0xff);
writeByte(rt, 0xff);
}

describe('TEC-1G SD SPI runtime', () => {
it('initializes and reads a block through port 0xFD', () => {
const image = new Uint8Array(1024);
image[0x0201] = 0xab;
const rt = makeRuntime(image);
writePort(rt, 0x00);
sendCommand(rt, [0x40, 0x00, 0x00, 0x00, 0x00, 0x95]);
expect(readResponse(rt)).toBe(0x01);
sendCommand(rt, [0x48, 0x00, 0x00, 0x01, 0xaa, 0x87]);
expect(readResponse(rt)).toBe(0x01);
sendCommand(rt, [0x77, 0x00, 0x00, 0x00, 0x00, 0x65]);
readResponse(rt);
sendCommand(rt, [0x69, 0x40, 0x00, 0x00, 0x00, 0x77]);
readResponse(rt);
sendCommand(rt, [0x7a, 0x00, 0x00, 0x00, 0x00, 0xfd]);
expect(readResponse(rt)).toBe(0x00);
expect(readByte(rt)).toBe(0x40);
const { rt } = makeRuntime(image);
initHighCapacity(rt);
sendCommand(rt, [0x51, 0x00, 0x00, 0x00, 0x01, 0xff]);
expect(readResponse(rt)).toBe(0x00);
expect(readByte(rt)).toBe(0xfe);
expect(readByte(rt)).toBe(0x00);
expect(readByte(rt)).toBe(0xab);
});

it('writes a block through port 0xFD', () => {
const image = new Uint8Array(1024);
const payload = new Uint8Array(512);
payload[0] = 0xde;
payload[1] = 0xad;
payload[2] = 0xbe;
const { rt } = makeRuntime(image);
initHighCapacity(rt);
sendCommand(rt, [0x58, 0x00, 0x00, 0x00, 0x01, 0xff]);
expect(readResponse(rt)).toBe(0x00);
writeDataBlock(rt, payload);
expect(readResponse(rt)).toBe(0x05);
sendCommand(rt, [0x51, 0x00, 0x00, 0x00, 0x01, 0xff]);
expect(readResponse(rt)).toBe(0x00);
expect(readByte(rt)).toBe(0xfe);
expect(readByte(rt)).toBe(0xde);
expect(readByte(rt)).toBe(0xad);
expect(readByte(rt)).toBe(0xbe);
});
});
Loading