adds shebang to process_json.py

This commit is contained in:
2025-10-01 15:47:28 +02:00
parent e935ee319d
commit 72814c5b15

View File

@@ -1,9 +1,11 @@
from abc import abstractmethod
#!/usr/bin/env python3
import argparse
import json
from abc import abstractmethod
from pathlib import Path
from typing import Union
from jsonschema import validate, ValidationError
from jsonschema import ValidationError, validate
INSTRUCTION_SCHEMA = {
"type": "object",
@@ -14,13 +16,13 @@ INSTRUCTION_SCHEMA = {
"type": "object",
"properties": {
"name": {"type": "string"},
"decoding": {"type": "string"}
"decoding": {"type": "string"},
},
"required": ["name", "decoding"]
}
"required": ["name", "decoding"],
},
}
},
"required": ["instructions"]
"required": ["instructions"],
}
@@ -36,29 +38,33 @@ class EncodingPart:
class Field(EncodingPart):
def get_bounds(self, s: str) -> tuple[int, int]:
if ":" in s:
end, start = s[s.index("["):].strip("[").rstrip("]").split(":")
end, start = s[s.index("[") :].strip("[").rstrip("]").split(":")
else:
start = end = int(s[s.index("["):].strip("[").rstrip("]"))
start = end = int(s[s.index("[") :].strip("[").rstrip("]"))
return int(start), int(end)
def __init__(self, s: str) -> None:
assert "[" in s and "]" in s
assert s.count("[") == 1 and s.count("]")
self.start, self.end = self.get_bounds(s)
self.size = self.end-self.start+1
self.name = s[:s.index("[")]
self.size = self.end - self.start + 1
self.name = s[: s.index("[")]
def __str__(self) -> str:
shift = " << " if self.pos >= self.start else ">>"
shamt = str(self.pos)
value_str = f"(\\{self.name} & 0b{self.size*'1'})"
value_str = f"(\\{self.name} & 0b{self.size * '1'})"
if self.start:
value_str = f"(\\{self.name} & 0b{self.size*'1'}{self.start*'0'})"
shamt = str(abs(self.pos-self.start))
return value_str + shift + shamt if self.pos-self.start else value_str
value_str = f"(\\{self.name} & 0b{self.size * '1'}{self.start * '0'})"
shamt = str(abs(self.pos - self.start))
return value_str + shift + shamt if self.pos - self.start else value_str
def coredsl(self) -> str:
middle = f"[{self.end}:{self.start}]" if self.size > 1 else f"[{self.end}:{self.end}]"
middle = (
f"[{self.end}:{self.start}]"
if self.size > 1
else f"[{self.end}:{self.end}]"
)
return self.name + middle
def __repr__(self) -> str:
@@ -73,11 +79,11 @@ class Literal(EncodingPart):
def __str__(self) -> str:
shamt = str(self.pos)
value_str = format(self.value, f'#0{self.size+2}b')
value_str = format(self.value, f"#0{self.size + 2}b")
return value_str + " << " + shamt if self.pos else value_str
def coredsl(self) -> str:
return format(self.value, f'#0{self.size+2}b')
return format(self.value, f"#0{self.size + 2}b")
def __repr__(self) -> str:
return "Literal: " + self.coredsl()
@@ -102,17 +108,27 @@ class Encoding:
self.name = d["name"].upper()
def _get_masked_enc(self) -> str:
masked_enc = "".join([bin(elem.value)[2:].zfill(elem.size) if isinstance(
elem, Literal) else elem.size*"x" for elem in self.parts])
masked_enc = "".join(
[
bin(elem.value)[2:].zfill(elem.size)
if isinstance(elem, Literal)
else elem.size * "x"
for elem in self.parts
]
)
return masked_enc
def _collapse_literals(self):
new_parts: list[EncodingPart] = []
for part in self.parts:
if isinstance(part, Literal) and new_parts and isinstance(new_parts[-1], Literal):
if (
isinstance(part, Literal)
and new_parts
and isinstance(new_parts[-1], Literal)
):
new_value = (new_parts[-1].value << part.size) + part.value
new_size = new_parts[-1].size + part.size
combined_val = format(new_value, f'#0{new_size+2}b')
combined_val = format(new_value, f"#0{new_size + 2}b")
collapsed = Literal(combined_val[2:])
new_parts[-1] = collapsed
else:
@@ -141,21 +157,21 @@ class Encoding:
else:
return (2, name)
field_names = [
elem.name for elem in self.parts if isinstance(elem, Field)]
field_names = [elem.name for elem in self.parts if isinstance(elem, Field)]
unique_field_names = list(dict.fromkeys(field_names))
fields_str = ', '.join(sorted(unique_field_names, key=riscv_sort_key))
header = f".macro {self.name}{',' if len(unique_field_names)> 0 else ''} {fields_str}"
fields_str = ", ".join(sorted(unique_field_names, key=riscv_sort_key))
header = f".macro {self.name}{',' if len(unique_field_names) > 0 else ''} {fields_str}"
indent = " "
comment = "# Encoding parts: " + \
" ".join([elem.coredsl() for elem in self.parts])
comment = "# Encoding parts: " + " ".join(
[elem.coredsl() for elem in self.parts]
)
self._collapse_literals()
strs = [str(elem) for elem in self.parts]
content = ".word " + " | ".join(strs)
tail = ".endm"
return "\n".join([header, indent+comment, indent+content, tail])
return "\n".join([header, indent + comment, indent + content, tail])
def parse_args():
@@ -163,20 +179,18 @@ def parse_args():
description="Generate assembler macros from CoreDSL2JSON output."
)
parser.add_argument(
"path",
type=Path,
help="Path to the JSON file generated by CoreDSL2JSON."
"path", type=Path, help="Path to the JSON file generated by CoreDSL2JSON."
)
parser.add_argument(
"--name",
type=str,
help="Name of the instruction to generate the macro for (optional)."
help="Name of the instruction to generate the macro for (optional).",
)
parser.add_argument(
"--size",
type=int,
default=-1,
help="Instruction size in bits. If not set, checks lowest bits of the instruction and determines size according to default RISC-V specification."
help="Instruction size in bits. If not set, checks lowest bits of the instruction and determines size according to default RISC-V specification.",
)
return parser.parse_args()