/** * Parses and asserts correct timings for every instruction in `instructions.s` */ import fs from "fs"; import parse from "../../src/parse"; import evaluate from "../../src/parse/evaluate"; import { Timing } from "../../src/timings"; const instructions = fs .readFileSync(__dirname + "/../examples/instructions.s") .toString(); /** * Extract expected timings from line comment */ function parseComment( comment: string, m?: number ): { total: Timing; index: number } { let index = 0; const [timings, caseText] = comment .substr(1) .split(";") .map((n) => n.trim()); // The comment suffix determines which timing we looks at where there are multiple values switch (caseText) { case "Branch not taken": case "Branch not taken, cc true": case "cc true": case "Trap": case "Trap, d0 > ": index = 1; break; case "Branch not taken, counter expired": case "Trap, d0 < 0": index = 2; break; } if (timings.includes("=")) { const total = parseTime(timings.split("=").pop().trim(), m); return { total, index }; } else { return { total: parseTime(timings, m), index, }; } } /** * Convert string formatted timing 'x(y/z)' */ const parseTime = (str: string, m?: number): Timing => str .match(/([\d+m]+)\(([\d+m]+)\/([\d+m]+)\)/) .slice(1) .map((n) => evaluate(n.replace(/(\d)m/, "$1*m"), { m })) as Timing; describe("instruction timings", () => { const lines = parse(instructions); for (let i = 0; i < lines.length; i++) { const { statement, timing } = lines[i]; if ( // Does this look like it should be an instruction? // Don't rely on `isInstruction()` as this won't catch unsupported mnemonics !statement.isDirective() && !statement.isLabel() && statement.text.trim() && // ignore empty lines !statement.text.match(/^\s*;/) // ignore comment-only lines ) { test(statement.text, () => { expect(statement.isInstruction()).toBeTruthy(); const { values: timings, calculation } = timing; const m = Array.isArray(calculation.n) ? calculation.n[0] : calculation.n; const { total, index } = parseComment(statement.comment.text, m); const idx = Math.min(index, timings.length - 1); expect(timings[idx]).toEqual(total); }); } } });