mirror of
https://github.com/ApfelTeeSaft/WebMetal.git
synced 2026-08-26 19:43:24 +00:00
111 lines
3.8 KiB
JavaScript
111 lines
3.8 KiB
JavaScript
import { readFileSync } from 'node:fs'
|
|
import { fileURLToPath, pathToFileURL } from 'node:url'
|
|
import { dirname, join } from 'node:path'
|
|
|
|
const repoRoot = dirname(dirname(fileURLToPath(import.meta.url)))
|
|
const modulePath =
|
|
process.argv[2] ?? join(repoRoot, 'wasm/build-wasm/webmetal-engine-node.mjs')
|
|
const vectorsPath = join(repoRoot, 'conformance/microop-vectors.json')
|
|
|
|
const { default: createModule } = await import(pathToFileURL(modulePath).href)
|
|
const module_ = await createModule()
|
|
const file = JSON.parse(readFileSync(vectorsPath, 'utf-8'))
|
|
|
|
const heap = () => module_.HEAPU32
|
|
let failures = 0
|
|
const fail = (name, message) => {
|
|
failures++
|
|
console.error(` ✗ ${name}: ${message}`)
|
|
}
|
|
|
|
for (const vector of file.vectors) {
|
|
const engine = new module_.Engine()
|
|
const model = vector.model ?? file.defaultModel
|
|
if (!engine.loadModel(JSON.stringify(model))) {
|
|
fail(vector.name, `loadModel failed: ${engine.lastError()}`)
|
|
engine.delete()
|
|
continue
|
|
}
|
|
const layout = JSON.parse(engine.stateLayout())
|
|
const base = engine.stateBufferPtr() >> 2
|
|
const flagIndex = (name) => layout.flags.names.indexOf(name)
|
|
const bankOf = (name) => layout.banks.find((b) => b.name === name)
|
|
const memOf = (name) => layout.memories.find((m) => m.name === name)
|
|
|
|
// setup
|
|
const setup = vector.setup ?? {}
|
|
for (const [bank, values] of Object.entries(setup.banks ?? {})) {
|
|
values.forEach((v, i) => {
|
|
heap()[base + bankOf(bank).offset + i] = v
|
|
})
|
|
}
|
|
for (const [mem, cells] of Object.entries(setup.memories ?? {})) {
|
|
for (const [addr, v] of Object.entries(cells)) {
|
|
heap()[base + memOf(mem).offset + Number(addr)] = v
|
|
}
|
|
}
|
|
for (const [flag, v] of Object.entries(setup.flags ?? {})) {
|
|
heap()[base + layout.flags.offset + flagIndex(flag)] = v ? 1 : 0
|
|
}
|
|
if (setup.pc !== undefined) heap()[base + layout.pc] = setup.pc
|
|
|
|
// run
|
|
let error = ''
|
|
for (const step of vector.run) {
|
|
error = engine.execSequence(
|
|
JSON.stringify(step.microOps),
|
|
JSON.stringify(step.operands ?? {}),
|
|
)
|
|
if (error !== '') break
|
|
}
|
|
|
|
if (vector.expectError !== undefined) {
|
|
if (error === '') fail(vector.name, 'expected an error, got none')
|
|
else if (!error.includes(vector.expectError))
|
|
fail(vector.name, `error "${error}" lacks "${vector.expectError}"`)
|
|
engine.delete()
|
|
continue
|
|
}
|
|
if (error !== '') {
|
|
fail(vector.name, `unexpected error: ${error}`)
|
|
engine.delete()
|
|
continue
|
|
}
|
|
|
|
// expect (partial)
|
|
const expect = vector.expect ?? {}
|
|
const problems = []
|
|
for (const [bank, values] of Object.entries(expect.banks ?? {})) {
|
|
values.forEach((want, i) => {
|
|
const got = heap()[base + bankOf(bank).offset + i]
|
|
if (got !== want) problems.push(`${bank}[${i}] = ${got}, want ${want}`)
|
|
})
|
|
}
|
|
for (const [mem, cells] of Object.entries(expect.memories ?? {})) {
|
|
for (const [addr, want] of Object.entries(cells)) {
|
|
const got = heap()[base + memOf(mem).offset + Number(addr)]
|
|
if (got !== want) problems.push(`${mem}[${addr}] = ${got}, want ${want}`)
|
|
}
|
|
}
|
|
for (const [flag, want] of Object.entries(expect.flags ?? {})) {
|
|
const got = heap()[base + layout.flags.offset + flagIndex(flag)] !== 0
|
|
if (got !== want) problems.push(`flag ${flag} = ${got}, want ${want}`)
|
|
}
|
|
if (expect.pc !== undefined && heap()[base + layout.pc] !== expect.pc) {
|
|
problems.push(`pc = ${heap()[base + layout.pc]}, want ${expect.pc}`)
|
|
}
|
|
if (expect.halted !== undefined) {
|
|
const got = (heap()[base + layout.status] & 1) !== 0
|
|
if (got !== expect.halted) problems.push(`halted = ${got}`)
|
|
}
|
|
for (const problem of problems) fail(vector.name, problem)
|
|
engine.delete()
|
|
}
|
|
|
|
const total = file.vectors.length
|
|
if (failures > 0) {
|
|
console.error(`\n${failures} failure(s) across ${total} vectors (wasm build)`)
|
|
process.exit(1)
|
|
}
|
|
console.log(`all ${total} conformance vectors pass against the wasm build`)
|