Files
retroSoC/scripts/apu_p5_coefficients.py
T
maksyuki ef754cd0ac feat: update APU register testbench and add codec transport tests
- Modified the capability register value in apu_reg_tb.sv to 0x01bd.
- Simplified rejected write checks for the COMMAND register in apu_reg_tb.sv.
- Added backend build ID input to the ring scheduler testbench.
- Updated test cases in test_apu.py to include new codec transport and controller files.
- Created new test file test_apu_codec_transport.py for APU-P5 transport assembler and parser tests.
- Added codec profile and dependency tests in test_apu_codecs.py.
- Enhanced register parity tests to include P5 primitive mask.
- Improved script tools tests for file download functionality and dependency helpers.
2026-09-06 07:43:16 +08:00

134 lines
4.5 KiB
Python

#!/usr/bin/env python3
"""Generate the frozen APU-P5 32-phase, 16-tap Q2.30 coefficient banks."""
from __future__ import annotations
import argparse
import hashlib
import json
import struct
from decimal import Decimal, ROUND_HALF_EVEN, localcontext
from pathlib import Path
def _pi(precision: int) -> Decimal:
with localcontext() as context:
context.prec = precision + 16
multiplier = Decimal(1)
linear = Decimal(13591409)
exponent = Decimal(1)
total = linear
k_value = Decimal(6)
terms = precision // 14 + 3
for index in range(1, terms):
divisor = Decimal(index) ** 3
multiplier = multiplier * (k_value**3 - Decimal(16) * k_value) / divisor
linear += Decimal(545140134)
exponent *= Decimal(-262537412640768000)
total += multiplier * linear / exponent
k_value += Decimal(12)
value = Decimal(426880) * Decimal(10005).sqrt() / total
context.prec = precision
return +value
def _sin(value: Decimal, pi_value: Decimal, precision: int) -> Decimal:
with localcontext() as context:
context.prec = precision + 12
period = Decimal(2) * pi_value
value %= period
if value > pi_value:
value -= period
term = value
total = value
index = 1
threshold = Decimal(10) ** Decimal(-(precision + 4))
while abs(term) > threshold:
term *= -(value * value) / Decimal((2 * index) * (2 * index + 1))
total += term
index += 1
context.prec = precision
return +total
def _cos(value: Decimal, pi_value: Decimal, precision: int) -> Decimal:
return _sin(value + pi_value / Decimal(2), pi_value, precision)
def coefficient_words(precision: int = 112) -> list[int]:
with localcontext() as context:
context.prec = precision
pi_value = _pi(precision)
banks = (Decimal(1), Decimal(2) / Decimal(3), Decimal(1) / Decimal(2))
words: list[int] = []
for cutoff in banks:
for phase in range(32):
amplitudes: list[Decimal] = []
for tap in range(16):
x_value = Decimal(tap - 7) - Decimal(phase) / Decimal(32)
argument = cutoff * x_value
sinc = (
Decimal(1)
if argument == 0
else _sin(pi_value * argument, pi_value, precision) /
(pi_value * argument)
)
window = (
Decimal(1) -
_cos(
Decimal(2) * pi_value * (Decimal(tap) + Decimal("0.5")) /
Decimal(16),
pi_value,
precision,
)
) / Decimal(2)
amplitudes.append(cutoff * sinc * window)
scale = sum(amplitudes)
phase_words = [
int((Decimal(1 << 30) * value / scale).to_integral_value(
rounding=ROUND_HALF_EVEN
))
for value in amplitudes
]
phase_words[7] += (1 << 30) - sum(phase_words)
words.extend(phase_words)
return words
def coefficient_bytes() -> bytes:
first = coefficient_words(112)
independent = coefficient_words(160)
if first != independent:
raise RuntimeError("coefficient rounding did not converge across precision bounds")
return b"".join(struct.pack("<i", word) for word in first)
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--output", type=Path, required=True)
parser.add_argument("--manifest", type=Path, required=True)
args = parser.parse_args()
payload = coefficient_bytes()
args.output.parent.mkdir(parents=True, exist_ok=True)
args.output.write_bytes(payload)
args.manifest.write_text(
json.dumps(
{
"banks": 3,
"phases": 32,
"taps": 16,
"words": len(payload) // 4,
"bytes": len(payload),
"sha256": hashlib.sha256(payload).hexdigest(),
},
indent=2,
sort_keys=True,
) + "\n",
encoding="utf-8",
)
return 0
if __name__ == "__main__":
raise SystemExit(main())