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