import fs from 'fs'; import { createESP32, ESP32 } from '../web/js/soc.js'; const wasmBytes = fs.readFileSync(new URL('../wasm/xtensa.wasm', import.meta.url)); for (const eng of ['wasm', 'js']) { const soc = eng === 'wasm' ? await createESP32({ wasmBytes }) : new ESP32({}); soc.reset('power'); // program at 0x40080000 (IRAM): mixed loop const code = []; const e = (...b) => code.push(...b); // movi a2, 0x7fff? use loop counter in a3 via l32r-free sequence: movi a3,1000(?) up to 2047 via movi (imm12) // loop: addi a4,a4,1 ; add a5,a4,a3 ; xor a6,a5,a4 ; s32i a6,a1?no. use a7 as pointer to DRAM // encode by assembling with objdump-free manual encodings: // movi a3, 2000 -> 0xA3 0x07 0xD0? use: movi a3, -1 ... keep simple: use loop instruction. // We'll use: loopgtz a3, end ; addi.n a4,a4,1 ; add.n a5,a4,a4 ; xor a6,a5,a4 ; s32i a6,a7,0 ; l32i a8,a7,0 ; end: ; j start const asm = [ 0xa0, 0x20, 0x00, // placeholder will be replaced ]; const mem = soc.h8; const base = 0x40080000; const off = (soc.cpus[0].rd[base >>> 12] + base) | 0; // bytes: movi a3, 2047 : r=10 (MOVI) imm8=0xFF, s=7 (imm12 hi), t=3 => inst = imm8<<16 | 0xA<<12 | s<<8 | t<<4 | 2 const w = (i) => [i & 255, (i >> 8) & 255, (i >> 16) & 255]; const prog = []; prog.push(...w((0xFF << 16) | (0xA << 12) | (7 << 8) | (3 << 4) | 2)); // movi a3, 2047 // movi a7, DRAM addr: use l32r? skip: use a1 (sp) region: a1 holds 0? set a7 via movi 0x...: use add.n? simply movi a7, 0x7ff? that's addr 0x7ff (unmapped slow!). use window: set a7 = pc-based? use call0 trick -> skip, use address in IRAM-literal: l32r a7, lit // literal at start+0x40: value 0x3ffb0000 const litAddr = base + 0x40; // l32r a7, lit : imm16 = ((lit - ((pc+3)&~3))>>2) & 0xFFFF const pcL = base + 3; const imm16 = (((litAddr - ((pcL + 3) & ~3)) >> 2) & 0xFFFF); prog.push(...w((imm16 << 8) | (7 << 4) | 1)); // l32r a7, lit const loopStart = base + prog.length; // loopgtz a3, end (BI1 m=1 B1 r=10): inst= imm8<<16 | 10<<12 | s<<8 | (n=3,m=1 -> t=0b0111) <<4 | 6 const bodyIns = []; bodyIns.push(0x4a, 0x1b); // addi.n a4,a4,1 ? (placeholder replaced below) const narrow = (op0, t, s, r) => [(t << 4) | op0, (r << 4) | s]; const body = []; const ONLY_ADD = process.env.ONLY_ADD === '1'; if (ONLY_ADD) { for (let k = 0; k < 8; k++) body.push(...narrow(0xA, 4, 4, 5)); } else { body.push(...narrow(0xB, 1, 4, 4)); // addi.n a4,a4,1 (t=1) r=4,s=4 body.push(...narrow(0xA, 4, 4, 5)); // add.n a5,a4,a4 body.push(...w((0x3 << 20) | (0x0 << 16) | (6 << 12) | (5 << 8) | (4 << 4) | 0)); // xor a6,a5,a4 (op2=3 op1=0) body.push(...w((0x06 << 12) | (7 << 8) | (6 << 4) | 2) .map((b,i)=>b)); // s32i a6,a7,0 : r=6 -> inst = imm8(0)<<16 | r=6<<12 | s=7<<8 | t=6<<4 | 2 body.push(...w((0x02 << 12) | (7 << 8) | (8 << 4) | 2)); // l32i a8,a7,0 (r=2) body.push(...narrow(0xA, 9, 8, 6)); } const loopLen = body.length; // loop instr: lend = pc+4+imm8 const loopInst = (loopLen << 16) | (10 << 12) | (3 << 8) | (0x7 << 4) | 6; prog.push(...w(loopInst)); prog.push(...body); // j start (backwards): J: op0=6,n=0 imm18 = off ; target = pc+4+off const jpc = base + prog.length; const joff = (loopStart - 4 - 0 - jpc); // jump back to the loop instruction const j18 = ((loopStart - (jpc + 4)) & 0x3FFFF); prog.push(...w((j18 << 6) | 6)); while (prog.length < 0x40) prog.push(0); prog.push(0, 0, 0xfb, 0x3f); // literal 0x3ffb0000 mem.set(prog, off); const c = soc.cpus[0]; c.pc = base; c.ps = 0x20; c.cpenable = 0; c.chkInt = false; c.intenable = 0; const N = 30e6; const t0 = process.hrtime.bigint(); for (let i = 0; i < N; i += 100000) c.run(100000); const dt = Number(process.hrtime.bigint() - t0) / 1e9; console.log(eng, (N / dt / 1e6).toFixed(1), 'MIPS', 'pc', (c.pc >>> 0).toString(16), 'a4', c.ar[(c.wb4 + 4) & 63]); }