import contextlib, csv, io, os, subprocess, sys
root = sys.argv[1]
names = {}
for f in ('csrs.csv', 'csrs32.csv'):
for num, name in csv.reader(open(os.path.join(root, f)), skipinitialspace=True):
num = int(num, 16)
assert names.setdefault(num, name) == name, (hex(num), name)
rev = subprocess.run(['git', '-C', root, 'rev-parse', 'HEAD'], capture_output=True, text=True).stdout.strip()
code = io.StringIO()
with contextlib.redirect_stdout(code):
print(f'''// Copyright (c) 2026 Christopher Swenson
// Licensed under the Apache-2.0 license.
//! Control and status register names.
//!
//! Generated by scripts/gen-csr-names.py from riscv-opcodes {rev}
//! (Copyright (c) 2022 RISC-V International, BSD-3-Clause).
/// Returns the name of CSR `csr`, or `None` if it has no standard name.
pub(crate) fn csr_name(csr: u16) -> Option<&'static str> {{
Some(match csr {{''')
for num in sorted(names):
print(f' {num:#05x} => "{names[num]}",')
print(''' _ => return None,
})
}
#[cfg(test)]
mod tests {
use super::csr_name;
#[test]
fn names_are_unique() {
let mut names: [Option<&str>; 0x1000] = [None; 0x1000];
for (csr, slot) in names.iter_mut().enumerate() {
*slot = csr_name(csr as u16);
}
names.sort_unstable();
for pair in names.windows(2) {
assert!(
pair[0].is_none() || pair[0] != pair[1],
"duplicate CSR name {:?}",
pair[0]
);
}
}
}''')
formatted = subprocess.run(['rustfmt', '--edition', '2024'], input=code.getvalue(),
capture_output=True, text=True, check=True).stdout
sys.stdout.write(formatted)