feat: refactor and enhance documentation for Linux runtime, boot acceptance, and NPU integration

- Updated fault reference documentation to clarify Linux termination behavior and NPU-P6 requirements.
- Enhanced Linux runtime section with emphasis on platform setup and kernel handoff processes.
- Revised overview section to include detailed descriptions of NPU capabilities and memory configurations.
- Improved product use documentation to specify Linux rootfs behavior and acceptance checkpoints.
- Clarified reset summary to differentiate between Linux and smoke/NPU-P6 acceptance processes.
- Updated software section to reflect changes in Linux image loading and readiness protocols.
- Modified build scripts to support RV64 architecture and ensure proper ELF requirements.
- Enhanced NPU compiler to support cycle counting for RV64 and RV32 architectures.
- Added tests to validate new configurations and ensure compliance with updated publication contracts.
This commit is contained in:
maksyuki committed 2026-10-01 12:41:05 +08:00
1 parent d084002bfe
commit 422f48d0cd
30 files changed
+539 -135

No files matched your search

+10 -4
View File
@@ -7,6 +7,11 @@ import argparse
import subprocess
from pathlib import Path
try:
from scripts.hp_tools import require_rv64_elf
except ModuleNotFoundError:
from hp_tools import require_rv64_elf
def build(args: argparse.Namespace) -> None:
output = args.output.resolve()
@@ -20,8 +25,8 @@ def build(args: argparse.Namespace) -> None:
subprocess.run(
[
compiler,
"-march=rv32imafdc_zicbom_zicsr_zifencei",
"-mabi=ilp32d",
"-march=rv64imafdc_zicbom_zicsr_zifencei",
"-mabi=lp64d",
"-nostdlib",
"-nostartfiles",
"-ffreestanding",
@@ -38,20 +43,21 @@ def build(args: argparse.Namespace) -> None:
],
check=True,
)
require_rv64_elf(elf)
subprocess.run(
[objcopy, "-O", "binary", str(elf), str(images / "fw_jump.bin")],
check=True,
)
(images / "retrosoc_hp.dtb").write_bytes(b"SMOK")
(images / "Image").write_bytes(b"SMOK")
(images / "rootfs.cpio.gz").write_bytes(b"SMOK")
(images / "rootfs.cpio").write_bytes(b"SMOK")
def main() -> None:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--source-dir", type=Path, required=True)
parser.add_argument("--output", type=Path, required=True)
parser.add_argument("--cross", default="riscv32-unknown-elf-")
parser.add_argument("--cross", default="riscv64-unknown-elf-")
parser.add_argument("--include", type=Path, action="append", default=[])
build(parser.parse_args())
+24 -21
View File
@@ -7,6 +7,11 @@ import argparse
import subprocess
from pathlib import Path
try:
from scripts.hp_tools import require_rv64_elf
except ModuleNotFoundError:
from hp_tools import require_rv64_elf
def build(args: argparse.Namespace) -> None:
output = args.output.resolve()
@@ -16,35 +21,33 @@ def build(args: argparse.Namespace) -> None:
compiler = f"{args.cross}gcc"
objcopy = f"{args.cross}objcopy"
command = [
compiler,
"-march=rv32imafdc_zicbom_zicsr_zifencei",
"-mabi=ilp32d",
"-nostdlib",
"-nostartfiles",
"-ffreestanding",
"-O3",
"-Wall",
"-Wextra",
"-Werror=implicit-function-declaration",
"-Werror=return-type",
"-Wl,--build-id=none",
f"-Wl,-T,{args.linker.resolve()}",
"-o",
str(elf),
str(args.source.resolve()),
compiler,
"-march=rv64imafdc_zicbom_zicsr_zifencei",
"-mabi=lp64d",
"-nostdlib",
"-nostartfiles",
"-ffreestanding",
"-O3",
"-Wall",
"-Wextra",
"-Werror=implicit-function-declaration",
"-Werror=return-type",
"-Wl,--build-id=none",
f"-Wl,-T,{args.linker.resolve()}",
"-o",
str(elf),
str(args.source.resolve()),
]
for include in args.include:
command.append(f"-I{include.resolve()}")
command.extend(str(source.resolve()) for source in args.extra_source)
command.extend(args.define)
subprocess.run(command, check=True)
require_rv64_elf(elf)
subprocess.run(
[objcopy, "-O", "binary", str(elf), str(images / "fw_jump.bin")],
[objcopy, "-O", "binary", str(elf), str(images / "hp_smoke.bin")],
check=True,
)
(images / "retrosoc_hp.dtb").write_bytes(b"SMOK")
(images / "Image").write_bytes(b"SMOK")
(images / "rootfs.cpio.gz").write_bytes(b"SMOK")
def main() -> None:
@@ -52,7 +55,7 @@ def main() -> None:
parser.add_argument("--source", type=Path, required=True)
parser.add_argument("--linker", type=Path, required=True)
parser.add_argument("--output", type=Path, required=True)
parser.add_argument("--cross", default="riscv32-unknown-elf-")
parser.add_argument("--cross", default="riscv64-unknown-elf-")
parser.add_argument("--extra-source", type=Path, action="append", default=[])
parser.add_argument("--include", type=Path, action="append", default=[])
parser.add_argument("--define", action="append", default=[])
+5 -1
View File
@@ -261,7 +261,11 @@ static const rs_{prefix}_reloc_t rs_{prefix}_npu_relocations[{len(job.relocation
{_c_bytes(f'rs_{prefix}_npu_params', job.params)}
static uint64_t rs_{prefix}_cycles(void) {{
#if defined(__riscv)
#if defined(__riscv_xlen) && (__riscv_xlen == 64)
uint64_t cycle;
__asm__ volatile("rdcycle %0" : "=r"(cycle));
return cycle;
#elif defined(__riscv)
uint32_t high0; uint32_t low; uint32_t high1;
do {{ __asm__ volatile("rdcycleh %0" : "=r"(high0));
__asm__ volatile("rdcycle %0" : "=r"(low));
+30 -9
View File
@@ -110,6 +110,32 @@ def build_variants(timestamp: str, log_dir: Path) -> dict[str, Path]:
return roots
def qualification_configuration(variants: dict[str, Path]) -> dict[str, object]:
selected = ("MINI_MODE", "APP", "SIMU", "HP_CONFIG", "EXT_CLK_HZ")
configurations: dict[str, dict[str, str]] = {}
for workload, variant in variants.items():
manifest = json.loads((variant / "meta/manifest.json").read_text(encoding="utf-8"))
configuration = manifest.get("configuration")
if not isinstance(configuration, dict) or any(
not isinstance(configuration.get(name), str) for name in selected
):
raise ValueError(f"P6 {workload} manifest lacks its PRODUCT configuration")
configurations[workload] = {name: configuration[name] for name in selected}
if set(configurations) != {"kws", "vww"} or configurations["kws"] != configurations["vww"]:
raise ValueError("P6 workload manifests use different PRODUCT configurations")
configuration = configurations["kws"]
expected = {
"MINI_MODE": "PRODUCT",
"APP": "hp_boot",
"SIMU": "VERILATOR",
"HP_CONFIG": "rv64imafdc_zicbom_max",
"EXT_CLK_HZ": "72000000",
}
if configuration != expected:
raise ValueError(f"P6 manifest configuration differs from the frozen target: {configuration}")
return {**configuration, "EXT_CLK_HZ": int(configuration["EXT_CLK_HZ"])}
def parse_case_line(line: str) -> dict[str, Any]:
if not line.startswith(CASE_PREFIX):
raise ValueError("not an NPU-P6 case record")
@@ -168,10 +194,10 @@ def package_shard(
shard_dir = output / workload / f"shard-{shard_index:03d}"
images = shard_dir / "images"
images.mkdir(parents=True, exist_ok=True)
shutil.copy2(variant / "hp-smoke/images/fw_jump.bin", images / "fw_jump.bin")
shutil.copy2(variant / "hp-smoke/images/hp_smoke.bin", images / "fw_jump.bin")
shutil.copy2(Path(shard["file"]["path"]), images / "Image")
(images / "retrosoc_hp.dtb").write_bytes(b"SMOK")
(images / "rootfs.cpio.gz").write_bytes(b"SMOK")
(images / "rootfs.cpio").write_bytes(b"SMOK")
bundle = shard_dir / "retrosoc_npu_p6.bin"
manifest = shard_dir / "bundle.json"
completed = run(
@@ -396,6 +422,7 @@ def main() -> int:
output = args.output_dir.resolve()
output.mkdir(parents=True, exist_ok=True)
variants = build_variants(args.build_timestamp, output / "build-logs")
configuration = qualification_configuration(variants)
emulator = variants["kws"] / "sim/verilator/emu"
if not emulator.is_file():
raise ValueError("P6 PRODUCT Verilator emulator is missing")
@@ -441,13 +468,7 @@ def main() -> int:
["git", "-C", str(ROOT), "rev-parse", "HEAD"], text=True
).strip(),
"profile": "configs/ci/ihp130.mk",
"configuration": {
"MINI_MODE": "PRODUCT",
"APP": "hp_boot",
"SIMU": "VERILATOR",
"HP_CONFIG": "rv32imafdc_zicbom_max",
"EXT_CLK_HZ": 72_000_000,
},
"configuration": configuration,
"measurement": {
"counter": "HP rdcycle",
"reference": "portable INT8 C through CPU Softmax",