From 71242c70ae7fc39c3f1a766ae24fb0c0d336ad4c Mon Sep 17 00:00:00 2001 From: "Jonas K." Date: Thu, 4 Jul 2024 18:48:00 +0200 Subject: [PATCH] fabric_gen: Add clocked GEN_IO and AddRegister to writer Add AddRegister command to VHDL and Verilog writer, which adds a Register. Add clocked feature to GEN_IO, which adds a register to GEN_IO. ``` fabric.csv: GEN_IO,2,OUTPUT,A_C_,CLOCKED,,,,,,,,,,,,, ``` Adds two clocked output GEN_IOs to a tile. Convert GEN_IO docsting to new format. Signed-off-by: Jonas K. --- FABulous/fabric_definition/Gen_IO.py | 31 ++++++++++++------- .../fabric_generator/code_generation_VHDL.py | 16 ++++++++-- .../code_generation_Verilog.py | 11 +++++++ FABulous/fabric_generator/code_generator.py | 20 ++++++++++++ FABulous/fabric_generator/fabric_gen.py | 29 ++++++++++++++--- FABulous/fabric_generator/file_parser.py | 8 +++++ 6 files changed, 97 insertions(+), 18 deletions(-) diff --git a/FABulous/fabric_definition/Gen_IO.py b/FABulous/fabric_definition/Gen_IO.py index 15a6b586..24546434 100644 --- a/FABulous/fabric_definition/Gen_IO.py +++ b/FABulous/fabric_definition/Gen_IO.py @@ -9,17 +9,25 @@ class Gen_IO: The information is parsed from the GEN_IO in the CSV definition file. There are something to be noted. - Attributes: - prefix (str): The prefix of the GEN_IO given in the CSV file. - pins (int): Number of IOs. - IO (IO) : Direction of the IOs, either INPUT or OUTPUT. - configBit (int) : The number of accessible config bits for config access GEN_IO. - params : Additional parameters of GEN_IOs. - - configAccess (bool) : Whether the GEN_IO is config access. - Routes access to config bits, directly to TOP. - This GEN_IOs are not connected to the switchmatrix, - Can only be used as an OUTPUT. - - inverted (bool) : GEN_IO will be inverted. + Attributes + ---------- + prefix : str + The prefix of the GEN_IO given in the CSV file. + pins : int + Number of IOs. + IO : IO + Direction of the IOs, either INPUT or OUTPUT. + configBit : int + The number of accessible config bits for config access GEN_IO. + configAccess (bool) + Whether the GEN_IO is config access. + Routes access to config bits, directly to TOP. + This GEN_IOs are not connected to the switchmatrix, + Can only be used as an OUTPUT. + inverted : bool + GEN_IO will be inverted. + clocked : bool + Adds a register to GEN_IO """ prefix: str @@ -30,3 +38,4 @@ class Gen_IO: # Paramters for GEN_IO: configAccess: bool = False inverted: bool = False + clocked: bool = False diff --git a/FABulous/fabric_generator/code_generation_VHDL.py b/FABulous/fabric_generator/code_generation_VHDL.py index 9c275eb3..deb52958 100644 --- a/FABulous/fabric_generator/code_generation_VHDL.py +++ b/FABulous/fabric_generator/code_generation_VHDL.py @@ -108,8 +108,20 @@ def addLogicStart(self, indentLevel=0): def addLogicEnd(self, indentLevel=0): self._add("\n" f"end" "\n", indentLevel) + def addRegister(self, reg, regIn, clk="CLK", inverted=False, indentLevel=0): + inv = "not " if inverted else "" + template = f""" +process({clk}) +begin + if {clk}'event and {clk}='1' then + {reg} <= {inv}{regIn}; + end if; +end process; +""" + self._add(template, indentLevel) + def addAssignScalar(self, left, right, delay=0, indentLevel=0, inverted=False): - inv = "not" if inverted else "" + inv = "not " if inverted else "" if type(right) == list: self._add( f"{left} <= {inv}{' & '.join(right)} after {delay} ps;", indentLevel @@ -126,7 +138,7 @@ def addAssignScalar(self, left, right, delay=0, indentLevel=0, inverted=False): def addAssignVector( self, left, right, widthL, widthR, indentLevel=0, inverted=False ): - inv = "not" if inverted else "" + inv = "not " if inverted else "" self._add(f"{left} <= {inv}{right}( {widthL} downto {widthR} );", indentLevel) def addInstantiation( diff --git a/FABulous/fabric_generator/code_generation_Verilog.py b/FABulous/fabric_generator/code_generation_Verilog.py index e91e35d5..1e3fe414 100644 --- a/FABulous/fabric_generator/code_generation_Verilog.py +++ b/FABulous/fabric_generator/code_generation_Verilog.py @@ -189,6 +189,17 @@ def addFlipFlopChain(self, configBits, indentLevel=0): ); end assign CONFout = ConfigBits[{cfgBit}-1]; +""" + self._add(template, indentLevel) + + def addRegister(self, reg, regIn, clk="CLK", inverted=False, indentLevel=0): + inv = "~" if inverted else "" + template = f""" +reg {reg}; +always @ (posedge {clk}) +begin + {reg} <= {inv}{regIn}; +end """ self._add(template, indentLevel) diff --git a/FABulous/fabric_generator/code_generator.py b/FABulous/fabric_generator/code_generator.py index 6ba38a3e..1a6337e4 100644 --- a/FABulous/fabric_generator/code_generator.py +++ b/FABulous/fabric_generator/code_generator.py @@ -512,6 +512,26 @@ def addFlipFlopChain(self, configBits: int, indentLevel=0): """ pass + @abc.abstractmethod + def addRegister(self, reg, regIn, clk="CLK", inverted=False, indentLevel=0): + """ + Add a register. + + Parameters + ---------- + reg : str + The name of the register. + regIn : str + The input signal of the register. + clk : str, optional + The clock signal of the register. Defaults to "CLK". + inverted : bool, optional + Invert the input signal. Defaults to False. + indentLevel : int, optional + The level of indentation. Defaults to 0. + """ + pass + @abc.abstractmethod def addAssignScalar(self, left, right, delay=0, indentLevel=0, inverted=False): """ diff --git a/FABulous/fabric_generator/fabric_gen.py b/FABulous/fabric_generator/fabric_gen.py index dc826e6a..ab9dbc07 100644 --- a/FABulous/fabric_generator/fabric_gen.py +++ b/FABulous/fabric_generator/fabric_gen.py @@ -513,8 +513,6 @@ def genTileSwitchMatrix(self, tile: Tile) -> None: self.writer.addPortScalar( f"{gio.prefix}{j}", IO.INPUT, indentLevel=2 ) - # if gio.inverted: - # self.writer.addPortScalar(f"{gio.prefix}{j}_N", IO.INPUT, indentLevel=2) # jump wire input for i in tile.portsInfo: @@ -1235,12 +1233,14 @@ def generateTile(self, tile: Tile) -> None: "gen_io config bit access not implemented for ConfigBitMode.FLIPFLOP_CHAIN" ) - # gen_io wire assignments + # gen_io assignments if tile.gen_ios: self.writer.addNewLine() - self.writer.addComment("gen_io wire assignments", onNewLine=True) + self.writer.addComment( + "gen_io wire and register assignments", onNewLine=True + ) for gio in tile.gen_ios: - if not gio.configAccess: + if not gio.configAccess and not gio.clocked: for j in range(gio.pins): if gio.IO == IO.INPUT: self.writer.addAssignScalar( @@ -1254,6 +1254,21 @@ def generateTile(self, tile: Tile) -> None: f"{gio.prefix}{j}_top", inverted=gio.inverted, ) + elif gio.clocked: + for j in range(gio.pins): + if gio.IO == IO.INPUT: + self.writer.addRegister( + f"{gio.prefix}{j}_top", + f"{gio.prefix}{j}", + inverted=gio.inverted, + ) + elif gio.IO == IO.OUTPUT: + self.writer.addRegister( + f"{gio.prefix}{j}", + f"{gio.prefix}{j}_top", + inverted=gio.inverted, + ) + if tile.gen_ios: self.writer.addNewLine() @@ -2278,6 +2293,10 @@ def split_port(p): assert basename[0] in "ABCDEFGH" indices.append(-(ord(basename[0]) - ord("A"))) basename = basename[2:] + # GEN_IO top level ports basename ends with __top, after the port indices + # are extractected, so we fix this here as it just looks odd. :) + if basename.endswith("__top"): + basename = basename.replace("__top", "_top") # Y is in reverse order return ((-y, x), tuple(indices), basename) diff --git a/FABulous/fabric_generator/file_parser.py b/FABulous/fabric_generator/file_parser.py index 2d30186a..dd941ffb 100644 --- a/FABulous/fabric_generator/file_parser.py +++ b/FABulous/fabric_generator/file_parser.py @@ -509,6 +509,7 @@ def parseTiles(fileName: Path) -> tuple[list[Tile], list[tuple[str, str]]]: configBit = 0 configAccess = False inverted = False + clocked = False # Additional params can be added for param in temp[4:]: param = param.strip() @@ -523,10 +524,16 @@ def parseTiles(fileName: Path) -> tuple[list[Tile], list[tuple[str, str]]]: configBit = int(temp[1]) elif param == "INVERTED": inverted = True + elif param == "CLOCKED": + clocked = True elif param is None or param == "": continue else: raise ValueError(f"Unknown parameter {param} in GEN_IO") + + if configAccess and clocked: + raise ValueError("CONFIGACCESS GEN_IO can not be clocked") + gen_ios.append( Gen_IO( temp[3], @@ -535,6 +542,7 @@ def parseTiles(fileName: Path) -> tuple[list[Tile], list[tuple[str, str]]]: configBit, configAccess, inverted, + clocked, ) ) elif temp[0] == "MATRIX":