Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
8347485
[Metamodel] Refactor Literal and one common PrimitiveKind type
jokap11 Apr 24, 2026
80e6787
[MetaModel] Move Primitive+Literal Types+Literals into own file
jokap11 Apr 27, 2026
5bc24ac
[Backend] Use type_info
jokap11 Apr 27, 2026
0fb43f7
[Metamodel] Remove IntLiteral occurances
jokap11 Apr 28, 2026
58ba68c
[MetaModel] Switch Typing System
jokap11 Apr 29, 2026
f606f80
[MetaModel] Move etiss attribute into ETISS backend
jokap11 Apr 29, 2026
2ed0c73
[MetaModel] Attributes into type_info
jokap11 Apr 30, 2026
3e4c72b
[MetaModel] StaticType into TypeInfo
jokap11 Apr 30, 2026
8c3f788
[MetaModel] Move attributes into own attribute func
jokap11 Apr 30, 2026
c4e5099
[Metamodel] Use properties for expressive assertions
jokap11 Apr 30, 2026
4df2be8
[Metmodel] Warning for deprecated IntegerType Constr
jokap11 Apr 30, 2026
30bce23
[Metamodel] Typing remove redundant TypeKind enums
jokap11 Apr 30, 2026
e8ac700
[MetaModel] Avoid Deprecated IntegerType constructor
jokap11 Apr 30, 2026
9a47542
[MetaModel] Lit = 0 needs to be signed (Warning in GCC)
jokap11 Apr 30, 2026
bd999e8
Merge branch 'develop' into meta_type_refactor
jokap11 Apr 30, 2026
1627b73
[MetaModel] Abstract scalar class in more abstract Symbol
jokap11 Apr 30, 2026
7bec7bb
[MetaModel] WIP abstract Symbol class for ARCH
jokap11 May 1, 2026
d285249
[MetaModel] Bugfix use attributes[static] for Symbols
jokap11 May 4, 2026
e73670e
[MetaModel] Get Rid of IntegerType by PointerType
jokap11 May 4, 2026
dd0366e
[MetaModel] WIP split arch.Memory in RegisterBanks/Alias/MEM
jokap11 May 11, 2026
a8334e7
[MetaModel] WIP Architecture Classes bugfix for infer+simplify
jokap11 May 14, 2026
2121a50
[Transform] Type Inferene for Funcs as well
jokap11 May 14, 2026
dac6ea0
[Backend] MetaModel Viewer update for Alias/Memory
jokap11 May 14, 2026
68a21ee
[Metamodel] Remove addition Type info for Type Conv
jokap11 May 14, 2026
8e192b0
[Frontend] CoreDSL 2 add properties for regs/mem
jokap11 May 26, 2026
0cd5136
[FrontEnd] CoreDSL bugfix of Alias init + Dict instead of Set
jokap11 May 26, 2026
5c3bd66
[Backend] Make Viewer Ref type better readable
jokap11 May 26, 2026
56de585
[Backend] ETISS refactor with new Register/Memory/Alias classes
jokap11 May 26, 2026
f7deed3
[MetaModel] Remove init from Alias declaration
jokap11 May 26, 2026
56bc5b4
[MetaModel] Constrain Types of Literals
jokap11 May 26, 2026
27ba05a
[Backend] Etiss eval constants at a certain time
jokap11 May 26, 2026
9cfa338
[MetaModel] Switch Constant with more precise Parameter term
jokap11 May 29, 2026
ca607fd
[MetaModel] Rename ArrayType Subtype from kind to type
jokap11 May 29, 2026
7acca32
[Backend] ETISS change element_kind with type
jokap11 May 31, 2026
d862328
[MetaModel] Fix Issue with wrong type inference for Aliases
jokap11 Jun 17, 2026
6bfa4e3
[ETISS] Generate Signed Register
jokap11 Jun 17, 2026
377eaab
Merge branch 'coredsl2' into meta_type_refactor
jokap11 Jul 2, 2026
4c27134
[InferTypes] Debug Merge Issues from MetaTypeRefactor
jokap11 Jul 2, 2026
c33d507
[Transforms] Replace width with type_info.size for Validator
jokap11 Jul 2, 2026
dd7cb04
[Transforms] Replace signed with type_info.TypeKind for Validator
jokap11 Jul 2, 2026
df3e12e
[Transforms] Small Bugfix in Validator
jokap11 Jul 2, 2026
7f4df61
[Transform] Fix const eval for Validator
jokap11 Jul 2, 2026
e771283
[MetaModel] Bugfix access static in Dict and not as attr of Obj
jokap11 Jul 15, 2026
0a22760
[Backend] ETISS GDB generation with new Type System
jokap11 Jul 15, 2026
d4e4381
[MetaModel] Switch API of Literal
jokap11 May 31, 2026
9f48acd
[MetaModel] Rename Scalar in more general Var
jokap11 May 31, 2026
8b20606
[MetaModel] New Tensor Class for n-D Literals
jokap11 Jun 2, 2026
15e8adf
[FrontEnd] Parse InitializerList in CoreDSL Frontend
jokap11 Jun 2, 2026
f4b4ad7
[Backend] Viewer Tensor Support
jokap11 Jun 2, 2026
f2d4102
[Backend] Add behav Array support within ETISS
jokap11 Jun 3, 2026
adc8120
[FrontEnd] Fix type casting in Alias
jokap11 Jun 8, 2026
b5671b0
[MetaModel] Raname StaticNess to Access attribute
jokap11 Jun 8, 2026
41a2fd5
[MetaModel] Support attributes in VarDefs
jokap11 Jun 10, 2026
0472c3d
Add missing utils for n-D type inference
jokap11 Jun 17, 2026
a603ed8
Remove redundant requirements.txt + small bug fix in ETISS writer
jokap11 Jul 5, 2026
4e8ab94
Change static-vars flag to meet CI/CD
jokap11 Jul 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 2 additions & 6 deletions m2isar/backends/coverage/id_transform.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,15 +57,11 @@ def _(self, expr: behav.ConcatOperation, context: "IdMatcherContext"):
self.generate(expr.right, context)

@generate.register
def _(self, expr: behav.NumberLiteral, context: "IdMatcherContext"):
def _(self, expr: behav.Literal, context: "IdMatcherContext"):
self._store_id(expr, context)

@generate.register
def _(self, expr: behav.IntLiteral, context: "IdMatcherContext"):
self._store_id(expr, context)

@generate.register
def _(self, expr: behav.ScalarDefinition, context: "IdMatcherContext"):
def _(self, expr: behav.VarDefinition, context: "IdMatcherContext"):
self._store_id(expr, context)

@generate.register
Expand Down
2 changes: 1 addition & 1 deletion m2isar/backends/etiss/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ These functionalities must be implemented manually in the file `<core_name>ArchS

## Known issues
- Instruction behavior such as `MEM[X[rs1] + imm] = MEM[X[rs2]]` does not see `X[rs1]` as a dependent register.
- Staticness (whether the value of a variable is completely known at instruction generation time, i.e. outside of JIT-compilation in ETISS) detection of instruction-level local variables (scalars) is crude and breaks once multiple levels of scoping are necessary.
- Staticness (whether the value of a variable is completely known at instruction generation time, i.e. outside of JIT-compilation in ETISS) detection of instruction-level local variables (vars) is crude and breaks once multiple levels of scoping are necessary.
- The above also breaks ETISS's register dependency tracking when scope-restricted variables or expressions are used for register addressing, see [issue #6](https://github.com/tum-ei-eda/M2-ISA-R/issues/6) in this repo.

## Usage
Expand Down
136 changes: 100 additions & 36 deletions m2isar/backends/etiss/architecture_writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,54 +10,96 @@

import logging
import pathlib
from itertools import chain
from typing import Union

from mako.template import Template


from .instruction_utils import actual_size, reg_type_info
from ... import M2TypeError
from ...metamodel import arch, behav
from ...metamodel import arch, behav, type_info, attribute_info
from . import BlockEndType
from .instruction_generator import (generate_fields,
generate_instruction_callback)
from .templates import template_dir

logger = logging.getLogger("arch_writer")

def write_child_reg_def(reg: arch.Memory, regs: "list[str]"):
"""Recursively generate register declarations"""
def write_child_reg_def(reg: Union[arch.Memory, arch.RegisterBank, arch.Register], regs: "list[str]"):
"""Recursively generate child declarations for Memories and Register(Banks)"""

logger.debug("processing register %s", reg)
if arch.MemoryAttribute.IS_PC in reg.attributes or arch.MemoryAttribute.IS_MAIN_MEM in reg.attributes:
if attribute_info.RegisterAttribute.IS_PC in reg.attributes or attribute_info.MemoryAttribute.IS_MAIN_MEM in reg.attributes:
logger.debug("this register is either the PC or main memory, skipping")
return

array_txt = f"[{reg.data_range.length}]" if reg.data_range.length > 1 else ""
assert(isinstance(reg.ty, (type_info.ArrayType, type_info.PrimitiveType, type_info.PointerType)))
type_acc = reg_type_info(reg)
if isinstance(reg.ty, type_info.ArrayType):
array_txt = f"[{arch.get_const_or_val(reg.ty.length)}]"
assert(reg.ty.element_type.kind in (type_info.TypeKind.UINT, type_info.TypeKind.INT))
elif isinstance(reg.ty, type_info.PrimitiveType):
assert(reg.ty.kind in (type_info.TypeKind.UINT, type_info.TypeKind.INT))
array_txt = ""
elif isinstance(reg.ty, type_info.PointerType):
array_txt = f"[{arch.get_const_or_val(reg.data_range.length)}]" if arch.get_const_or_val(reg.data_range.length) > 1 else ""
else:
array_txt = ""

if hasattr(reg, "children"):

if len(reg.children) > 0:
logger.debug("processing children")
for child in reg.children:
write_child_reg_def(child, regs)

# registers with children (aliases) are defined as two arrays:
# 1) array of pointers, used for actual access
# 2) array of actual data type, for every index which is not aliased
regs.append(f"etiss_uint{reg.actual_size} *{reg.name}{array_txt}")
regs.append(f"etiss_uint{reg.actual_size} ins_{reg.name}{array_txt}")
type_acc = reg_type_info(reg)
if isinstance(reg.ty, type_info.ArrayType):
assert(reg.ty.element_type.kind in (type_info.TypeKind.UINT, type_info.TypeKind.INT))
size = actual_size(reg.ty.element_type.size)
elif isinstance(reg.ty, type_info.PrimitiveType):
assert(reg.ty.kind in (type_info.TypeKind.UINT, type_info.TypeKind.INT))
size = actual_size(reg.ty.size)
else:
raise "Register Types needs to be of Array or PrimitiveType"

if (len(reg.children) > 0):
regs.append(f"{type_acc}{size} *{reg.name}{array_txt}")
regs.append(f"{type_acc}{size} ins_{reg.name}{array_txt}")
else:
regs.append(f"{type_acc}{actual_size(size)} {reg.name}{array_txt}")

else:
regs.append(f"etiss_uint{reg.actual_size} {reg.name}{array_txt}")
size = None
if isinstance(reg.ty, type_info.PointerType):
assert(isinstance(reg.ty.ty, type_info.PrimitiveType))
size = actual_size(reg.ty.ty.size)
else:
assert(isinstance(reg.ty, type_info.PrimitiveType))
size = actual_size(reg.ty.size)
regs.append(f"{type_acc}{size} {reg.name}{array_txt}")

def write_arch_struct(core: arch.CoreDef, start_time: str, output_path: pathlib.Path):
arch_struct_template = Template(filename=str(template_dir/'etiss_arch_struct.mako'))
regs = []
mems = []

logger.info("writing architecture struct")

for _, mem_desc in core.memories.items():
write_child_reg_def(mem_desc, regs)
assert core.memories is not None and core.register_banks is not None
for _, reg_desc in chain(core.register_banks.items()):
write_child_reg_def(reg_desc, regs)
for _, mem_desc in chain(core.memories.items()):
write_child_reg_def(mem_desc, mems)

txt = arch_struct_template.render(
start_time=start_time,
core_name=core.name,
regs=regs
regs=regs,
mems=mems
)

with open(output_path / f"{core.name}.h", "w", encoding="utf-8") as f:
Expand All @@ -77,8 +119,9 @@ def write_arch_header(core: arch.CoreDef, start_time: str, output_path: pathlib.
with open(output_path / f"{core.name}Arch.h", "w", encoding="utf-8") as f:
f.write(txt)

def build_reg_hierarchy(reg: arch.Memory, ptr_regs: "list[arch.Memory]", actual_regs: "list[arch.Memory]",
alias_regs: "dict[arch.Memory, arch.Memory]", initval_regs: "list[arch.Memory]"):
def build_reg_hierarchy(reg: Union[arch.Memory, arch.Alias, arch.Register, arch.RegisterBank],
ptr_regs: "list[arch.Memory]", actual_regs: "list[arch.Memory]",
alias_regs: "dict[arch.Memory, arch.Memory]", initval_regs: "list[arch.Memory]"):
"""Populate the passed lists with memory objects of their category.

ptr_regs: Registers that need to be a pointer within ETISS
Expand All @@ -91,16 +134,21 @@ def build_reg_hierarchy(reg: arch.Memory, ptr_regs: "list[arch.Memory]", actual_
if reg._initval:
initval_regs.append(reg)

if len(reg.children) > 0:
for child in reg.children:
if child.is_main_mem:
logger.warning("main memory is a child memory of %s", reg)
continue
build_reg_hierarchy(child, ptr_regs, actual_regs, alias_regs, initval_regs)
alias_regs[child] = reg
ptr_regs.append(reg)
if isinstance(reg, (arch.Memory, arch.Register, arch.RegisterBank)):
if len(reg.children) > 0:
for child in reg.children:
if hasattr(child, "is_main_mem"):
if child.is_main_mem:
logger.warning("main memory is a child memory of %s", reg)
continue
build_reg_hierarchy(child, ptr_regs, actual_regs, alias_regs, initval_regs)
alias_regs[child] = reg
ptr_regs.append(reg)
else:
actual_regs.append(reg)
else:
actual_regs.append(reg)
assert isinstance(reg, arch.Alias)
return

def write_arch_cpp(core: arch.CoreDef, start_time: str, output_path: pathlib.Path, aliased_regnames: bool=True):
"""Generate {CoreName}Arch.cpp file. Contains mainly register initialization code."""
Expand All @@ -115,15 +163,16 @@ def write_arch_cpp(core: arch.CoreDef, start_time: str, output_path: pathlib.Pat
logger.info("writing architecture class file")

# determine memory types
for _, mem_desc in core.memories.items():
if mem_desc.is_main_mem:
continue
for _, mem_desc in chain(core.memories.items(), core.register_banks.items(), core.memory_aliases.items(), core.register_aliases.items()):
if hasattr(mem_desc, "is_main_mem"):
if mem_desc.is_main_mem:
continue
build_reg_hierarchy(mem_desc, ptr_regs, actual_regs, alias_regs, initval_regs)

# generate main register file names for ETISS's 'char* reg_name[]'
reg_names = [f"{core.main_reg_file.name}{n}" for n in range(core.main_reg_file.data_range.length)]
reg_names = [f"{core.main_reg_file.name}{n}" for n in range(core.main_reg_file.ty.length)]
if core.float_reg_file is not None:
reg_names += [f"{core.float_reg_file.name}{n}" for n in range(core.float_reg_file.data_range.length)]
reg_names += [f"{core.float_reg_file.name}{n}" for n in range(core.float_reg_file.ty.length)]
# TODO(annnnna42): add float reg names (F0-F31) here

# if main register file entries have aliases optionally use these for 'char* reg_name[]'
Expand All @@ -142,7 +191,9 @@ def write_arch_cpp(core: arch.CoreDef, start_time: str, output_path: pathlib.Pat
actual_regs=actual_regs,
alias_regs=alias_regs,
initval_regs=initval_regs,
procno_memory=core.procno_memory
procno_memory=core.procno_memory,
type_info=type_info,
arch=arch,
)

with open(output_path / f"{core.name}Arch.cpp", "w", encoding="utf-8") as f:
Expand All @@ -166,13 +217,26 @@ def write_arch_specific_header(core: arch.CoreDef, start_time: str, output_path:

logger.info("writing architecture specific header")

core.main_reg_file.ty.element_type.size = arch.get_const_or_val(core.main_reg_file.ty.element_type.size)
core.main_reg_file.ty.length = arch.get_const_or_val(core.main_reg_file.ty.length)
if core.float_reg_file is not None:
core.float_reg_file.ty.element_type.size = arch.get_const_or_val(core.float_reg_file.ty.element_type.size)
core.float_reg_file.ty.length = arch.get_const_or_val(core.float_reg_file.ty.length)
if core.vector_reg_file is not None:
core.vector_reg_file.ty.element_type.size = arch.get_const_or_val(core.vector_reg_file.ty.element_type.size)
core.vector_reg_file.ty.length = arch.get_const_or_val(core.vector_reg_file.ty.length)
if core.csr_reg_file is not None:
core.csr_reg_file.ty.element_type.size = arch.get_const_or_val(core.csr_reg_file.ty.element_type.size)
core.csr_reg_file.ty.length = arch.get_const_or_val(core.csr_reg_file.ty.length)

txt = arch_specific_header_template.render(
start_time=start_time,
core_name=core.name,
main_reg=core.main_reg_file,
float_reg=core.float_reg_file,
vector_reg=core.vector_reg_file,
csr_reg=core.csr_reg_file
csr_reg=core.csr_reg_file,
arch=arch
)

with open(output_path / f"{core.name}ArchSpecificImp.h", "w", encoding="utf-8") as f:
Expand Down Expand Up @@ -215,21 +279,21 @@ def write_arch_specific_cpp(core: arch.CoreDef, start_time: str, output_path: pa
error_fn = None

for fn in core.functions.values():
if arch.FunctionAttribute.ETISS_TRAP_ENTRY_FN in fn.attributes:
if attribute_info.FunctionAttribute.ETISS_TRAP_ENTRY_FN in fn.attributes:
error_fn = fn
break

for fn in core.functions.values():
if arch.FunctionAttribute.ETISS_TRAP_TRANSLATE_FN in fn.attributes:
if attribute_info.FunctionAttribute.ETISS_TRAP_TRANSLATE_FN in fn.attributes:
error_fn = fn
break

error_callbacks: "dict[int, str]" = {}

if error_fn is not None:
for bitsize in core.instr_classes:
error_bitfield = arch.BitField("error_code", arch.RangeSpec(31, 0), arch.DataType.U)
error_instr = arch.Instruction(f"trap_entry {bitsize}", {arch.InstrAttribute.NO_CONT: None}, [error_bitfield], "", "", None, None)
error_bitfield = arch.BitField("error_code", arch.RangeSpec(31, 0), type_info.TypeKind.UINT)
error_instr = arch.Instruction(f"trap_entry {bitsize}", {attribute_info.InstrAttribute.NO_CONT: None}, [error_bitfield], "", "", None, None)
error_bitfield_descr = error_instr.fields.get("error_code")
error_op = behav.Operation([
behav.ProcedureCall(error_fn, [behav.NamedReference(error_bitfield_descr)])
Expand All @@ -245,8 +309,8 @@ def write_arch_specific_cpp(core: arch.CoreDef, start_time: str, output_path: pa

global_irq_en_mask = None
if core.global_irq_en_memory is not None:
attr = core.global_irq_en_memory.attributes[arch.MemoryAttribute.ETISS_IS_GLOBAL_IRQ_EN][0]
if not isinstance(attr, behav.IntLiteral):
attr = core.global_irq_en_memory.attributes[attribute_info.MemoryAttribute.ETISS_IS_GLOBAL_IRQ_EN][0]
if not isinstance(attr, behav.Literal):
raise M2TypeError(f"IRQ enable mask of {core.global_irq_en_memory.name} is not compile static")
global_irq_en_mask = attr.value

Expand Down
Loading