Skip to content

Commit a7488f0

Browse files
committed
Add generator for capstone
1 parent cbcb87e commit a7488f0

File tree

2 files changed

+114
-2
lines changed

2 files changed

+114
-2
lines changed

backends/generators/tasks.rake

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
1+
# typed: false
12
# frozen_string_literal: true
23

34
require "udb/resolver"
4-
require 'json'
5-
require 'tempfile'
5+
require "json"
6+
require "tempfile"
67

78
directory "#{$root}/gen/go"
89
directory "#{$root}/gen/c_header"
910
directory "#{$root}/gen/sverilog"
1011

12+
UDB_CAPSTONE_DIR = "#{$root}/tools/python-packages/udb-capstone"
13+
directory UDB_CAPSTONE_DIR
14+
1115
def with_resolved_exception_codes(cfg_arch)
1216
# Process ERB templates in exception codes using Ruby ERB processing
1317
resolved_exception_codes = []
@@ -127,4 +131,28 @@ namespace :gen do
127131
"--output=#{output_dir}riscv_decode_package.svh --include-all"
128132
end
129133
end
134+
135+
desc <<~DESC
136+
Generate Capstone CSR switch from RISC-V CSR definitions
137+
138+
Options:
139+
* CONFIG - Configuration name (defaults to "_")
140+
* OUTPUT_DIR - Output directory for generated Capstone code (defaults to "#{$root}/gen/capstone/")
141+
DESC
142+
task capstone: "#{$root}/gen/capstone/" do
143+
config_name = ENV["CONFIG"] || "_"
144+
output_dir = ENV["OUTPUT_DIR"] || "#{$root}/gen/capstone/"
145+
146+
# Ensure the output directory exists
147+
FileUtils.mkdir_p output_dir
148+
149+
# Get the arch paths based on the config
150+
resolver = Udb::Resolver.new
151+
cfg_arch = resolver.cfg_arch_for(config_name)
152+
inst_dir = cfg_arch.path / "inst"
153+
csr_dir = cfg_arch.path / "csr"
154+
155+
# Run the Capstone CSR switch generator Python script
156+
sh "#{$root}/.home/.venv/bin/python3 #{UDB_CAPSTONE_DIR}/generate_csr_switch.py --csr-dir=#{csr_dir} --arch=BOTH --output=#{output_dir}csr_switch.c"
157+
end
130158
end
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
#!/usr/bin/env python3
2+
3+
# Copyright (c) Salil Mittal
4+
# SPDX-License-Identifier: BSD-3-Clause-Clear
5+
"""
6+
Generate a C function mapping RISC-V CSR numbers to names using a switch statement.
7+
"""
8+
9+
import sys
10+
import os
11+
12+
# Import functions from generator.py
13+
generator_dir = os.path.abspath(
14+
os.path.join(os.path.dirname(__file__), "../../../backends/generators")
15+
)
16+
sys.path.append(generator_dir)
17+
from generator import load_csrs
18+
19+
20+
def generate_csr_switch(csrs, output_file):
21+
with open(output_file, "w", encoding="utf-8") as f:
22+
fn_str = "/* SP" + "DX-License-Identifier: BSD-3-Clause */" + '"'
23+
fn_str = """
24+
/* Copyright (c) 2025 RISC-V International */
25+
/*
26+
* This file is auto-generated by riscv-unified-db
27+
*/
28+
static const char *getCSRSystemRegisterName(unsigned CsrNo)
29+
{
30+
switch (CsrNo) {
31+
"""
32+
for addr, name in sorted(csrs.items()):
33+
fn_str += f'\tcase 0x{addr:04x}:\n\t\treturn "{name.lower()}";\n'
34+
35+
fn_str += """ }
36+
return NULL;
37+
}
38+
"""
39+
f.write(fn_str)
40+
41+
42+
def main():
43+
import argparse
44+
45+
parser = argparse.ArgumentParser(description="Generate C switch for RISC-V CSRs")
46+
parser.add_argument(
47+
"--csr-dir",
48+
default=os.path.abspath(
49+
os.path.join(os.path.dirname(__file__), "../../../arch/csr/")
50+
),
51+
help="Directory containing CSR YAML files",
52+
)
53+
parser.add_argument(
54+
"--extensions",
55+
default="",
56+
help="Comma-separated list of enabled extensions (default: all)",
57+
)
58+
parser.add_argument(
59+
"--arch",
60+
default="BOTH",
61+
choices=["RV32", "RV64", "BOTH"],
62+
help="Target architecture (RV32, RV64, BOTH)",
63+
)
64+
parser.add_argument(
65+
"--output",
66+
default=os.path.join(os.path.dirname(__file__), "csr_switch.c"),
67+
help="Output C file name",
68+
)
69+
args = parser.parse_args()
70+
71+
enabled_extensions = (
72+
[ext.strip() for ext in args.extensions.split(",") if ext.strip()]
73+
if args.extensions
74+
else []
75+
)
76+
include_all = not enabled_extensions
77+
csrs = load_csrs(args.csr_dir, enabled_extensions, include_all, args.arch)
78+
79+
generate_csr_switch(csrs, args.output)
80+
print(f"Generated: {args.output}")
81+
82+
83+
if __name__ == "__main__":
84+
main()

0 commit comments

Comments
 (0)