diff --git a/b_asic/codegen/vhdl/__init__.py b/b_asic/codegen/vhdl/__init__.py index 0b584689166818be9eec98d65deac9b5f2b898c2..2fd8e4240a823a8848d3ef5abebb18b366d452c4 100644 --- a/b_asic/codegen/vhdl/__init__.py +++ b/b_asic/codegen/vhdl/__init__.py @@ -9,7 +9,7 @@ VHDL_TAB = r" " def write( - f: TextIO, + file: TextIO, indent_level: int, text: str, *, @@ -20,12 +20,12 @@ def write( Base VHDL code generation utility. ``f'{VHDL_TAB*indent_level}'`` is first written to the TextIO - object *f*. Immediately after the indentation, *text* is written to *f*. Finally, - *text* is also written to *f*. + object *file*. Immediately after the indentation, *text* is written to *file*. Finally, + *text* is also written to *file*. Parameters ---------- - f : TextIO + file : TextIO The file object to emit VHDL code to. indent_level : int Indentation level to use. Exactly ``f'{VHDL_TAB*indent_level}'`` is written @@ -33,36 +33,36 @@ def write( text : str The text to write to. end : str, default: '\n' - Text to write exactly after *text* is written to *f*. + Text to write exactly after *text* is written to *file*. start : str, optional Text to write before both indentation and *text*. """ if start is not None: - f.write(start) - f.write(f"{VHDL_TAB * indent_level}{text}{end}") + file.write(start) + file.write(f"{VHDL_TAB * indent_level}{text}{end}") -def write_lines(f: TextIO, lines: list[tuple[int, str] | tuple[int, str, str]]): +def write_lines(file: TextIO, lines: list[tuple[int, str] | tuple[int, str, str]]): """ Multiline VHDL code generation utility. Each tuple ``(int, str, [int])`` in the list *lines* is written to the - TextIO object *f* using the :function:`vhdl.write` function. + TextIO object *file* using the :func:`vhdl.write` function. Parameters ---------- - f : TextIO + file : TextIO The file object to emit VHDL code to. lines : list of tuple (int,str) [1], or list of tuple (int,str,str) [2] [1]: The first ``int`` of the tuple is used as indentation level for the line and the second ``str`` of the tuple is the content of the line. [2]: Same as [1], but the third ``str`` of the tuple is passed to parameter - *end* when calling :function:`vhdl.write`. + *end* when calling :func:`vhdl.write`. """ for tpl in lines: if len(tpl) == 2: - write(f, indent_level=tpl[0], text=str(tpl[1])) + write(file, indent_level=tpl[0], text=str(tpl[1])) elif len(tpl) == 3: - write(f, indent_level=tpl[0], text=str(tpl[1]), end=str(tpl[2])) + write(file, indent_level=tpl[0], text=str(tpl[1]), end=str(tpl[2])) else: raise ValueError("All tuples in list `lines` must have length 2 or 3") diff --git a/b_asic/codegen/vhdl/architecture.py b/b_asic/codegen/vhdl/architecture.py index fb548d41e1fd301aca3032faa7e9cb1497b9cc3c..d6ad90250e57f61ee501a507e960bce99b9bf273 100644 --- a/b_asic/codegen/vhdl/architecture.py +++ b/b_asic/codegen/vhdl/architecture.py @@ -3,7 +3,7 @@ Module for code generation of VHDL architectures. """ from math import ceil, log2 -from typing import TYPE_CHECKING, TextIO, cast +from typing import TYPE_CHECKING, Literal, TextIO, cast from b_asic.codegen.vhdl import common, write, write_lines from b_asic.process import MemoryVariable @@ -24,6 +24,12 @@ def memory_based_storage( input_sync: bool = True, adr_mux_size: int = 1, adr_pipe_depth: int = 0, + vivado_ram_style: ( + Literal["block", "distributed", "registers", "ultra", "mixed", "auto"] | None + ) = None, + quartus_ram_style: ( + Literal["M4K", "M9K", "M10K", "M20K", "M144K", "MLAB", "logic"] | None + ) = None, ): """ Generate the VHDL architecture for a memory-based storage architecture. @@ -62,6 +68,12 @@ def memory_based_storage( adr_pipe_depth : int, default: 0 Depth of address generation pipelining. Set to 0 for no multiplexer pipelining. If any other value than 0, `input_sync` must be set. + vivado_ram_style : str, optional + An optional Xilinx Vivado RAM style attribute to apply to this memory. + If set, exactly one of: "block", "distributed", "registers", "ultra", "mixed" or "auto". + quartus_ram_style : str, optional + An optional Quartus Prime RAM style attribute to apply to this memory. + If set, exactly one of: "M4K", "M9K", "M10K", "M20K", "M144K", "MLAB" or "logic". """ # Code settings @@ -92,13 +104,24 @@ def memory_based_storage( common.type_declaration( f, "mem_type", "array(0 to MEM_DEPTH-1) of std_logic_vector(MEM_WL-1 downto 0)" ) - common.signal_declaration( - f, - name="memory", - signal_type="mem_type", - name_pad=18, - vivado_ram_style="distributed", # Xilinx Vivado distributed RAM - ) + if vivado_ram_style is not None: + common.signal_declaration( + f, + name="memory", + signal_type="mem_type", + name_pad=18, + vivado_ram_style=vivado_ram_style, + ) + elif quartus_ram_style is not None: + common.signal_declaration( + f, + name="memory", + signal_type="mem_type", + name_pad=18, + quartus_ram_style=quartus_ram_style, + ) + else: + common.signal_declaration(f, name="memory", signal_type="mem_type", name_pad=18) # Schedule time counter write(f, 1, "-- Schedule counter", start="\n") diff --git a/b_asic/codegen/vhdl/common.py b/b_asic/codegen/vhdl/common.py index ec0849ad9d2e546e26bfe91c55cfadb5fc1d9fa3..630dc6ac7e8512286efc04e981e591c172becba2 100644 --- a/b_asic/codegen/vhdl/common.py +++ b/b_asic/codegen/vhdl/common.py @@ -5,7 +5,7 @@ Generation of common VHDL constructs import re from datetime import datetime from subprocess import PIPE, Popen -from typing import Any, TextIO +from typing import Any, Literal, TextIO from b_asic.codegen.vhdl import write, write_lines @@ -78,8 +78,12 @@ def signal_declaration( signal_type: str, default_value: str | None = None, name_pad: int | None = None, - vivado_ram_style: str | None = None, - quartus_ram_style: str | None = None, + vivado_ram_style: ( + Literal["block", "distributed", "registers", "ultra", "mixed", "auto"] | None + ) = None, + quartus_ram_style: ( + Literal["M4K", "M9K", "M10K", "M20K", "M144K", "MLAB", "logic"] | None + ) = None, ): """ Create a VHDL signal declaration.