From 587bf09b0f9a0c6708b8843658a573a6e0a410d8 Mon Sep 17 00:00:00 2001 From: bilal458 Date: Wed, 10 Jul 2024 16:44:56 +0500 Subject: [PATCH 1/5] Added Support for device.xml parsing and extracting BRAMs and DSPS --- .../dsp_generator/v1_0/dsp_generator_gen.py | 7 ++++- .../fifo_generator/v1_0/fifo_generator_gen.py | 3 ++ .../fir_generator/v1_0/fir_generator_gen.py | 5 +++- .../on_chip_memory/v1_0/on_chip_memory_gen.py | 2 ++ rapidsilicon/lib/common.py | 30 +++++++++++++++++++ 5 files changed, 45 insertions(+), 2 deletions(-) diff --git a/rapidsilicon/ip/dsp_generator/v1_0/dsp_generator_gen.py b/rapidsilicon/ip/dsp_generator/v1_0/dsp_generator_gen.py index d2a9d9b2..84f133ac 100755 --- a/rapidsilicon/ip/dsp_generator/v1_0/dsp_generator_gen.py +++ b/rapidsilicon/ip/dsp_generator/v1_0/dsp_generator_gen.py @@ -268,7 +268,12 @@ def main(): file_path = os.path.dirname(os.path.realpath(__file__)) rs_builder.copy_images(file_path) - + + + #device_dict contains the number of BRAMs and DSP for the device used. + device_dic = rs_builder.parse_device(args.device_path,args.device) + + summary = { "Multiplier" : args.equation } diff --git a/rapidsilicon/ip/fifo_generator/v1_0/fifo_generator_gen.py b/rapidsilicon/ip/fifo_generator/v1_0/fifo_generator_gen.py index 7683d96e..37b07e67 100755 --- a/rapidsilicon/ip/fifo_generator/v1_0/fifo_generator_gen.py +++ b/rapidsilicon/ip/fifo_generator/v1_0/fifo_generator_gen.py @@ -376,6 +376,9 @@ def main(): args = rs_builder.import_args_from_json(parser=parser, json_filename=args.json) + + #device_dict contains the number of BRAMs and DSP for the device used. + device_dic = rs_builder.parse_device(args.device_path,args.device) if (args.builtin_fifo == False and args.synchronous == False): depth = args.DEPTH else: diff --git a/rapidsilicon/ip/fir_generator/v1_0/fir_generator_gen.py b/rapidsilicon/ip/fir_generator/v1_0/fir_generator_gen.py index dd91277b..8d6e65d8 100755 --- a/rapidsilicon/ip/fir_generator/v1_0/fir_generator_gen.py +++ b/rapidsilicon/ip/fir_generator/v1_0/fir_generator_gen.py @@ -203,7 +203,10 @@ def main(): else: abs_sum = sum(abs(coeff) for coeff in extract_numbers(coefficients, args.coefficients_file)) bit_growth = math.ceil(math.log2(abs_sum)) - + + #device_dict contains the number of BRAMs and DSP for the device used. + device_dic = rs_builder.parse_device(args.device_path,args.device) + summary = {} if (args.coefficients_file): if (args.optimization == "Area"): diff --git a/rapidsilicon/ip/on_chip_memory/v1_0/on_chip_memory_gen.py b/rapidsilicon/ip/on_chip_memory/v1_0/on_chip_memory_gen.py index b2efad31..70318330 100755 --- a/rapidsilicon/ip/on_chip_memory/v1_0/on_chip_memory_gen.py +++ b/rapidsilicon/ip/on_chip_memory/v1_0/on_chip_memory_gen.py @@ -285,6 +285,8 @@ def main(): elif (args.memory_type in ["True_Dual_Port"]): if (args.write_width_A != args.read_width_A or args.write_width_A != args.write_width_B or args.write_width_B != args.read_width_B): parser._actions[3].choices = ["Block_RAM"] + #device_dict contains the number of BRAMs and DSP for the device used. + device_dic = rs_builder.parse_device(args.device_path,args.device) # Create Wrapper ------------------------------------------------------------------------------- platform = OSFPGAPlatform(io=[], toolchain="raptor", device="gemini") diff --git a/rapidsilicon/lib/common.py b/rapidsilicon/lib/common.py index 7a6e40bb..198fdd4f 100644 --- a/rapidsilicon/lib/common.py +++ b/rapidsilicon/lib/common.py @@ -8,6 +8,7 @@ import json import shutil import argparse +import xml.etree.ElementTree as ET # IP Catalog Builder ------------------------------------------------------------------------------- @@ -373,3 +374,32 @@ def generate_wrapper(self, platform, module, version): # Remove build files. shutil.rmtree(build_path) + +#Function to parse device.xml for BRAMs and DSPs + def parse_device(self, device_file, device): + + # Read the XML data from the file + with open(device_file, 'r') as file: + xml_data = file.read() + + + # Parse the XML data + root = ET.fromstring(xml_data) + + # Initialize variables to store the fnum values + fnum_bram = None + fnum_dsp = None + device_dict = {} + + for dummy in root: + if dummy.attrib.get('name') == device: +# print("Device name = " , device ," ---------- found") + for sub_dummy in dummy: + if sub_dummy.attrib.get('type') == 'bram': + fnum_bram = sub_dummy.attrib.get('num') + device_dict[sub_dummy.attrib.get('type')] = (fnum_bram) + elif sub_dummy.attrib.get('type') == 'dsp': + fnum_dsp = sub_dummy.attrib.get('num') + device_dict[sub_dummy.attrib.get('type')] = (fnum_dsp) + + return device_dict \ No newline at end of file From 8435900b7b82af5dc321cd077d750c2affff3cff Mon Sep 17 00:00:00 2001 From: Sarmad-Salman Date: Thu, 18 Jul 2024 17:40:47 +0500 Subject: [PATCH 2/5] added support to change range depending on selected device --- .../dsp_generator/v1_0/dsp_generator_gen.py | 346 +++++++++++------- .../fifo_generator/v1_0/fifo_generator_gen.py | 312 ++++++++-------- .../fir_generator/v1_0/fir_generator_gen.py | 211 ++++++----- rapidsilicon/lib/common.py | 4 +- 4 files changed, 489 insertions(+), 384 deletions(-) diff --git a/rapidsilicon/ip/dsp_generator/v1_0/dsp_generator_gen.py b/rapidsilicon/ip/dsp_generator/v1_0/dsp_generator_gen.py index 84f133ac..1aa8fc52 100755 --- a/rapidsilicon/ip/dsp_generator/v1_0/dsp_generator_gen.py +++ b/rapidsilicon/ip/dsp_generator/v1_0/dsp_generator_gen.py @@ -210,150 +210,225 @@ def main(): 'Interface' : 'Native', 'Description' : 'DSP Generator IP is a versatile solution that tailors DSP IPs based on specified parameters. It offers pre-built functions, optimizing performance by allowing the configuration of different multiplicative algorithms suited for custom requirements.'} } + + device_dic = { + 'dsp' : 56, + 'bram' : 56 + } + # Import JSON (Optional) ----------------------------------------------------------------------- if args.json: args = rs_builder.import_args_from_json(parser=parser, json_filename=args.json) rs_builder.import_ip_details_json(build_dir=args.build_dir ,details=details , build_name = args.build_name, version = "v1_0") - if (args.equation == "AxB"): - dep_dict.update({ - 'c_width' : 'True', - 'd_width' : 'True', - 'e_width' : 'True', - 'f_width' : 'True', - 'g_width' : 'True', - 'h_width' : 'True' - }) - parser._actions[2].choices = ["Base", "Enhanced", "Pipeline"] - if (args.feature == "Base") or (args.feature == "Pipeline" and args.unsigned == True): - if(args.feature == "Pipeline"): - parser._actions[11].default = True - dep_dict.update({ - 'reg_in' : 'True' - }) - parser._actions[3].choices = range(1, 73) - parser._actions[4].choices = range(1, 73) - elif (args.feature == "Pipeline" and args.unsigned == False) or (args.feature == "Enhanced" and args.unsigned == True): - if(args.feature == "Pipeline"): - parser._actions[11].default = True - dep_dict.update({ - 'reg_in' : 'True' - }) - if (args.a_width > 68): - parser._actions[3].default = 68 - if (args.b_width > 68): - parser._actions[4].default = 68 - parser._actions[3].choices = range(1, 69) - parser._actions[4].choices = range(1, 69) - elif (args.feature == "Enhanced" and args.unsigned == False): - if (args.a_width > 64): - parser._actions[3].default = 64 - if (args.b_width > 64): - parser._actions[4].default = 64 - parser._actions[3].choices = range(1, 65) - parser._actions[4].choices = range(1, 65) - else: - parser._actions[2].choices = ["Base"] - parser._actions[3].choices = range(1, 21) - parser._actions[4].choices = range(1, 19) - if (args.equation == "AxB+CxD"): + #device_dict contains the number of BRAMs and DSP for the device used. + device_dic = rs_builder.parse_device(args.device_path,args.device) + + if (device_dic['dsp'] > 0): + if (args.equation == "AxB"): dep_dict.update({ + 'c_width' : 'True', + 'd_width' : 'True', 'e_width' : 'True', 'f_width' : 'True', 'g_width' : 'True', 'h_width' : 'True' }) + parser._actions[2].choices = ["Base", "Enhanced", "Pipeline"] + if (args.feature == "Base") or (args.feature == "Pipeline" and args.unsigned == True): + if(args.feature == "Pipeline"): + parser._actions[11].default = True + dep_dict.update({ + 'reg_in' : 'True' + }) + if (args.feature == "Base"): + if (device_dic['dsp'] >= 16): + parser._actions[3].choices = range(1, 73) + parser._actions[4].choices = range(1, 73) + elif (device_dic['dsp'] >= 9): + parser._actions[3].choices = range(1, 55) + parser._actions[4].choices = range(1, 55) + elif (device_dic['dsp'] >= 4): + parser._actions[3].choices = range(1, 37) + parser._actions[4].choices = range(1, 37) + else: + parser._actions[3].choices = range(1, 21) + parser._actions[4].choices = range(1, 19) + else: + if (device_dic['dsp'] >= 7): + parser._actions[3].choices = range(1, 73) + parser._actions[4].choices = range(1, 73) + elif (device_dic['dsp'] >= 5): + parser._actions[3].choices = range(1, 55) + parser._actions[4].choices = range(1, 55) + elif (device_dic['dsp'] >= 3): + parser._actions[3].choices = range(1, 37) + parser._actions[4].choices = range(1, 37) + else: + parser._actions[3].choices = range(1, 21) + parser._actions[4].choices = range(1, 19) + + elif (args.feature == "Pipeline" and args.unsigned == False) or (args.feature == "Enhanced" and args.unsigned == True): + if(args.feature == "Pipeline"): + parser._actions[11].default = True + dep_dict.update({ + 'reg_in' : 'True' + }) + if (args.a_width > 68): + parser._actions[3].default = 68 + if (args.b_width > 68): + parser._actions[4].default = 68 + + if (args.feature == "Pipeline"): + if (device_dic['dsp'] >= 7): + parser._actions[3].choices = range(1, 69) + parser._actions[4].choices = range(1, 69) + elif (device_dic['dsp'] >= 5): + parser._actions[3].choices = range(1, 52) + parser._actions[4].choices = range(1, 52) + elif (device_dic['dsp'] >= 3): + parser._actions[3].choices = range(1, 35) + parser._actions[4].choices = range(1, 35) + else: + parser._actions[3].choices = range(1, 21) + parser._actions[4].choices = range(1, 19) + else: + if (device_dic['dsp'] >= 10): + parser._actions[3].choices = range(1, 69) + parser._actions[4].choices = range(1, 69) + elif (device_dic['dsp'] >= 6): + parser._actions[3].choices = range(1, 52) + parser._actions[4].choices = range(1, 52) + elif (device_dic['dsp'] >= 3): + parser._actions[3].choices = range(1, 35) + parser._actions[4].choices = range(1, 35) + else: + parser._actions[3].choices = range(1, 21) + parser._actions[4].choices = range(1, 19) + + elif (args.feature == "Enhanced" and args.unsigned == False): + if (args.a_width > 64): + parser._actions[3].default = 64 + if (args.b_width > 64): + parser._actions[4].default = 64 + if (device_dic['dsp'] >= 10): + parser._actions[3].choices = range(1, 65) + parser._actions[4].choices = range(1, 65) + elif (device_dic['dsp'] >= 6): + parser._actions[3].choices = range(1, 49) + parser._actions[4].choices = range(1, 49) + elif (device_dic['dsp'] >= 3): + parser._actions[3].choices = range(1, 33) + parser._actions[4].choices = range(1, 33) + else: + parser._actions[3].choices = range(1, 21) + parser._actions[4].choices = range(1, 19) + + else: + parser._actions[2].choices = ["Base"] + if (device_dic['dsp'] >= 1): + parser._actions[3].choices = range(1, 21) + parser._actions[4].choices = range(1, 19) + if (args.equation == "AxB+CxD"): + dep_dict.update({ + 'e_width' : 'True', + 'f_width' : 'True', + 'g_width' : 'True', + 'h_width' : 'True' + }) + else: + parser._actions = [action for action in parser._actions if not action.option_strings] args = rs_builder.import_args_from_json(parser=parser, json_filename=args.json) file_path = os.path.dirname(os.path.realpath(__file__)) rs_builder.copy_images(file_path) - - #device_dict contains the number of BRAMs and DSP for the device used. - device_dic = rs_builder.parse_device(args.device_path,args.device) - - - summary = { - "Multiplier" : args.equation - } - if(args.feature == "Base"): - summary["Algorithm"] = "Karatsuba Algorithm" - summary["Latency (clock cycles)"] = "1" - if(args.equation == "AxB"): - if ((args.a_width > 54 and args.a_width <=72) or (args.b_width > 54 and args.b_width <=72)): - summary["Count of DSPs"] = "16" - elif ((args.a_width > 36 and args.a_width <=54) or (args.b_width > 36 and args.b_width <=54)): - summary["Count of DSPs"] = "9" - elif ((args.a_width > 20 and args.a_width <=36) or (args.b_width > 18 and args.b_width <=36)): + if (device_dic['dsp'] > 0): + summary = { + "Multiplier" : args.equation + } + if(args.feature == "Base"): + summary["Algorithm"] = "Karatsuba Algorithm" + summary["Latency (clock cycles)"] = "1" + if(args.equation == "AxB"): + if ((args.a_width > 54 and args.a_width <=72) or (args.b_width > 54 and args.b_width <=72)): + summary["Count of DSPs"] = "16" + elif ((args.a_width > 36 and args.a_width <=54) or (args.b_width > 36 and args.b_width <=54)): + summary["Count of DSPs"] = "9" + elif ((args.a_width > 20 and args.a_width <=36) or (args.b_width > 18 and args.b_width <=36)): + summary["Count of DSPs"] = "4" + else: + summary["Count of DSPs"] = "1" + elif (args.equation == "AxB+CxD"): + summary["Count of DSPs"] = "2" + else: summary["Count of DSPs"] = "4" + elif (args.feature == "Enhanced"): + summary["Algorithm"] = "Karatsuba-Offman Algorithm" + summary["Latency (clock cycles)"] = "1" + if(args.unsigned): + if ((args.a_width > 51 and args.a_width <=68) or (args.b_width > 51 and args.b_width <=68)): + summary["Count of DSPs"] = "10" + elif ((args.a_width > 34 and args.a_width <=51) or (args.b_width > 34 and args.b_width <=51)): + summary["Count of DSPs"] = "6" + elif ((args.a_width > 20 and args.a_width <=34) or (args.b_width > 18 and args.b_width <=34)): + summary["Count of DSPs"] = "3" + else: + summary["Count of DSPs"] = "1" else: - summary["Count of DSPs"] = "1" - elif (args.equation == "AxB+CxD"): - summary["Count of DSPs"] = "2" + if ((args.a_width > 48 and args.a_width <=64) or (args.b_width > 48 and args.b_width <=64)): + summary["Count of DSPs"] = "10" + elif ((args.a_width > 32 and args.a_width <=48) or (args.b_width > 32 and args.b_width <=48)): + summary["Count of DSPs"] = "6" + elif ((args.a_width > 20 and args.a_width <=32) or (args.b_width > 18 and args.b_width <=32)): + summary["Count of DSPs"] = "3" + else: + summary["Count of DSPs"] = "1" else: - summary["Count of DSPs"] = "4" - elif (args.feature == "Enhanced"): - summary["Algorithm"] = "Karatsuba-Offman Algorithm" - summary["Latency (clock cycles)"] = "1" - if(args.unsigned): - if ((args.a_width > 51 and args.a_width <=68) or (args.b_width > 51 and args.b_width <=68)): - summary["Count of DSPs"] = "10" - elif ((args.a_width > 34 and args.a_width <=51) or (args.b_width > 34 and args.b_width <=51)): - summary["Count of DSPs"] = "6" - elif ((args.a_width > 20 and args.a_width <=34) or (args.b_width > 18 and args.b_width <=34)): - summary["Count of DSPs"] = "3" + summary["Algorithm"] = "Pipelined Algorithm" + if(args.unsigned): + if ((args.a_width > 54 and args.a_width <=72) or (args.b_width > 54 and args.b_width <=72)): + summary["Count of DSPs"] = "7" + summary["Latency (clock cycles)"] = "4" + elif ((args.a_width > 36 and args.a_width <=54) or (args.b_width > 36 and args.b_width <=54)): + summary["Count of DSPs"] = "5" + summary["Latency (clock cycles)"] = "3" + elif ((args.a_width > 20 and args.a_width <=36) or (args.b_width > 18 and args.b_width <=36)): + summary["Count of DSPs"] = "3" + summary["Latency (clock cycles)"] = "2" + else: + summary["Count of DSPs"] = "1" + summary["Latency (clock cycles)"] = "1" else: - summary["Count of DSPs"] = "1" + if ((args.a_width > 51 and args.a_width <=68) or (args.b_width > 51 and args.b_width <=68)): + summary["Count of DSPs"] = "7" + summary["Latency (clock cycles)"] = "4" + elif ((args.a_width > 34 and args.a_width <=51) or (args.b_width > 34 and args.b_width <=51)): + summary["Count of DSPs"] = "5" + summary["Latency (clock cycles)"] = "3" + elif ((args.a_width > 20 and args.a_width <=34) or (args.b_width > 18 and args.b_width <=34)): + summary["Count of DSPs"] = "3" + summary["Latency (clock cycles)"] = "2" + else: + summary["Count of DSPs"] = "1" + summary["Latency (clock cycles)"] = "1" + if (args.unsigned and not args.reg_in): + summary["Input"] = "Unregistered and Unsigned" + elif (args.unsigned and args.reg_in): + summary["Input"] = "Registered and Unsigned" + elif (not args.unsigned and args.reg_in): + summary["Input"] = "Registered and Signed" else: - if ((args.a_width > 48 and args.a_width <=64) or (args.b_width > 48 and args.b_width <=64)): - summary["Count of DSPs"] = "10" - elif ((args.a_width > 32 and args.a_width <=48) or (args.b_width > 32 and args.b_width <=48)): - summary["Count of DSPs"] = "6" - elif ((args.a_width > 20 and args.a_width <=32) or (args.b_width > 18 and args.b_width <=32)): - summary["Count of DSPs"] = "3" - else: - summary["Count of DSPs"] = "1" - else: - summary["Algorithm"] = "Pipelined Algorithm" - if(args.unsigned): - if ((args.a_width > 54 and args.a_width <=72) or (args.b_width > 54 and args.b_width <=72)): - summary["Count of DSPs"] = "7" - summary["Latency (clock cycles)"] = "4" - elif ((args.a_width > 36 and args.a_width <=54) or (args.b_width > 36 and args.b_width <=54)): - summary["Count of DSPs"] = "5" - summary["Latency (clock cycles)"] = "3" - elif ((args.a_width > 20 and args.a_width <=36) or (args.b_width > 18 and args.b_width <=36)): - summary["Count of DSPs"] = "3" - summary["Latency (clock cycles)"] = "2" - else: - summary["Count of DSPs"] = "1" - summary["Latency (clock cycles)"] = "1" + summary["Input"] = "Unregistered and Signed" + if (args.reg_out): + summary["Output"] = "Registered Output" else: - if ((args.a_width > 51 and args.a_width <=68) or (args.b_width > 51 and args.b_width <=68)): - summary["Count of DSPs"] = "7" - summary["Latency (clock cycles)"] = "4" - elif ((args.a_width > 34 and args.a_width <=51) or (args.b_width > 34 and args.b_width <=51)): - summary["Count of DSPs"] = "5" - summary["Latency (clock cycles)"] = "3" - elif ((args.a_width > 20 and args.a_width <=34) or (args.b_width > 18 and args.b_width <=34)): - summary["Count of DSPs"] = "3" - summary["Latency (clock cycles)"] = "2" - else: - summary["Count of DSPs"] = "1" - summary["Latency (clock cycles)"] = "1" - if (args.unsigned and not args.reg_in): - summary["Input"] = "Unregistered and Unsigned" - elif (args.unsigned and args.reg_in): - summary["Input"] = "Registered and Unsigned" - elif (not args.unsigned and args.reg_in): - summary["Input"] = "Registered and Signed" - else: - summary["Input"] = "Unregistered and Signed" - if (args.reg_out): - summary["Output"] = "Registered Output" + summary["Output"] = "Unregistered Output" else: - summary["Output"] = "Unregistered Output" + summary = { + "WARNING" : "No DSPs in selected device. Select a different device with DSPs." + } # Export JSON Template (Optional) -------------------------------------------------------------- if args.json_template: @@ -362,21 +437,22 @@ def main(): # Create Wrapper ------------------------------------------------------------------------------- platform = OSFPGAPlatform(io=[], toolchain="raptor", device="gemini") - module = RS_DSP_Wrapper(platform, - a_width = args.a_width, - b_width = args.b_width, - c_width = args.c_width, - d_width = args.d_width, - e_width = args.e_width, - f_width = args.f_width, - g_width = args.g_width, - h_width = args.h_width, - feature = args.feature, - reg_in = args.reg_in, - reg_out = args.reg_out, - unsigned = args.unsigned, - equation = args.equation - ) + if (device_dic['dsp'] > 0): + module = RS_DSP_Wrapper(platform, + a_width = args.a_width, + b_width = args.b_width, + c_width = args.c_width, + d_width = args.d_width, + e_width = args.e_width, + f_width = args.f_width, + g_width = args.g_width, + h_width = args.h_width, + feature = args.feature, + reg_in = args.reg_in, + reg_out = args.reg_out, + unsigned = args.unsigned, + equation = args.equation + ) # Build Project -------------------------------------------------------------------------------- if args.build: diff --git a/rapidsilicon/ip/fifo_generator/v1_0/fifo_generator_gen.py b/rapidsilicon/ip/fifo_generator/v1_0/fifo_generator_gen.py index 37b07e67..72fd3926 100755 --- a/rapidsilicon/ip/fifo_generator/v1_0/fifo_generator_gen.py +++ b/rapidsilicon/ip/fifo_generator/v1_0/fifo_generator_gen.py @@ -227,14 +227,31 @@ def main(): args = parser.parse_args() + details = { "IP details": { + 'Name' : 'FIFO Generator', + 'Version' : 'V1_0', + 'Interface' : 'Native', + 'Description' : 'FIFO Generator IP is a versatile solution that tailors FIFO IPs based on specified parameters. It optimizes data flow, synchronizes components with different data rates, and adapts to various design requirements, offering efficient and customizable data management.'} + } + if (args.builtin_fifo == False and args.synchronous == False): depth = args.DEPTH else: depth = args.depth + + device_dic = { + 'dsp' : 56, + 'bram' : 56 + } # Import JSON (Optional) ----------------------------------------------------------------------- if args.json: args = rs_builder.import_args_from_json(parser=parser, json_filename=args.json) + rs_builder.import_ip_details_json(build_dir=args.build_dir ,details=details , build_name = args.build_name, version = "v1_0") + + #device_dict contains the number of BRAMs and DSP for the device used. + device_dic = rs_builder.parse_device(args.device_path,args.device) + if (args.asymmetric): data_width_read = args.data_width_read data_width_write = args.data_width_write @@ -247,7 +264,7 @@ def main(): num_9K = 0 num_18K = 0 total_mem = 0 - while total_BRAM(data_width_write, remaining_memory/data_width_write) < 128: + while total_BRAM(data_width_write, remaining_memory/data_width_write) < device_dic['bram']: for i, bus in enumerate(buses_write): if (len(bus) <= 9): memory = 1024 @@ -272,181 +289,174 @@ def main(): else: prev_rem = prev_rem - details = { "IP details": { - 'Name' : 'FIFO Generator', - 'Version' : 'V1_0', - 'Interface' : 'Native', - 'Description' : 'FIFO Generator IP is a versatile solution that tailors FIFO IPs based on specified parameters. It optimizes data flow, synchronizes components with different data rates, and adapts to various design requirements, offering efficient and customizable data management.'} - } - - # Import JSON (Optional) ----------------------------------------------------------------------- - if args.json: - args = rs_builder.import_args_from_json(parser=parser, json_filename=args.json) - rs_builder.import_ip_details_json(build_dir=args.build_dir ,details=details , build_name = args.build_name, version = "v1_0") file_path = os.path.dirname(os.path.realpath(__file__)) rs_builder.copy_images(file_path) - - if (args.full_threshold == False): - dep_dict.update({ - 'full_value' : 'True' - }) - if (args.empty_threshold == False): - dep_dict.update({ - 'empty_value' : 'True' - }) - if (args.builtin_fifo == False): - dep_dict.update({ - 'asymmetric' : 'True' - }) - if (args.asymmetric == True): - dep_dict.update({ - 'builtin_fifo' : 'True' - }) - if (args.builtin_fifo == False): - args.asymmetric = False - if (args.builtin_fifo == False and args.synchronous == False): - option_strings_to_remove = ['--write_depth'] - parser._actions = [action for action in parser._actions if action.option_strings and action.option_strings[0] not in option_strings_to_remove] - option_strings_to_remove = ['--depth'] - parser._actions = [action for action in parser._actions if action.option_strings and action.option_strings[0] not in option_strings_to_remove] - if (args.asymmetric): - option_strings_to_remove = ['--data_width'] - parser._actions = [action for action in parser._actions if action.option_strings and action.option_strings[0] not in option_strings_to_remove] - if (math.ceil(math.log2(args.depth)) != math.floor(math.log2(args.depth))): - parser._actions[5].default = 2 ** round(math.log2(args.depth)) - parser._actions[2].choices = range(2, args.DEPTH) - parser._actions[3].choices = range(1, args.DEPTH) - if (args.full_value >= args.DEPTH): - parser._actions[2].default = args.DEPTH - 1 - if (args.empty_value >= args.DEPTH): - parser._actions[3].default = 1 - parser._actions[4].choices = factors_multiples(args.data_width_write) - parser._actions[4].default = args.data_width_write - else: - option_strings_to_remove = ['--data_width_read'] - parser._actions = [action for action in parser._actions if action.option_strings and action.option_strings[0] not in option_strings_to_remove] - option_strings_to_remove = ['--data_width_write'] - parser._actions = [action for action in parser._actions if action.option_strings and action.option_strings[0] not in option_strings_to_remove] - if (math.ceil(math.log2(args.depth)) != math.floor(math.log2(args.depth))): - parser._actions[4].default = 2 ** round(math.log2(args.depth)) - parser._actions[2].choices = range(2, args.DEPTH) - parser._actions[3].choices = range(1, args.DEPTH) - if (args.full_value >= args.DEPTH): - parser._actions[2].default = args.DEPTH - 1 - if (args.empty_value >= args.DEPTH): - parser._actions[3].default = 1 - parser._actions[4].choices = [4 * (2 ** i) for i in range(int(math.log2(remaining_memory/args.data_width) - 1))] - else: - if (args.asymmetric): - option_strings_to_remove = ['--data_width'] - parser._actions = [action for action in parser._actions if action.option_strings and action.option_strings[0] not in option_strings_to_remove] - option_strings_to_remove = ['--depth'] - parser._actions = [action for action in parser._actions if action.option_strings and action.option_strings[0] not in option_strings_to_remove] - data_width_write = args.data_width_write - else: + if (device_dic['bram'] > 0): + if (args.full_threshold == False): + dep_dict.update({ + 'full_value' : 'True' + }) + if (args.empty_threshold == False): + dep_dict.update({ + 'empty_value' : 'True' + }) + if (args.builtin_fifo == False): + dep_dict.update({ + 'asymmetric' : 'True' + }) + if (args.asymmetric == True): + dep_dict.update({ + 'builtin_fifo' : 'True' + }) + if (args.builtin_fifo == False): + args.asymmetric = False + if (args.builtin_fifo == False and args.synchronous == False): option_strings_to_remove = ['--write_depth'] parser._actions = [action for action in parser._actions if action.option_strings and action.option_strings[0] not in option_strings_to_remove] - data_width_write = args.data_width - option_strings_to_remove = ['--DEPTH'] - parser._actions = [action for action in parser._actions if action.option_strings and action.option_strings[0] not in option_strings_to_remove] - if (args.asymmetric): - option_strings_to_remove = ['--data_width'] + option_strings_to_remove = ['--depth'] parser._actions = [action for action in parser._actions if action.option_strings and action.option_strings[0] not in option_strings_to_remove] - parser._actions[2].choices = range(2, args.depth) - parser._actions[3].choices = range(1, args.depth) - if (args.full_value >= args.depth): - parser._actions[2].default = args.depth - 1 - if (args.empty_value >= args.depth): - parser._actions[3].default = 1 - parser._actions[5].choices = factors_multiples(args.data_width_write) - parser._actions[5].default = args.data_width_write - parser._actions[4].choices = [16 * 2**i for i in range(0, 120) if 16 * 2**i <= int(prev_rem/args.data_width_write)] + if (args.asymmetric): + option_strings_to_remove = ['--data_width'] + parser._actions = [action for action in parser._actions if action.option_strings and action.option_strings[0] not in option_strings_to_remove] + if (math.ceil(math.log2(args.depth)) != math.floor(math.log2(args.depth))): + parser._actions[5].default = 2 ** round(math.log2(args.depth)) + parser._actions[2].choices = range(2, args.DEPTH) + parser._actions[3].choices = range(1, args.DEPTH) + if (args.full_value >= args.DEPTH): + parser._actions[2].default = args.DEPTH - 1 + if (args.empty_value >= args.DEPTH): + parser._actions[3].default = 1 + parser._actions[4].choices = factors_multiples(args.data_width_write) + parser._actions[4].default = args.data_width_write + else: + option_strings_to_remove = ['--data_width_read'] + parser._actions = [action for action in parser._actions if action.option_strings and action.option_strings[0] not in option_strings_to_remove] + option_strings_to_remove = ['--data_width_write'] + parser._actions = [action for action in parser._actions if action.option_strings and action.option_strings[0] not in option_strings_to_remove] + if (math.ceil(math.log2(args.depth)) != math.floor(math.log2(args.depth))): + parser._actions[4].default = 2 ** round(math.log2(args.depth)) + parser._actions[2].choices = range(2, args.DEPTH) + parser._actions[3].choices = range(1, args.DEPTH) + if (args.full_value >= args.DEPTH): + parser._actions[2].default = args.DEPTH - 1 + if (args.empty_value >= args.DEPTH): + parser._actions[3].default = 1 + parser._actions[4].choices = [4 * (2 ** i) for i in range(int(math.log2(remaining_memory/args.data_width) - 1))] else: - option_strings_to_remove = ['--data_width_read'] - parser._actions = [action for action in parser._actions if action.option_strings and action.option_strings[0] not in option_strings_to_remove] - option_strings_to_remove = ['--data_width_write'] + if (args.asymmetric): + option_strings_to_remove = ['--data_width'] + parser._actions = [action for action in parser._actions if action.option_strings and action.option_strings[0] not in option_strings_to_remove] + option_strings_to_remove = ['--depth'] + parser._actions = [action for action in parser._actions if action.option_strings and action.option_strings[0] not in option_strings_to_remove] + data_width_write = args.data_width_write + else: + option_strings_to_remove = ['--write_depth'] + parser._actions = [action for action in parser._actions if action.option_strings and action.option_strings[0] not in option_strings_to_remove] + data_width_write = args.data_width + option_strings_to_remove = ['--DEPTH'] parser._actions = [action for action in parser._actions if action.option_strings and action.option_strings[0] not in option_strings_to_remove] - parser._actions[2].choices = range(2, args.depth) - parser._actions[3].choices = range(1, args.depth) - if (args.full_value >= args.depth): - parser._actions[2].default = args.depth - 1 - if (args.empty_value >= args.depth): - parser._actions[3].default = 1 - parser._actions[4].choices = range(2, int(prev_rem/args.data_width) + 1) + if (args.asymmetric): + option_strings_to_remove = ['--data_width'] + parser._actions = [action for action in parser._actions if action.option_strings and action.option_strings[0] not in option_strings_to_remove] + parser._actions[2].choices = range(2, args.depth) + parser._actions[3].choices = range(1, args.depth) + if (args.full_value >= args.depth): + parser._actions[2].default = args.depth - 1 + if (args.empty_value >= args.depth): + parser._actions[3].default = 1 + parser._actions[5].choices = factors_multiples(args.data_width_write) + parser._actions[5].default = args.data_width_write + parser._actions[4].choices = [16 * 2**i for i in range(0, 120) if 16 * 2**i <= int(prev_rem/args.data_width_write)] + else: + option_strings_to_remove = ['--data_width_read'] + parser._actions = [action for action in parser._actions if action.option_strings and action.option_strings[0] not in option_strings_to_remove] + option_strings_to_remove = ['--data_width_write'] + parser._actions = [action for action in parser._actions if action.option_strings and action.option_strings[0] not in option_strings_to_remove] + parser._actions[2].choices = range(2, args.depth) + parser._actions[3].choices = range(1, args.depth) + if (args.full_value >= args.depth): + parser._actions[2].default = args.depth - 1 + if (args.empty_value >= args.depth): + parser._actions[3].default = 1 + parser._actions[4].choices = range(2, int(prev_rem/args.data_width) + 1) + else: + parser._actions = [action for action in parser._actions if not action.option_strings] args = rs_builder.import_args_from_json(parser=parser, json_filename=args.json) - - #device_dict contains the number of BRAMs and DSP for the device used. - device_dic = rs_builder.parse_device(args.device_path,args.device) - if (args.builtin_fifo == False and args.synchronous == False): - depth = args.DEPTH - else: - if(not args.asymmetric): - depth = args.depth + if (device_dic['bram'] > 0): + if (args.builtin_fifo == False and args.synchronous == False): + depth = args.DEPTH else: - if(args.data_width_read > args.data_width_write): - depth = args.write_depth + if(not args.asymmetric): + depth = args.depth + else: + if(args.data_width_read > args.data_width_write): + depth = args.write_depth summary = { } - if (args.asymmetric): - summary["Write Depth"] = depth - summary["Data Width Write"] = args.data_width_write - summary["Data Width Read"] = args.data_width_read - if (args.data_width_read > args.data_width_write): - summary["Read Latency (clock cycles)"] = clock_cycles_to_obtain_desired_output(args.data_width_read, args.data_width_write) - depth = args.write_depth - summary["Read Depth"] = int(depth/clock_cycles_to_obtain_desired_output(args.data_width_read, args.data_width_write) if (clock_cycles_to_obtain_desired_output(args.data_width_read, args.data_width_write)) > 1 else depth/(args.data_width_read/args.data_width_write)) + if (device_dic['bram'] > 0): + if (args.asymmetric): + summary["Write Depth"] = depth + summary["Data Width Write"] = args.data_width_write + summary["Data Width Read"] = args.data_width_read + if (args.data_width_read > args.data_width_write): + summary["Read Latency (clock cycles)"] = clock_cycles_to_obtain_desired_output(args.data_width_read, args.data_width_write) + depth = args.write_depth + summary["Read Depth"] = int(depth/clock_cycles_to_obtain_desired_output(args.data_width_read, args.data_width_write) if (clock_cycles_to_obtain_desired_output(args.data_width_read, args.data_width_write)) > 1 else depth/(args.data_width_read/args.data_width_write)) + else: + depth = args.write_depth + summary["Read Latency (clock cycles)"] = "1" + summary["Read Depth"] = int(depth*(args.data_width_write/args.data_width_read)) else: - depth = args.write_depth + summary["FIFO Depth"] = depth + summary["Data Width"] = args.data_width summary["Read Latency (clock cycles)"] = "1" - summary["Read Depth"] = int(depth*(args.data_width_write/args.data_width_read)) - else: - summary["FIFO Depth"] = depth - summary["Data Width"] = args.data_width - summary["Read Latency (clock cycles)"] = "1" - if(args.first_word_fall_through): - summary["FIFO Mode"] = "First Word Fall Through" - else: - summary["FIFO Mode"] = "Standard" - if (args.builtin_fifo): - if (args.asymmetric): - data_width_write = args.data_width_write + if(args.first_word_fall_through): + summary["FIFO Mode"] = "First Word Fall Through" else: - data_width_write = args.data_width - summary["Count of FIFOs"] = math.ceil(total_BRAM(data_width_write, depth) * 2) / 2 - if (args.empty_threshold): - summary["Programmable Empty"] = "Programmble Empty will be asserted at data count %s" % args.empty_value - if (args.full_threshold): - summary["Programmable Full"] = "Programmble Full will be asserted at data count %s" % args.full_value + summary["FIFO Mode"] = "Standard" + if (args.builtin_fifo): + if (args.asymmetric): + data_width_write = args.data_width_write + else: + data_width_write = args.data_width + summary["Count of FIFOs"] = math.ceil(total_BRAM(data_width_write, depth) * 2) / 2 + if (args.empty_threshold): + summary["Programmable Empty"] = "Programmble Empty will be asserted at data count %s" % args.empty_value + if (args.full_threshold): + summary["Programmable Full"] = "Programmble Full will be asserted at data count %s" % args.full_value + else: + summary["WARNING"] = "No FIFOs in selected device. Select a different device with BRAMs/FIFOs." # Export JSON Template (Optional) -------------------------------------------------------------- if args.json_template: rs_builder.export_json_template(parser=parser, dep_dict=dep_dict, summary=summary) - - if (args.asymmetric): - data_width_read = args.data_width_read - data_width_write = args.data_width_write - else: - data_width_read = args.data_width - data_width_write = args.data_width + if (device_dic['bram'] > 0): + if (args.asymmetric): + data_width_read = args.data_width_read + data_width_write = args.data_width_write + else: + data_width_read = args.data_width + data_width_write = args.data_width # Create Generator ------------------------------------------------------------------------------- platform = OSFPGAPlatform(io=[], toolchain="raptor", device="gemini") - module = FIFOGenerator(platform, - data_width_read = data_width_read, - data_width_write = data_width_write, - synchronous = args.synchronous, - full_threshold = args.full_threshold, - empty_threshold = args.empty_threshold, - depth = depth, - full_value = args.full_value, - empty_value = args.empty_value, - first_word_fall_through = args.first_word_fall_through, - builtin_fifo = args.builtin_fifo - ) + if (device_dic['bram'] > 0): + module = FIFOGenerator(platform, + data_width_read = data_width_read, + data_width_write = data_width_write, + synchronous = args.synchronous, + full_threshold = args.full_threshold, + empty_threshold = args.empty_threshold, + depth = depth, + full_value = args.full_value, + empty_value = args.empty_value, + first_word_fall_through = args.first_word_fall_through, + builtin_fifo = args.builtin_fifo + ) # Build Project -------------------------------------------------------------------------------- if args.build: diff --git a/rapidsilicon/ip/fir_generator/v1_0/fir_generator_gen.py b/rapidsilicon/ip/fir_generator/v1_0/fir_generator_gen.py index 8d6e65d8..a426446d 100755 --- a/rapidsilicon/ip/fir_generator/v1_0/fir_generator_gen.py +++ b/rapidsilicon/ip/fir_generator/v1_0/fir_generator_gen.py @@ -147,115 +147,133 @@ def main(): 'Description' : 'FIR Generator lets designers to efficiently design digital filters with customizable taps. Ideal for signal processing in FPGA applications.'} } + device_dic = { + 'dsp' : 56, + 'bram' : 56 + } + # Import JSON (Optional) ----------------------------------------------------------------------- if args.json: args = rs_builder.import_args_from_json(parser=parser, json_filename=args.json) rs_builder.import_ip_details_json(build_dir=args.build_dir ,details=details , build_name = args.build_name, version = "v1_0") + + #device_dict contains the number of BRAMs and DSP for the device used. + device_dic = rs_builder.parse_device(args.device_path,args.device) + file_path = os.path.dirname(os.path.realpath(__file__)) rs_builder.copy_images(file_path) - - if (args.optimization == "Area"): - if (not args.coefficients_file): - option_strings_to_remove = ['--number_of_coefficients'] + if (device_dic['dsp'] > 0): + if (args.optimization == "Area"): + if (not args.coefficients_file): + option_strings_to_remove = ['--number_of_coefficients'] + parser._actions = [action for action in parser._actions if action.option_strings and action.option_strings[0] not in option_strings_to_remove] + else: + if (args.number_of_coefficients == 1): + parser._actions[4].default = 2 + parser._actions[4].choices = range(2, 121) + option_strings_to_remove = ['--coefficient_width'] + parser._actions = [action for action in parser._actions if action.option_strings and action.option_strings[0] not in option_strings_to_remove] + else: + if (not args.coefficients_file): + option_strings_to_remove = ['--number_of_coefficients'] + parser._actions = [action for action in parser._actions if action.option_strings and action.option_strings[0] not in option_strings_to_remove] + parser._actions[4].choices = range(1, 20 - args.input_width + 1) + parser._actions[5].choices = range(0, 20 - args.input_width + 1) + else: + parser._actions[4].choices = range(1, device_dic['dsp'] + 1) + parser._actions[5].choices = range(1, 20 - args.input_width + 1) + parser._actions[6].choices = range(0, 20 - args.input_width + 1) + if (args.coefficients_file == False): + option_strings_to_remove = ['--file_path'] parser._actions = [action for action in parser._actions if action.option_strings and action.option_strings[0] not in option_strings_to_remove] else: - if (args.number_of_coefficients == 1): - parser._actions[4].default = 2 - parser._actions[4].choices = range(2, 121) - option_strings_to_remove = ['--coefficient_width'] + option_strings_to_remove = ['--coefficients'] parser._actions = [action for action in parser._actions if action.option_strings and action.option_strings[0] not in option_strings_to_remove] - else: - if (not args.coefficients_file): - option_strings_to_remove = ['--number_of_coefficients'] + if (not has_fractional_number(extract_numbers(args.coefficients, args.coefficients_file))): + dep_dict.update({ + 'coefficient_fractional_bits' : 'True' + }) + if (args.optimization == "Area" and args.coefficients_file): + option_strings_to_remove = ['--coefficient_fractional_bits'] parser._actions = [action for action in parser._actions if action.option_strings and action.option_strings[0] not in option_strings_to_remove] - parser._actions[4].choices = range(1, 20 - args.input_width + 1) - parser._actions[5].choices = range(0, 20 - args.input_width + 1) - else: - parser._actions[5].choices = range(1, 20 - args.input_width + 1) - parser._actions[6].choices = range(0, 20 - args.input_width + 1) - if (args.coefficients_file == False): - option_strings_to_remove = ['--file_path'] - parser._actions = [action for action in parser._actions if action.option_strings and action.option_strings[0] not in option_strings_to_remove] + if (not args.truncated_output): + dep_dict.update({ + 'output_data_width' : 'True' + }) else: - option_strings_to_remove = ['--coefficients'] - parser._actions = [action for action in parser._actions if action.option_strings and action.option_strings[0] not in option_strings_to_remove] - if (not has_fractional_number(extract_numbers(args.coefficients, args.coefficients_file))): - dep_dict.update({ - 'coefficient_fractional_bits' : 'True' - }) - if (args.optimization == "Area" and args.coefficients_file): - option_strings_to_remove = ['--coefficient_fractional_bits'] - parser._actions = [action for action in parser._actions if action.option_strings and action.option_strings[0] not in option_strings_to_remove] - if (not args.truncated_output): - dep_dict.update({ - 'output_data_width' : 'True' - }) + parser._actions = [action for action in parser._actions if not action.option_strings] if (not args.coefficients_file): coefficients = args.coefficients else: coefficients = args.file_path - if (args.optimization == "Area" and args.coefficients_file): - non_zero_elements = [element for element in extract_numbers(coefficients, args.coefficients_file) if element != 0] - bit_growth = int(args.coefficient_width + math.ceil(math.log2(len(non_zero_elements))) if len(non_zero_elements) > 0 else 0) - elif (args.coefficients == ""): - bit_growth = 0 + if (device_dic['dsp'] > 0): + if (args.optimization == "Area" and args.coefficients_file): + non_zero_elements = [element for element in extract_numbers(coefficients, args.coefficients_file) if element != 0] + bit_growth = int(args.coefficient_width + math.ceil(math.log2(len(non_zero_elements))) if len(non_zero_elements) > 0 else 0) + elif (args.coefficients == ""): + bit_growth = 0 + else: + abs_sum = sum(abs(coeff) for coeff in extract_numbers(coefficients, args.coefficients_file)) + bit_growth = math.ceil(math.log2(abs_sum)) else: - abs_sum = sum(abs(coeff) for coeff in extract_numbers(coefficients, args.coefficients_file)) - bit_growth = math.ceil(math.log2(abs_sum)) - - #device_dict contains the number of BRAMs and DSP for the device used. - device_dic = rs_builder.parse_device(args.device_path,args.device) + bit_growth = 0 summary = {} - if (args.coefficients_file): - if (args.optimization == "Area"): - input_minimum = round(max(800/args.number_of_coefficients, 8), 2) - input_maximum = round(min(3200/args.number_of_coefficients, 500), 2) - summary ["Reloadable Coefficient Filter"] = "The coefficients file can be modified after IP generation, but the count of coefficients must remain constant." - summary ["Coefficient Bit Width"] = "20" - summary ["Input Frequency"] = f"{input_minimum} MHz - {input_maximum} MHz" - summary ["Input File"] = "Only .hex file format is supported without any prefix for numbers." - summary ["Fast Clock Frequency"] = f"Fast clock must be {args.number_of_coefficients}x of the input master clock." - if (not args.truncated_output): - summary ["Output Width"] = f"{min(args.input_width + bit_growth, 38)} with worst case bit growth." - summary ["Number of DSPs"] = "1" + if (device_dic['dsp'] > 0): + if (args.coefficients_file): + if (args.optimization == "Area"): + input_minimum = round(max(800/args.number_of_coefficients, 8), 2) + input_maximum = round(min(3200/args.number_of_coefficients, 500), 2) + summary ["Reloadable Coefficient Filter"] = "The coefficients file can be modified after IP generation, but the count of coefficients must remain constant." + summary ["Coefficient Bit Width"] = "20" + summary ["Input Frequency"] = f"{input_minimum} MHz - {input_maximum} MHz" + summary ["Input File"] = "Only .hex file format is supported without any prefix for numbers." + summary ["Fast Clock Frequency"] = f"Fast clock must be {args.number_of_coefficients}x of the input master clock." + if (not args.truncated_output): + summary ["Output Width"] = f"{min(args.input_width + bit_growth, 38)} with worst case bit growth." + summary ["Number of DSPs"] = "1" + else: + summary ["Fixed Coefficient Filter"] = "The coefficients cannot be changed after IP generation." + if (not args.truncated_output): + summary ["Output Width"] = f"{min(args.input_width + bit_growth, 38)} with true maximum bit growth." + summary ["Number of DSPs"] = len(extract_numbers(coefficients, args.coefficients_file)) + summary ["Input File"] = ".txt or .hex file formats are supported with the hex numbers starting with 0x while decimal numbers require no prefix." + if (args.file_path == ""): + summary ["Coefficients"] = "None" + summary ["File"] = "No file provided" + elif (is_valid_extension(coefficients) and len(extract_numbers(coefficients, args.coefficients_file)) > 0): + summary ["Coefficients"] = ', '.join(map(str, extract_numbers(coefficients, args.coefficients_file))) + summary ["Filter Taps"] = len(extract_numbers(coefficients, args.coefficients_file)) + else: + summary ["Coefficients"] = "None" + summary["File Not Valid"] = "Only .txt and .hex file formats are supported with numbers having the correct prefix as specified." else: summary ["Fixed Coefficient Filter"] = "The coefficients cannot be changed after IP generation." if (not args.truncated_output): summary ["Output Width"] = f"{min(args.input_width + bit_growth, 38)} with true maximum bit growth." - summary ["Number of DSPs"] = len(extract_numbers(coefficients, args.coefficients_file)) - summary ["Input File"] = ".txt or .hex file formats are supported with the hex numbers starting with 0x while decimal numbers require no prefix." - if (args.file_path == ""): - summary ["Coefficients"] = "None" - summary ["File"] = "No file provided" - elif (is_valid_extension(coefficients) and len(extract_numbers(coefficients, args.coefficients_file)) > 0): - summary ["Coefficients"] = ', '.join(map(str, extract_numbers(coefficients, args.coefficients_file))) summary ["Filter Taps"] = len(extract_numbers(coefficients, args.coefficients_file)) + if (args.optimization == "Area"): + input_minimum = round(max(800/len(extract_numbers(coefficients, args.coefficients_file)) if len(extract_numbers(coefficients, args.coefficients_file)) > 0 else 1, 8), 2) + input_maximum = round(min(3200/len(extract_numbers(coefficients, args.coefficients_file)) if len(extract_numbers(coefficients, args.coefficients_file)) > 0 else 500, 500), 2) + summary ["Input Frequency"] = f"{input_minimum} MHz - {input_maximum} MHz" + summary ["Optimization"] = "Area" + summary ["Number of DSPs"] = "1" + summary ["Fast Clock Frequency"] = f"Fast clock must be {len(extract_numbers(coefficients, args.coefficients_file))}x of the input master clock." + else: + summary ["Optimization"] = "Performance" + if (len(extract_numbers(coefficients, args.coefficients_file)) <= device_dic['dsp']): + summary ["Number of DSPs"] = len(extract_numbers(coefficients, args.coefficients_file)) + else: + summary["WARNING"] = "Filter taps greater than number of DSPs in the selected device. Invalid design." + if (args.truncated_output): + summary ["Output Fractional Bits"] = f"{args.input_fractional_bits + args.coefficient_fractional_bits - max(0, (args.input_width + bit_growth) - args.output_data_width) if args.input_fractional_bits + args.coefficient_fractional_bits - max(0, (args.input_width + bit_growth) - args.output_data_width) > 0 else 0}" + summary ["Output Rounding"] = "Truncation Applied." else: - summary ["Coefficients"] = "None" - summary["File Not Valid"] = "Only .txt and .hex file formats are supported with numbers having the correct prefix as specified." - else: - summary ["Fixed Coefficient Filter"] = "The coefficients cannot be changed after IP generation." - if (not args.truncated_output): - summary ["Output Width"] = f"{min(args.input_width + bit_growth, 38)} with true maximum bit growth." - summary ["Filter Taps"] = len(extract_numbers(coefficients, args.coefficients_file)) - if (args.optimization == "Area"): - input_minimum = round(max(800/len(extract_numbers(coefficients, args.coefficients_file)) if len(extract_numbers(coefficients, args.coefficients_file)) > 0 else 1, 8), 2) - input_maximum = round(min(3200/len(extract_numbers(coefficients, args.coefficients_file)) if len(extract_numbers(coefficients, args.coefficients_file)) > 0 else 500, 500), 2) - summary ["Input Frequency"] = f"{input_minimum} MHz - {input_maximum} MHz" - summary ["Optimization"] = "Area" - summary ["Number of DSPs"] = "1" - summary ["Fast Clock Frequency"] = f"Fast clock must be {len(extract_numbers(coefficients, args.coefficients_file))}x of the input master clock." - else: - summary ["Optimization"] = "Performance" - summary ["Number of DSPs"] = len(extract_numbers(coefficients, args.coefficients_file)) - if (args.truncated_output): - summary ["Output Fractional Bits"] = f"{args.input_fractional_bits + args.coefficient_fractional_bits - max(0, (args.input_width + bit_growth) - args.output_data_width) if args.input_fractional_bits + args.coefficient_fractional_bits - max(0, (args.input_width + bit_growth) - args.output_data_width) > 0 else 0}" - summary ["Output Rounding"] = "Truncation Applied." + summary ["Output Fractional Bits"] = f"{args.input_fractional_bits + args.coefficient_fractional_bits}" + summary ["Output Rounding"] = "Full Precision with Saturation Applied when accumulated output becomes greater than 38 bits." else: - summary ["Output Fractional Bits"] = f"{args.input_fractional_bits + args.coefficient_fractional_bits}" - summary ["Output Rounding"] = "Full Precision with Saturation Applied when accumulated output becomes greater than 38 bits." + summary["WARNING"] = "No DSPs in selected device. Select a different device with DSPs." # Export JSON Template (Optional) -------------------------------------------------------------- if args.json_template: @@ -263,19 +281,20 @@ def main(): # Create Generator ------------------------------------------------------------------------------- platform = OSFPGAPlatform(io=[], toolchain="raptor", device="gemini") - module = FIRGenerator(platform, - input_width = args.input_width, - coefficients = coefficients, - coefficients_file = args.coefficients_file, - coefficient_fractional_bits = args.coefficient_fractional_bits, - signed = args.signed, - optimization = args.optimization, - number_of_coefficients = args.number_of_coefficients, - coefficient_width = args.coefficient_width, - input_fractional_bits = args.input_fractional_bits, - truncated_output = args.truncated_output, - output_data_width = args.output_data_width - ) + if (device_dic['dsp'] > 0): + module = FIRGenerator(platform, + input_width = args.input_width, + coefficients = coefficients, + coefficients_file = args.coefficients_file, + coefficient_fractional_bits = args.coefficient_fractional_bits, + signed = args.signed, + optimization = args.optimization, + number_of_coefficients = args.number_of_coefficients, + coefficient_width = args.coefficient_width, + input_fractional_bits = args.input_fractional_bits, + truncated_output = args.truncated_output, + output_data_width = args.output_data_width + ) # Build Project -------------------------------------------------------------------------------- if args.build: diff --git a/rapidsilicon/lib/common.py b/rapidsilicon/lib/common.py index 198fdd4f..1be8b958 100644 --- a/rapidsilicon/lib/common.py +++ b/rapidsilicon/lib/common.py @@ -397,9 +397,9 @@ def parse_device(self, device_file, device): for sub_dummy in dummy: if sub_dummy.attrib.get('type') == 'bram': fnum_bram = sub_dummy.attrib.get('num') - device_dict[sub_dummy.attrib.get('type')] = (fnum_bram) + device_dict[sub_dummy.attrib.get('type')] = (int(fnum_bram)) elif sub_dummy.attrib.get('type') == 'dsp': fnum_dsp = sub_dummy.attrib.get('num') - device_dict[sub_dummy.attrib.get('type')] = (fnum_dsp) + device_dict[sub_dummy.attrib.get('type')] = (int(fnum_dsp)) return device_dict \ No newline at end of file From 76a94de3488e744d54ac82818b6d89ba81789835 Mon Sep 17 00:00:00 2001 From: moinijaz Date: Wed, 31 Jul 2024 16:45:55 +0500 Subject: [PATCH 3/5] ocm device parsing updated --- .../on_chip_memory/v1_0/on_chip_memory_gen.py | 180 +++++++++++------- 1 file changed, 109 insertions(+), 71 deletions(-) diff --git a/rapidsilicon/ip/on_chip_memory/v1_0/on_chip_memory_gen.py b/rapidsilicon/ip/on_chip_memory/v1_0/on_chip_memory_gen.py index 70318330..bccdaf5d 100755 --- a/rapidsilicon/ip/on_chip_memory/v1_0/on_chip_memory_gen.py +++ b/rapidsilicon/ip/on_chip_memory/v1_0/on_chip_memory_gen.py @@ -91,9 +91,17 @@ def get_clkin_ios(port_type, data_width, write_depth, memory_type, write_width_A ("be_B", 0, Pins(math.ceil(write_width_B/9))) ] +def depth_param_limit(data_width, device_dic): + if (data_width > 36): + Max_Depth = math.ceil(int(device_dic['bram'] * 1024) / math.ceil(data_width/36)) + else: + Max_Depth = device_dic['bram'] * 1024 + + return Max_Depth + # on_chip_memory Wrapper ---------------------------------------------------------------------------------- class OCMWrapper(Module): - def __init__(self, platform, write_width_A, write_width_B, read_width_A, read_width_B, memory_type, write_depth, data_width, common_clk, port_type, write_depth_A, read_depth_A, write_depth_B, read_depth_B, memory_mapping, file_path_hex, file_extension, byte_write_enable): + def __init__(self, platform, write_width_A, write_width_B, read_width_A, read_width_B, memory_type, write_depth, data_width, common_clk, port_type, write_depth_A, read_depth_A, write_depth_B, read_depth_B, memory_mapping, file_path_hex, file_extension, byte_write_enable, op_mode): # Clocking --------------------------------------------------------------------------------- platform.add_extension(get_clkin_ios(port_type, data_width, write_depth, memory_type, write_width_A, write_width_B, read_width_A, read_width_B, write_depth_A, write_depth_B, read_depth_A, read_depth_B)) self.clock_domains.cd_sys = ClockDomain(reset_less = True) @@ -101,9 +109,9 @@ def __init__(self, platform, write_width_A, write_width_B, read_width_A, read_wi self.clock_domains.B = ClockDomain(reset_less = True) if port_type == "Asymmetric": - self.submodules.sp = ram = OCM_ASYM(write_width_A, write_width_B, read_width_A, read_width_B, memory_type, common_clk, write_depth_A, read_depth_A, write_depth_B, read_depth_B, memory_mapping, file_path_hex, file_extension, byte_write_enable) + self.submodules.sp = ram = OCM_ASYM(write_width_A, write_width_B, read_width_A, read_width_B, memory_type, common_clk, write_depth_A, read_depth_A, write_depth_B, read_depth_B, memory_mapping, file_path_hex, file_extension, byte_write_enable, op_mode) else: - self.submodules.sp = ram = OCM_SYM(data_width, memory_type, common_clk, write_depth, memory_mapping, file_path_hex, file_extension, byte_write_enable) + self.submodules.sp = ram = OCM_SYM(data_width, memory_type, common_clk, write_depth, memory_mapping, file_path_hex, file_extension, byte_write_enable, op_mode) self.M = ram.m self.N = ram.n @@ -194,6 +202,7 @@ def main(): core_string_param_group.add_argument("--memory_type", type=str, default="Single_Port", choices=["Single_Port", "Simple_Dual_Port", "True_Dual_Port"], help="RAM Type") core_string_param_group.add_argument("--port_type", type=str, default="Symmetric", choices=["Symmetric", "Asymmetric"], help="Ports Type") core_string_param_group.add_argument("--memory_mapping", type=str, default="Block_RAM", choices=["Block_RAM", "Distributed_RAM"], help="Memory mapping on Block RAM and Distributed RAM (LUTs)") + core_string_param_group.add_argument("--op_mode", type=str, default="Read_First", choices=["No_Change", "Write_First", "Read_First"], help="Operation Mode of Memory") # Core bool value parameters. core_bool_param_group = parser.add_argument_group(title="Core bool parameters") @@ -238,6 +247,13 @@ def main(): 'Description' : 'On Chip Memory Generator is an IP Core with native interface. This IP Core simplifies the integration of memory elements, allowing designers to generate customized on-chip memory instances that match their specific requirements. It include the ability to configure memory size, data width, organization (e.g., single-port, dual-port), and various memory types (e.g., single-ported RAM, simple dual-port RAM and true dual port RAM).'} } + device_dic = { + 'dsp' : 0, + 'bram' : 0 + } + + summary = {} + # Import JSON (Optional) ----------------------------------------------------------------------- if args.json: args = rs_builder.import_args_from_json(parser=parser, json_filename=args.json) @@ -246,50 +262,71 @@ def main(): file_path = os.path.dirname(os.path.realpath(__file__)) rs_builder.copy_images(file_path) - if (args.byte_write_enable == True): - option_strings_to_remove = ['--data_width'] - parser._actions = [action for action in parser._actions if action.option_strings and action.option_strings[0] not in option_strings_to_remove] - else: - option_strings_to_remove = ['--DATA_WIDTH'] - parser._actions = [action for action in parser._actions if action.option_strings and action.option_strings[0] not in option_strings_to_remove] + # bram device resources + device_dic = rs_builder.parse_device(args.device_dic, args.device) - if (args.memory_mapping == "Distributed_RAM"): - option_strings_to_remove = ['--byte_write_enable'] - parser._actions = [action for action in parser._actions if action.option_strings and action.option_strings[0] not in option_strings_to_remove] + if (args.port_type == "Symmetric"): + if (args.byte_write_enable == True): + data_width = args.DATA_WIDTH + else: + data_width = args.data_width + else: # Asymmetric + if (args.memory_type == "Single_Port"): + data_width = max(args.write_width_A, args.read_width_A) + elif (args.memory_type == "Simple_Dual_Port"): + data_width = max(args.write_width_A, args.read_width_B) + elif (args.memory_type == "True_Dual_Port"): + data_width = max(args.write_width_A, args.read_width_A, args.write_width_B, args.read_width_B) + + Max_Depth = depth_param_limit(data_width, device_dic) - if (args.write_width_A >= 288 or args.read_width_A >= 288 or args.write_width_B >= 288 or args.read_width_B >= 288): - parser._actions[11].choices = [1024, 2048, 4096, 8192] - if (args.port_type == "Symmetric"): - option_strings_to_remove = ['--write_width_A', '--write_width_B', '--read_width_A', '--read_width_B', '--write_depth_A'] - parser._actions = [action for action in parser._actions if action.option_strings and action.option_strings[0] not in option_strings_to_remove] + parser._actions[14].choices = range(2, Max_Depth+1) + parser._actions[14].default = Max_Depth else: - option_strings_to_remove = ['--DATA_WIDTH', '--data_width','--write_depth'] - parser._actions = [action for action in parser._actions if action.option_strings and action.option_strings[0] not in option_strings_to_remove] + depth_list = [1024, 2048, 4096, 8192, 16384, 32768] + parser._actions[12].choices = [value for value in depth_list if value <= Max_Depth] + parser._actions[12].default = Max_Depth - if (args.memory_type in ["Single_Port"]): - dep_dict.update({ - 'common_clk': 'True' - }) - option_strings_to_remove = ['--write_width_B', '--read_width_B'] - parser._actions = [action for action in parser._actions if action.option_strings and action.option_strings[0] not in option_strings_to_remove] - if (args.write_width_A != args.read_width_A): - parser._actions[3].choices = ["Block_RAM"] - - elif (args.memory_type in ["Simple_Dual_Port"]): - option_strings_to_remove = ['--write_width_B', '--read_width_A'] - parser._actions = [action for action in parser._actions if action.option_strings and action.option_strings[0] not in option_strings_to_remove] - if (args.write_width_A != args.read_width_B): - parser._actions[3].choices = ["Block_RAM"] - - elif (args.memory_type in ["True_Dual_Port"]): - if (args.write_width_A != args.read_width_A or args.write_width_A != args.write_width_B or args.write_width_B != args.read_width_B): - parser._actions[3].choices = ["Block_RAM"] - #device_dict contains the number of BRAMs and DSP for the device used. - device_dic = rs_builder.parse_device(args.device_path,args.device) + if (device_dic['bram'] > 0): + if (args.byte_write_enable == True): + option_strings_to_remove = ['--data_width'] + parser._actions = [action for action in parser._actions if action.option_strings and action.option_strings[0] not in option_strings_to_remove] + else: + option_strings_to_remove = ['--DATA_WIDTH'] + parser._actions = [action for action in parser._actions if action.option_strings and action.option_strings[0] not in option_strings_to_remove] + if (args.memory_mapping == "Distributed_RAM"): + option_strings_to_remove = ['--byte_write_enable'] + parser._actions = [action for action in parser._actions if action.option_strings and action.option_strings[0] not in option_strings_to_remove] + if (args.write_width_A >= 288 or args.read_width_A >= 288 or args.write_width_B >= 288 or args.read_width_B >= 288): + parser._actions[12].choices = [1024, 2048, 4096, 8192] + if (args.port_type == "Symmetric"): + option_strings_to_remove = ['--write_width_A', '--write_width_B', '--read_width_A', '--read_width_B', '--write_depth_A'] + parser._actions = [action for action in parser._actions if action.option_strings and action.option_strings[0] not in option_strings_to_remove] + else: + option_strings_to_remove = ['--DATA_WIDTH', '--data_width','--write_depth'] + parser._actions = [action for action in parser._actions if action.option_strings and action.option_strings[0] not in option_strings_to_remove] + if (args.memory_type in ["Single_Port"]): + dep_dict.update({ + 'common_clk': 'True' + }) + option_strings_to_remove = ['--write_width_B', '--read_width_B'] + parser._actions = [action for action in parser._actions if action.option_strings and action.option_strings[0] not in option_strings_to_remove] + if (args.write_width_A != args.read_width_A): + parser._actions[3].choices = ["Block_RAM"] + elif (args.memory_type in ["Simple_Dual_Port"]): + option_strings_to_remove = ['--write_width_B', '--read_width_A'] + parser._actions = [action for action in parser._actions if action.option_strings and action.option_strings[0] not in option_strings_to_remove] + if (args.write_width_A != args.read_width_B): + parser._actions[3].choices = ["Block_RAM"] + elif (args.memory_type in ["True_Dual_Port"]): + if (args.write_width_A != args.read_width_A or args.write_width_A != args.write_width_B or args.write_width_B != args.read_width_B): + parser._actions[3].choices = ["Block_RAM"] + else: + parser._actions = [action for action in parser._actions if not action.option_strings] # Create Wrapper ------------------------------------------------------------------------------- - platform = OSFPGAPlatform(io=[], toolchain="raptor", device="gemini") + platform = OSFPGAPlatform(io=[], toolchain="raptor", device=args.device) file_extension = os.path.splitext(args.file_path)[1] if (args.memory_type == "Single_Port"): @@ -316,38 +353,37 @@ def main(): memory_mapping = "Block RAM" else: memory_mapping = "Distributed RAM(LUTs)" - - summary = { - "Type of Memory": memory, - "Mapping": memory_mapping, - } - if args.port_type == "Asymmetric": - if (args.memory_type == "Single_Port"): - summary["Address A"] = math.ceil(math.log2(args.write_depth_A)) - elif args.memory_type == "Simple_Dual_Port": - summary["Address A"] = math.ceil(math.log2(args.write_depth_A)) - summary["Address B"] = math.ceil(math.log2(read_depth_B)) - elif args.memory_type == "True_Dual_Port": - if (args.write_depth_A > read_depth_A): # assigning greater value to addr_A port - write_depthA = args.write_depth_A - else: - write_depthA = read_depth_A - if (write_depth_B > read_depth_B): # assigning greater value to addr_B port - write_depthB = write_depth_B + if (device_dic['bram'] > 0): + summary["Type of Memory"] = memory + summary["Mapping"] = memory_mapping + if args.port_type == "Asymmetric": + if (args.memory_type == "Single_Port"): + summary["Address A"] = math.ceil(math.log2(args.write_depth_A)) + elif args.memory_type == "Simple_Dual_Port": + summary["Address A"] = math.ceil(math.log2(args.write_depth_A)) + summary["Address B"] = math.ceil(math.log2(read_depth_B)) + elif args.memory_type == "True_Dual_Port": + if (args.write_depth_A > read_depth_A): # assigning greater value to addr_A port + write_depthA = args.write_depth_A + else: + write_depthA = read_depth_A + if (write_depth_B > read_depth_B): # assigning greater value to addr_B port + write_depthB = write_depth_B + else: + write_depthB = read_depth_B + summary["Address A"] = math.ceil(math.log2(write_depthA)) + summary["Address B"] = math.ceil(math.log2(write_depthB)) + else: + summary["Address"] = math.ceil(math.log2(args.write_depth)) + if (args.memory_type in ["Simple_Dual_Port", "True_Dual_Port"]): + if (args.common_clk == 1): + summary["Synchronization"] = "True" else: - write_depthB = read_depth_B - summary["Address A"] = math.ceil(math.log2(write_depthA)) - summary["Address B"] = math.ceil(math.log2(write_depthB)) + summary["Synchronization"] = "False" else: - summary["Address"] = math.ceil(math.log2(args.write_depth)) + summary["WARNING"] = "No BRAMs in selected device. Select a different device with BRAMs." - if (args.memory_type in ["Simple_Dual_Port", "True_Dual_Port"]): - if (args.common_clk == 1): - summary["Synchronization"] = "True" - else: - summary["Synchronization"] = "False" - if (args.byte_write_enable == True): data = args.DATA_WIDTH else: @@ -370,11 +406,13 @@ def main(): port_type = args.port_type, file_path_hex = args.file_path, file_extension = file_extension, - byte_write_enable = args.byte_write_enable + byte_write_enable = args.byte_write_enable, + op_mode = args.op_mode ) - if (args.memory_mapping == "Block_RAM"): - summary["Number of BRAMs"] = module.M * module.N + if (device_dic['bram'] > 0): + if (args.memory_mapping == "Block_RAM"): + summary["Number of BRAMs"] = module.M * module.N # Export JSON Template (Optional) -------------------------------------------------------------- if args.json_template: From 0ad091f15c0e8d6bf6fb7f57cde479f577f81041 Mon Sep 17 00:00:00 2001 From: moinijaz Date: Wed, 31 Jul 2024 17:06:34 +0500 Subject: [PATCH 4/5] ocm wrappers updated and SP clock updated --- ...on_chip_memory_litex_wrapper_asymmetric.py | 164 +++++++++++----- .../on_chip_memory_litex_wrapper_symmetric.py | 132 +++++++++---- .../on_chip_memory/v1_0/on_chip_memory_gen.py | 180 +++++++----------- 3 files changed, 283 insertions(+), 193 deletions(-) diff --git a/rapidsilicon/ip/on_chip_memory/v1_0/litex_wrapper/on_chip_memory_litex_wrapper_asymmetric.py b/rapidsilicon/ip/on_chip_memory/v1_0/litex_wrapper/on_chip_memory_litex_wrapper_asymmetric.py index cda14694..598dd385 100644 --- a/rapidsilicon/ip/on_chip_memory/v1_0/litex_wrapper/on_chip_memory_litex_wrapper_asymmetric.py +++ b/rapidsilicon/ip/on_chip_memory/v1_0/litex_wrapper/on_chip_memory_litex_wrapper_asymmetric.py @@ -421,7 +421,7 @@ def memory_init(self, file_path, file_extension, m, n, smaller_width, large_dept self.logger.info(f"===================================================") return INIT, INIT_PARITY - def __init__(self, write_width_A, write_width_B, read_width_A, read_width_B, memory_type, common_clk, write_depth_A, read_depth_A, write_depth_B, read_depth_B, memory_mapping, file_path_hex, file_extension, byte_write_enable): + def __init__(self, write_width_A, write_width_B, read_width_A, read_width_B, memory_type, common_clk, write_depth_A, read_depth_A, write_depth_B, read_depth_B, memory_mapping, file_path_hex, file_extension, byte_write_enable, op_mode): self.write_depth_A = write_depth_A self.write_width_A = write_width_A @@ -497,21 +497,25 @@ def __init__(self, write_width_A, write_width_B, read_width_A, read_width_B, mem # Port A din/dout self.din_A = Signal(write_width_A) + self.din_A_reg = Signal(write_width_A) self.dout_A = Signal(read_width_A) self.dout_A_ = Signal(read_width_A) self.dout_A_reg = Signal(read_width_A) # Port B din/dout self.din_B = Signal(write_width_B) + self.din_B_reg = Signal(write_width_B) self.dout_B = Signal(read_width_B) self.dout_B_ = Signal(read_width_B) self.dout_B_reg = Signal(read_width_B) # External write/read enables self.wen_A = Signal(1) + self.wen_A_reg = Signal(1) self.ren_A = Signal(1) self.ren_A_reg = Signal(1) self.wen_B = Signal(1) + self.wen_B_reg = Signal(1) self.ren_B = Signal(1) self.ren_B_reg = Signal(1) @@ -799,9 +803,15 @@ def __init__(self, write_width_A, write_width_B, read_width_A, read_width_B, mem # -------------------------------------------------------------------------------------------- # Single Port RAM if (memory_type == "Single_Port"): - self.comb += If((self.ren_A_reg), self.dout_A_.eq(self.dout_A)).Else(self.dout_A_.eq(self.dout_A_reg)) - self.sync.A += If(self.ren_A_reg, self.dout_A_reg.eq(self.dout_A)) - self.sync.A += self.ren_A_reg.eq(self.ren_A) + if (op_mode in ["No_Change", "Read_First"]): + self.comb += If((self.ren_A_reg), self.dout_A_.eq(self.dout_A)).Else(self.dout_A_.eq(self.dout_A_reg)) + self.sync.A += If(self.ren_A_reg, self.dout_A_reg.eq(self.dout_A)) + self.sync.A += self.ren_A_reg.eq(self.ren_A) + else: # WRITE_FIRST + self.comb += If((self.wen_A_reg), self.dout_A_.eq(self.din_A_reg)).Else(self.dout_A_.eq(self.dout_A)) + self.sync.A += self.wen_A_reg.eq(self.wen_A) + self.sync.A += self.din_A_reg.eq(self.din_A) + if (write_width_A == read_width_A): # Symmetric Memory if (write_depth_A in [1024, 2048, 4096, 8192, 16384, 32768]): if n > 1: @@ -884,20 +894,24 @@ def __init__(self, write_width_A, write_width_B, read_width_A, read_width_B, mem addr_reg_mux = {} if (write_depth_A == 1024 and read_width_A <= 36): for i in range(m): - ren_mux[i] = self.ren_A1.eq(Cat(Replicate(0,i), self.ren_A)) + if (op_mode in ["No_Change", "Read_First"]): + ren_mux[i] = self.ren_A1.eq(Cat(Replicate(0,i), self.ren_A)) addr_reg_mux[i] = self.addr_reg_A.eq(i) elif (write_depth_A == 2048 and read_width_A <= 18): for i in range(m): - ren_mux[i] = self.ren_A1.eq(Cat(Replicate(0,i), self.ren_A)) + if (op_mode in ["No_Change", "Read_First"]): + ren_mux[i] = self.ren_A1.eq(Cat(Replicate(0,i), self.ren_A)) addr_reg_mux[i] = self.addr_reg_A.eq(i) elif (write_depth_A == 4096 and read_width_A <= 9): for i in range(m): - ren_mux[i] = self.ren_A1.eq(Cat(Replicate(0,i), self.ren_A)) + if (op_mode in ["No_Change", "Read_First"]): + ren_mux[i] = self.ren_A1.eq(Cat(Replicate(0,i), self.ren_A)) addr_reg_mux[i] = self.addr_reg_A.eq(i) elif (write_depth_A in [8192, 16384, 32768]): if (read_width_A >= 9): for i in range(n * int(write_width_A/read_width_A)): - ren_mux[i] = self.ren_A1.eq(Cat(Replicate(0,i), self.ren_A)) + if (op_mode in ["No_Change", "Read_First"]): + ren_mux[i] = self.ren_A1.eq(Cat(Replicate(0,i), self.ren_A)) addr_reg_mux[i] = self.addr_reg_A.eq(i) if (m > 1 or n > 1): @@ -906,7 +920,8 @@ def __init__(self, write_width_A, write_width_B, read_width_A, read_width_B, mem else: if (write_width_A > read_width_A): for i in range(int(write_width_A/read_width_A)): - ren_mux[i] = self.ren_A1.eq(Cat(Replicate(0,i), self.ren_A)) + if (op_mode in ["No_Change", "Read_First"]): + ren_mux[i] = self.ren_A1.eq(Cat(Replicate(0,i), self.ren_A)) addr_reg_mux[i] = self.addr_reg_A.eq(i) # For more than 1 BRAMS @@ -990,7 +1005,8 @@ def __init__(self, write_width_A, write_width_B, read_width_A, read_width_B, mem if (read_depth_A >= 8192): n_temp = int(read_depth_A/4096) for i in range(n_temp): - ren_mux[i] = self.ren_A1.eq(Cat(Replicate(0,i), self.ren_A)) + if (op_mode in ["No_Change", "Read_First"]): + ren_mux[i] = self.ren_A1.eq(Cat(Replicate(0,i), self.ren_A)) dout_mux[i] = self.addr_reg_A.eq(i) if read_depth_A <= 1024 or read_depth_A in [2048, 4096]: @@ -1447,7 +1463,10 @@ def __init__(self, write_width_A, write_width_B, read_width_A, read_width_B, mem write_data_A = self.din_A[(j*1):((j*1)+1)] w_parity_A = Replicate(0,4) - + if (op_mode == "Read_First"): + renA = ren + elif (op_mode == "No_Change" or op_mode == "Write_First"): + renA = ~self.wen_A # Module instance. # ---------------- @@ -1462,11 +1481,11 @@ def __init__(self, write_width_A, write_width_B, read_width_A, read_width_B, mem p_READ_WIDTH_B = param_read_width_A, # Ports. # ----------- - i_CLK_A = clock1, + i_CLK_A = ClockSignal("A"), i_CLK_B = 0, i_WEN_A = wen, i_WEN_B = 0, - i_REN_A = ren, + i_REN_A = renA, i_REN_B = 0, i_BE_A = be_A, i_BE_B = Replicate(0,4), @@ -1490,13 +1509,23 @@ def __init__(self, write_width_A, write_width_B, read_width_A, read_width_B, mem # -------------------------------------------------------------------------------------------- # Simple Dual Port RAM elif (memory_type == "Simple_Dual_Port"): - self.comb += If((self.ren_B_reg), self.dout_B_.eq(self.dout_B)).Else(self.dout_B_.eq(self.dout_B_reg)) - if (common_clk == 1): - self.sync += If(self.ren_B_reg, self.dout_B_reg.eq(self.dout_B)) - self.sync += self.ren_B_reg.eq(self.ren_B) - else: - self.sync.B += If(self.ren_B_reg, self.dout_B_reg.eq(self.dout_B)) - self.sync.B += self.ren_B_reg.eq(self.ren_B) + if (op_mode in ["No_Change", "Read_First"]): + self.comb += If((self.ren_B_reg), self.dout_B_.eq(self.dout_B)).Else(self.dout_B_.eq(self.dout_B_reg)) + if (common_clk == 1): + self.sync += If(self.ren_B_reg, self.dout_B_reg.eq(self.dout_B)) + self.sync += self.ren_B_reg.eq(self.ren_B) + else: + self.sync.B += If(self.ren_B_reg, self.dout_B_reg.eq(self.dout_B)) + self.sync.B += self.ren_B_reg.eq(self.ren_B) + else: # WRITE_FIRST + self.comb += If((self.wen_A_reg), self.dout_B_.eq(self.din_A_reg)).Else(self.dout_B_.eq(self.dout_B)) + if (common_clk == 1): + self.sync += self.wen_A_reg.eq(self.wen_A) + self.sync += self.din_A_reg.eq(self.din_A) + else: + self.sync.A += self.wen_A_reg.eq(self.wen_A) + self.sync.A += self.din_A_reg.eq(self.din_A) + if (write_width_A == read_width_B): # Symmetric read_loop = m y = write_width_A - 36*(n-1) @@ -1629,23 +1658,27 @@ def __init__(self, write_width_A, write_width_B, read_width_A, read_width_B, mem addr_reg_mux = {} if (write_depth_A == 1024 and read_width_B <= 36): for i in range(m): - ren_mux[i] = self.ren_B1.eq(Cat(Replicate(0,i), self.ren_B)) + if (op_mode in ["No_Change", "Read_First"]): + ren_mux[i] = self.ren_B1.eq(Cat(Replicate(0,i), self.ren_B)) addr_reg_mux[i] = self.addr_reg_B.eq(i) elif (write_depth_A == 2048 and read_width_B <= 18): for i in range(m): - ren_mux[i] = self.ren_B1.eq(Cat(Replicate(0,i), self.ren_B)) + if (op_mode in ["No_Change", "Read_First"]): + ren_mux[i] = self.ren_B1.eq(Cat(Replicate(0,i), self.ren_B)) addr_reg_mux[i] = self.addr_reg_B.eq(i) elif (write_depth_A == 4096 and read_width_B <= 9): for i in range(m): - ren_mux[i] = self.ren_B1.eq(Cat(Replicate(0,i), self.ren_B)) + if (op_mode in ["No_Change", "Read_First"]): + ren_mux[i] = self.ren_B1.eq(Cat(Replicate(0,i), self.ren_B)) addr_reg_mux[i] = self.addr_reg_B.eq(i) elif (write_depth_A in [8192, 16384, 32768]): if (read_width_B >= 9): for i in range(n * int(write_width_A/read_width_B)): - ren_mux[i] = self.ren_B1.eq(Cat(Replicate(0,i), self.ren_B)) + if (op_mode in ["No_Change", "Read_First"]): + ren_mux[i] = self.ren_B1.eq(Cat(Replicate(0,i), self.ren_B)) addr_reg_mux[i] = self.addr_reg_B.eq(i) if (m > 1 or n > 1): @@ -1655,7 +1688,8 @@ def __init__(self, write_width_A, write_width_B, read_width_A, read_width_B, mem else: if (write_width_A > read_width_B): for i in range(math.ceil(write_width_A/read_width_B)): - ren_mux[i] = self.ren_B1.eq(Cat(Replicate(0,i), self.ren_B)) + if (op_mode in ["No_Change", "Read_First"]): + ren_mux[i] = self.ren_B1.eq(Cat(Replicate(0,i), self.ren_B)) addr_reg_mux[i] = self.addr_reg_B.eq(i) if (m > 1): @@ -1746,7 +1780,8 @@ def __init__(self, write_width_A, write_width_B, read_width_A, read_width_B, mem if (read_depth_B >= 8192): n_temp = int(read_depth_B/4096) for i in range(n_temp): - ren_mux[i] = self.ren_B1.eq(Cat(Replicate(0,i), self.ren_B)) + if (op_mode in ["No_Change", "Read_First"]): + ren_mux[i] = self.ren_B1.eq(Cat(Replicate(0,i), self.ren_B)) dout_mux[i] = self.addr_reg_B.eq(i) if read_depth_B <= 1024 or read_depth_B in [2048, 4096]: @@ -2254,6 +2289,11 @@ def __init__(self, write_width_A, write_width_B, read_width_A, read_width_B, mem write_data_A = self.din_A[(j*1):((j*1)+1)] w_parity_A = Replicate(0,4) + if (op_mode == "Read_First"): + renB = ren + elif (op_mode == "No_Change" or op_mode == "Write_First"): + renB = ~self.wen_A + # Module instance. # ---------------- self.specials += Instance("TDP_RAM36K", name= "SDP_MEM", @@ -2272,7 +2312,7 @@ def __init__(self, write_width_A, write_width_B, read_width_A, read_width_B, mem i_WEN_A = wen, i_WEN_B = 0, i_REN_A = 0, - i_REN_B = ren, + i_REN_B = renB, i_BE_A = be_A, i_BE_B = Replicate(0,4), i_ADDR_A = address_A, @@ -2297,20 +2337,36 @@ def __init__(self, write_width_A, write_width_B, read_width_A, read_width_B, mem ################################################################################################# ################################################################################################# elif (memory_type == "True_Dual_Port"): - - self.comb += If((self.ren_A_reg), self.dout_A_.eq(self.dout_A)).Else(self.dout_A_.eq(self.dout_A_reg)) - self.comb += If((self.ren_B_reg), self.dout_B_.eq(self.dout_B)).Else(self.dout_B_.eq(self.dout_B_reg)) - if (common_clk == 1): - self.sync += If(self.ren_A_reg, self.dout_A_reg.eq(self.dout_A)) - self.sync += self.ren_A_reg.eq(self.ren_A) - self.sync += If(self.ren_B_reg, self.dout_B_reg.eq(self.dout_B)) - self.sync += self.ren_B_reg.eq(self.ren_B) - else: - self.sync.A += If(self.ren_A_reg, self.dout_A_reg.eq(self.dout_A)) - self.sync.A += self.ren_A_reg.eq(self.ren_A) - self.sync.B += If(self.ren_B_reg, self.dout_B_reg.eq(self.dout_B)) - self.sync.B += self.ren_B_reg.eq(self.ren_B) - + ############################################################################################# + # Block RAM Operational Modes + ############################################################################################# + if (op_mode in ["No_Change", "Read_First"]): + self.comb += If((self.ren_A_reg), self.dout_A_.eq(self.dout_A)).Else(self.dout_A_.eq(self.dout_A_reg)) + self.comb += If((self.ren_B_reg), self.dout_B_.eq(self.dout_B)).Else(self.dout_B_.eq(self.dout_B_reg)) + if (common_clk == 1): + self.sync += If(self.ren_A_reg, self.dout_A_reg.eq(self.dout_A)) + self.sync += self.ren_A_reg.eq(self.ren_A) + self.sync += If(self.ren_B_reg, self.dout_B_reg.eq(self.dout_B)) + self.sync += self.ren_B_reg.eq(self.ren_B) + else: + self.sync.A += If(self.ren_A_reg, self.dout_A_reg.eq(self.dout_A)) + self.sync.A += self.ren_A_reg.eq(self.ren_A) + self.sync.B += If(self.ren_B_reg, self.dout_B_reg.eq(self.dout_B)) + self.sync.B += self.ren_B_reg.eq(self.ren_B) + else: # Write_First + self.comb += If((self.wen_A_reg), self.dout_A_.eq(self.din_A_reg)).Else(self.dout_A_.eq(self.dout_A)) + self.comb += If((self.wen_B_reg), self.dout_B_.eq(self.din_B_reg)).Else(self.dout_B_.eq(self.dout_B)) + if (common_clk == 1): + self.sync += self.wen_A_reg.eq(self.wen_A) + self.sync += self.din_A_reg.eq(self.din_A) + self.sync += self.wen_B_reg.eq(self.wen_B) + self.sync += self.din_B_reg.eq(self.din_B) + else: + self.sync.A += self.wen_A_reg.eq(self.wen_A) + self.sync.A += self.din_A_reg.eq(self.din_A) + self.sync.B += self.wen_B_reg.eq(self.wen_B) + self.sync.B += self.din_B_reg.eq(self.din_B) + write_ratio_A = math.ceil(math.log2(large_width / write_width_A)) write_ratio_B = math.ceil(math.log2(large_width / write_width_B)) read_ratio_A = math.ceil(math.log2(large_width / read_width_A)) @@ -2558,7 +2614,8 @@ def __init__(self, write_width_A, write_width_B, read_width_A, read_width_B, mem for j in range(n): for i in range(read_loop_A): addr_reg_mux_A[i] = self.addr_reg_A.eq(i) - ren_mux_A[i] = self.ren_A1.eq(Cat(Replicate(0,i), self.ren_A)) + if (op_mode in ["No_Change", "Read_First"]): + ren_mux_A[i] = self.ren_A1.eq(Cat(Replicate(0,i), self.ren_A)) if (m > 1 and n == 1): # when write depth is 1024 and width greater than 36 if read_width_A == 9: self.comb += Case(self.addr_A[2:read_ratio_A+n_log], ren_mux_A) @@ -2624,7 +2681,8 @@ def __init__(self, write_width_A, write_width_B, read_width_A, read_width_B, mem for j in range(n): for i in range(read_loop_A): addr_reg_mux_A[i] = self.addr_reg_A.eq(i) - ren_mux_A[i] = self.ren_A1.eq(Cat(Replicate(0,i), self.ren_A)) + if (op_mode in ["No_Change", "Read_First"]): + ren_mux_A[i] = self.ren_A1.eq(Cat(Replicate(0,i), self.ren_A)) if read_width_A == 9: self.comb += Case(self.addr_A[msb_read_A-n_log:msb_read_A], ren_mux_A) if common_clk == 1: @@ -2651,7 +2709,8 @@ def __init__(self, write_width_A, write_width_B, read_width_A, read_width_B, mem for j in range(n): for i in range(read_loop_B): addr_reg_mux_B[i] = self.addr_reg_B.eq(i) - ren_mux_B[i] = self.ren_B1.eq(Cat(Replicate(0,i), self.ren_B)) + if (op_mode in ["No_Change", "Read_First"]): + ren_mux_B[i] = self.ren_B1.eq(Cat(Replicate(0,i), self.ren_B)) if (n == 1 and m > 1): # when write depth is 1024 and width greater than 36 if read_width_B == 9: self.comb += Case(self.addr_B[2:read_ratio_B+n_log], ren_mux_B) @@ -2716,7 +2775,8 @@ def __init__(self, write_width_A, write_width_B, read_width_A, read_width_B, mem for j in range(n): for i in range(read_loop_B): addr_reg_mux_B[i] = self.addr_reg_B.eq(i) - ren_mux_B[i] = self.ren_B1.eq(Cat(Replicate(0,i), self.ren_B)) + if (op_mode in ["No_Change", "Read_First"]): + ren_mux_B[i] = self.ren_B1.eq(Cat(Replicate(0,i), self.ren_B)) if read_width_B == 9: self.comb += Case(self.addr_B[msb_read_B-n_log:msb_read_B], ren_mux_B) if common_clk == 1: @@ -2936,6 +2996,16 @@ def __init__(self, write_width_A, write_width_B, read_width_A, read_width_B, mem k = (j // write_temp_B) + (i * (m // write_temp_B)) wen_B = self.wen_B1[k] + ############################################################################################# + # Block RAM Operational Mode + ############################################################################################# + if (op_mode == "Read_First"): + renA = ren_A + renB = ren_B + elif (op_mode == "No_Change" or op_mode == "Write_First"): + renA = ~self.wen_A + renB = ~self.wen_B + ############################################################################################# # True Dual Port Instance ############################################################################################# @@ -2956,8 +3026,8 @@ def __init__(self, write_width_A, write_width_B, read_width_A, read_width_B, mem i_CLK_B = clock2, i_WEN_A = wen_A, i_WEN_B = wen_B, - i_REN_A = ren_A, - i_REN_B = ren_B, + i_REN_A = renA, + i_REN_B = renB, i_BE_A = be_A, i_BE_B = be_B, i_ADDR_A = self.address_A, diff --git a/rapidsilicon/ip/on_chip_memory/v1_0/litex_wrapper/on_chip_memory_litex_wrapper_symmetric.py b/rapidsilicon/ip/on_chip_memory/v1_0/litex_wrapper/on_chip_memory_litex_wrapper_symmetric.py index e90ac986..d8be3b95 100644 --- a/rapidsilicon/ip/on_chip_memory/v1_0/litex_wrapper/on_chip_memory_litex_wrapper_symmetric.py +++ b/rapidsilicon/ip/on_chip_memory/v1_0/litex_wrapper/on_chip_memory_litex_wrapper_symmetric.py @@ -407,7 +407,7 @@ def memory_init(self, file_path, file_extension): self.logger.info(f"===================================================") return INIT, INIT_PARITY - def __init__(self, data_width, memory_type, common_clk, write_depth, memory_mapping, file_path_hex, file_extension, byte_write_enable): + def __init__(self, data_width, memory_type, common_clk, write_depth, memory_mapping, file_path_hex, file_extension, byte_write_enable, op_mode): self.write_depth = write_depth self.data_width = data_width @@ -435,11 +435,13 @@ def __init__(self, data_width, memory_type, common_clk, write_depth, memory_mapp self.addr_B = Signal(math.ceil(math.log2(write_depth))) self.din_A = Signal(data_width) + self.din_A_reg = Signal(data_width) self.dout_A = Signal(data_width) self.dout_A_ = Signal(data_width) self.dout_A_reg = Signal(data_width) self.din_B = Signal(data_width) + self.din_B_reg = Signal(data_width) self.dout_B = Signal(data_width) self.dout_B_ = Signal(data_width) self.dout_B_reg = Signal(data_width) @@ -509,9 +511,11 @@ def __init__(self, data_width, memory_type, common_clk, write_depth, memory_mapp # External write/read enables self.wen_A = Signal(1) + self.wen_A_reg = Signal(1) self.ren_A = Signal(1) self.ren_A_reg = Signal(1) self.wen_B = Signal(1) + self.wen_B_reg = Signal(1) self.ren_B = Signal(1) self.ren_B_reg = Signal(1) @@ -541,9 +545,14 @@ def __init__(self, data_width, memory_type, common_clk, write_depth, memory_mapp if (write_depth in [1024, 2048, 4096, 8192, 16384, 32768]): # Single Port RAM if (memory_type == "Single_Port"): - self.comb += If((self.ren_A_reg), self.dout_A_.eq(self.dout_A)).Else(self.dout_A_.eq(self.dout_A_reg)) - self.sync.A += If(self.ren_A_reg, self.dout_A_reg.eq(self.dout_A)) - self.sync.A += self.ren_A_reg.eq(self.ren_A) + if (op_mode in ["No_Change", "Read_First"]): + self.comb += If((self.ren_A_reg), self.dout_A_.eq(self.dout_A)).Else(self.dout_A_.eq(self.dout_A_reg)) + self.sync.A += If(self.ren_A_reg, self.dout_A_reg.eq(self.dout_A)) + self.sync.A += self.ren_A_reg.eq(self.ren_A) + else: # Write_First + self.comb += If((self.wen_A_reg), self.dout_A_.eq(self.din_A_reg)).Else(self.dout_A_.eq(self.dout_A)) + self.sync.A += self.wen_A_reg.eq(self.wen_A) + self.sync.A += self.din_A_reg.eq(self.din_A) for j in range(n): for i in range(m): if (write_depth <= 1024): @@ -562,13 +571,23 @@ def __init__(self, data_width, memory_type, common_clk, write_depth, memory_mapp # Simple Dual Port RAM elif (memory_type == "Simple_Dual_Port"): - self.comb += If((self.ren_B_reg), self.dout_B_.eq(self.dout_B)).Else(self.dout_B_.eq(self.dout_B_reg)) - if (common_clk == 1): - self.sync += If(self.ren_B_reg, self.dout_B_reg.eq(self.dout_B)) - self.sync += self.ren_B_reg.eq(self.ren_B) - else: - self.sync.B += If(self.ren_B_reg, self.dout_B_reg.eq(self.dout_B)) - self.sync.B += self.ren_B_reg.eq(self.ren_B) + if (op_mode in ["No_Change", "Read_First"]): + self.comb += If((self.ren_B_reg), self.dout_B_.eq(self.dout_B)).Else(self.dout_B_.eq(self.dout_B_reg)) + if (common_clk == 1): + self.sync += If(self.ren_B_reg, self.dout_B_reg.eq(self.dout_B)) + self.sync += self.ren_B_reg.eq(self.ren_B) + else: + self.sync.B += If(self.ren_B_reg, self.dout_B_reg.eq(self.dout_B)) + self.sync.B += self.ren_B_reg.eq(self.ren_B) + else: # Write_First + self.comb += If((self.wen_A_reg), self.dout_B_.eq(self.din_A_reg)).Else(self.dout_B_.eq(self.dout_B)) + if (common_clk == 1): + self.sync += self.wen_A_reg.eq(self.wen_A) + self.sync += self.din_A_reg.eq(self.din_A) + else: + self.sync.A += self.wen_A_reg.eq(self.wen_A) + self.sync.A += self.din_A_reg.eq(self.din_A) + for j in range(n): for i in range(m): if (write_depth <= 1024): @@ -587,18 +606,33 @@ def __init__(self, data_width, memory_type, common_clk, write_depth, memory_mapp # True Dual Port RAM elif (memory_type == "True_Dual_Port"): - self.comb += If((self.ren_A_reg), self.dout_A_.eq(self.dout_A)).Else(self.dout_A_.eq(self.dout_A_reg)) - self.comb += If((self.ren_B_reg), self.dout_B_.eq(self.dout_B)).Else(self.dout_B_.eq(self.dout_B_reg)) - if (common_clk == 1): - self.sync += If(self.ren_A_reg, self.dout_A_reg.eq(self.dout_A)) - self.sync += self.ren_A_reg.eq(self.ren_A) - self.sync += If(self.ren_B_reg, self.dout_B_reg.eq(self.dout_B)) - self.sync += self.ren_B_reg.eq(self.ren_B) - else: - self.sync.A += If(self.ren_A_reg, self.dout_A_reg.eq(self.dout_A)) - self.sync.A += self.ren_A_reg.eq(self.ren_A) - self.sync.B += If(self.ren_B_reg, self.dout_B_reg.eq(self.dout_B)) - self.sync.B += self.ren_B_reg.eq(self.ren_B) + if (op_mode in ["No_Change", "Read_First"]): + self.comb += If((self.ren_A_reg), self.dout_A_.eq(self.dout_A)).Else(self.dout_A_.eq(self.dout_A_reg)) + self.comb += If((self.ren_B_reg), self.dout_B_.eq(self.dout_B)).Else(self.dout_B_.eq(self.dout_B_reg)) + if (common_clk == 1): + self.sync += If(self.ren_A_reg, self.dout_A_reg.eq(self.dout_A)) + self.sync += self.ren_A_reg.eq(self.ren_A) + self.sync += If(self.ren_B_reg, self.dout_B_reg.eq(self.dout_B)) + self.sync += self.ren_B_reg.eq(self.ren_B) + else: + self.sync.A += If(self.ren_A_reg, self.dout_A_reg.eq(self.dout_A)) + self.sync.A += self.ren_A_reg.eq(self.ren_A) + self.sync.B += If(self.ren_B_reg, self.dout_B_reg.eq(self.dout_B)) + self.sync.B += self.ren_B_reg.eq(self.ren_B) + else: #Write_First + self.comb += If((self.wen_A_reg), self.dout_A_.eq(self.din_A_reg)).Else(self.dout_A_.eq(self.dout_A)) + self.comb += If((self.wen_B_reg), self.dout_B_.eq(self.din_B_reg)).Else(self.dout_B_.eq(self.dout_B)) + if (common_clk == 1): + self.sync += self.wen_A_reg.eq(self.wen_A) + self.sync += self.din_A_reg.eq(self.din_A) + self.sync += self.wen_B_reg.eq(self.wen_B) + self.sync += self.din_B_reg.eq(self.din_B) + else: + self.sync.A += self.wen_A_reg.eq(self.wen_A) + self.sync.A += self.din_A_reg.eq(self.din_A) + self.sync.B += self.wen_B_reg.eq(self.wen_B) + self.sync.B += self.din_B_reg.eq(self.din_B) + for i in range(m): if (write_depth <= 1024): self.comb += self.dout_A[(i*36):((i*36)+36)].eq(Cat(self.bram_out_A[i][0:8], self.rparity_A[i][0], self.bram_out_A[i][8:16], self.rparity_A[i][1], @@ -923,6 +957,11 @@ def __init__(self, data_width, memory_type, common_clk, write_depth, memory_mapp else: wen = self.wen_A1[j] + if (op_mode == "Read_First"): + ren = self.ren_A + elif (op_mode == "No_Change" or op_mode == "Write_First"): + ren = ~self.wen_A + # Module instance. # ---------------- self.specials += Instance("TDP_RAM36K", name= "SP_MEM", @@ -936,11 +975,11 @@ def __init__(self, data_width, memory_type, common_clk, write_depth, memory_mapp p_READ_WIDTH_B = param_read_width_A, # Ports. # ----------- - i_CLK_A = clock1, + i_CLK_A = ClockSignal("A"), i_CLK_B = 0, i_WEN_A = wen, i_WEN_B = 0, - i_REN_A = self.ren_A, + i_REN_A = ren, i_REN_B = 0, i_BE_A = be_A, i_BE_B = Replicate(0,4), @@ -1159,6 +1198,11 @@ def __init__(self, data_width, memory_type, common_clk, write_depth, memory_mapp wen = self.wen_A else: wen = self.wen_A1[j] + + if (op_mode == "Read_First"): + ren = self.ren_B + elif (op_mode == "No_Change" or op_mode == "Write_First"): + ren = ~self.wen_A # Module instance. # ---------------- @@ -1178,7 +1222,7 @@ def __init__(self, data_width, memory_type, common_clk, write_depth, memory_mapp i_WEN_A = wen, i_WEN_B = 0, i_REN_A = 0, - i_REN_B = self.ren_B, + i_REN_B = ren, i_BE_A = be_A, i_BE_B = Replicate(0,4), i_ADDR_A = address_A, @@ -1485,6 +1529,13 @@ def __init__(self, data_width, memory_type, common_clk, write_depth, memory_mapp wen_A = self.wen_A1[j] wen_B = self.wen_B1[j] + if (op_mode == "Read_First"): + renA = self.ren_A + renB = self.ren_B + elif (op_mode == "No_Change" or op_mode == "Write_First"): + renA = ~self.wen_A + renB = ~self.wen_B + # Module instance. # ---------------- self.specials += Instance("TDP_RAM36K", name= "TDP_MEM", @@ -1502,8 +1553,8 @@ def __init__(self, data_width, memory_type, common_clk, write_depth, memory_mapp i_CLK_B = clock2, i_WEN_A = wen_A, i_WEN_B = wen_B, - i_REN_A = self.ren_A, - i_REN_B = self.ren_B, + i_REN_A = renA, + i_REN_B = renB, i_BE_A = be_A, i_BE_B = be_B, i_ADDR_A = address_A, @@ -1520,9 +1571,16 @@ def __init__(self, data_width, memory_type, common_clk, write_depth, memory_mapp # Distributed RAM else: + # Operational modes of memory + operation_mode = { + "Read_First" : 0, + "Write_First" : 1, + "No_Change" : 2 + }[op_mode] + self.specials.memory = Memory(width=data_width, depth=write_depth) if (memory_type == "Single_Port"): - self.port = self.memory.get_port(write_capable=True, async_read=False, mode=WRITE_FIRST, has_re=True, clock_domain="A") + self.port = self.memory.get_port(write_capable=True, async_read=False, mode=operation_mode, has_re=True, clock_domain="A") self.specials += self.port self.comb += [ @@ -1535,14 +1593,14 @@ def __init__(self, data_width, memory_type, common_clk, write_depth, memory_mapp elif (memory_type == "Simple_Dual_Port"): if (common_clk == 1): - self.port_A = self.memory.get_port(write_capable=True, async_read=True, mode=WRITE_FIRST, has_re=False, clock_domain="sys") + self.port_A = self.memory.get_port(write_capable=True, async_read=True, mode=operation_mode, has_re=False, clock_domain="sys") self.specials += self.port_A - self.port_B = self.memory.get_port(write_capable=False, async_read=False, mode=WRITE_FIRST, has_re=True, clock_domain="sys") + self.port_B = self.memory.get_port(write_capable=False, async_read=False, mode=operation_mode, has_re=True, clock_domain="sys") self.specials += self.port_B else: - self.port_A = self.memory.get_port(write_capable=True, async_read=True, mode=WRITE_FIRST, has_re=False, clock_domain="A") + self.port_A = self.memory.get_port(write_capable=True, async_read=True, mode=operation_mode, has_re=False, clock_domain="A") self.specials += self.port_A - self.port_B = self.memory.get_port(write_capable=False, async_read=False, mode=WRITE_FIRST, has_re=True, clock_domain="B") + self.port_B = self.memory.get_port(write_capable=False, async_read=False, mode=operation_mode, has_re=True, clock_domain="B") self.specials += self.port_B self.comb += [ @@ -1556,14 +1614,14 @@ def __init__(self, data_width, memory_type, common_clk, write_depth, memory_mapp elif (memory_type == "True_Dual_Port"): if (common_clk == 1): - self.port_A = self.memory.get_port(write_capable=True, async_read=False, mode=WRITE_FIRST, has_re=True, clock_domain="sys") + self.port_A = self.memory.get_port(write_capable=True, async_read=False, mode=operation_mode, has_re=True, clock_domain="sys") self.specials += self.port_A - self.port_B = self.memory.get_port(write_capable=True, async_read=False, mode=WRITE_FIRST, has_re=True, clock_domain="sys") + self.port_B = self.memory.get_port(write_capable=True, async_read=False, mode=operation_mode, has_re=True, clock_domain="sys") self.specials += self.port_B else: - self.port_A = self.memory.get_port(write_capable=True, async_read=False, mode=WRITE_FIRST, has_re=True, clock_domain="A") + self.port_A = self.memory.get_port(write_capable=True, async_read=False, mode=operation_mode, has_re=True, clock_domain="A") self.specials += self.port_A - self.port_B = self.memory.get_port(write_capable=True, async_read=False, mode=WRITE_FIRST, has_re=True, clock_domain="B") + self.port_B = self.memory.get_port(write_capable=True, async_read=False, mode=operation_mode, has_re=True, clock_domain="B") self.specials += self.port_B self.comb += [ diff --git a/rapidsilicon/ip/on_chip_memory/v1_0/on_chip_memory_gen.py b/rapidsilicon/ip/on_chip_memory/v1_0/on_chip_memory_gen.py index bccdaf5d..70318330 100755 --- a/rapidsilicon/ip/on_chip_memory/v1_0/on_chip_memory_gen.py +++ b/rapidsilicon/ip/on_chip_memory/v1_0/on_chip_memory_gen.py @@ -91,17 +91,9 @@ def get_clkin_ios(port_type, data_width, write_depth, memory_type, write_width_A ("be_B", 0, Pins(math.ceil(write_width_B/9))) ] -def depth_param_limit(data_width, device_dic): - if (data_width > 36): - Max_Depth = math.ceil(int(device_dic['bram'] * 1024) / math.ceil(data_width/36)) - else: - Max_Depth = device_dic['bram'] * 1024 - - return Max_Depth - # on_chip_memory Wrapper ---------------------------------------------------------------------------------- class OCMWrapper(Module): - def __init__(self, platform, write_width_A, write_width_B, read_width_A, read_width_B, memory_type, write_depth, data_width, common_clk, port_type, write_depth_A, read_depth_A, write_depth_B, read_depth_B, memory_mapping, file_path_hex, file_extension, byte_write_enable, op_mode): + def __init__(self, platform, write_width_A, write_width_B, read_width_A, read_width_B, memory_type, write_depth, data_width, common_clk, port_type, write_depth_A, read_depth_A, write_depth_B, read_depth_B, memory_mapping, file_path_hex, file_extension, byte_write_enable): # Clocking --------------------------------------------------------------------------------- platform.add_extension(get_clkin_ios(port_type, data_width, write_depth, memory_type, write_width_A, write_width_B, read_width_A, read_width_B, write_depth_A, write_depth_B, read_depth_A, read_depth_B)) self.clock_domains.cd_sys = ClockDomain(reset_less = True) @@ -109,9 +101,9 @@ def __init__(self, platform, write_width_A, write_width_B, read_width_A, read_wi self.clock_domains.B = ClockDomain(reset_less = True) if port_type == "Asymmetric": - self.submodules.sp = ram = OCM_ASYM(write_width_A, write_width_B, read_width_A, read_width_B, memory_type, common_clk, write_depth_A, read_depth_A, write_depth_B, read_depth_B, memory_mapping, file_path_hex, file_extension, byte_write_enable, op_mode) + self.submodules.sp = ram = OCM_ASYM(write_width_A, write_width_B, read_width_A, read_width_B, memory_type, common_clk, write_depth_A, read_depth_A, write_depth_B, read_depth_B, memory_mapping, file_path_hex, file_extension, byte_write_enable) else: - self.submodules.sp = ram = OCM_SYM(data_width, memory_type, common_clk, write_depth, memory_mapping, file_path_hex, file_extension, byte_write_enable, op_mode) + self.submodules.sp = ram = OCM_SYM(data_width, memory_type, common_clk, write_depth, memory_mapping, file_path_hex, file_extension, byte_write_enable) self.M = ram.m self.N = ram.n @@ -202,7 +194,6 @@ def main(): core_string_param_group.add_argument("--memory_type", type=str, default="Single_Port", choices=["Single_Port", "Simple_Dual_Port", "True_Dual_Port"], help="RAM Type") core_string_param_group.add_argument("--port_type", type=str, default="Symmetric", choices=["Symmetric", "Asymmetric"], help="Ports Type") core_string_param_group.add_argument("--memory_mapping", type=str, default="Block_RAM", choices=["Block_RAM", "Distributed_RAM"], help="Memory mapping on Block RAM and Distributed RAM (LUTs)") - core_string_param_group.add_argument("--op_mode", type=str, default="Read_First", choices=["No_Change", "Write_First", "Read_First"], help="Operation Mode of Memory") # Core bool value parameters. core_bool_param_group = parser.add_argument_group(title="Core bool parameters") @@ -247,13 +238,6 @@ def main(): 'Description' : 'On Chip Memory Generator is an IP Core with native interface. This IP Core simplifies the integration of memory elements, allowing designers to generate customized on-chip memory instances that match their specific requirements. It include the ability to configure memory size, data width, organization (e.g., single-port, dual-port), and various memory types (e.g., single-ported RAM, simple dual-port RAM and true dual port RAM).'} } - device_dic = { - 'dsp' : 0, - 'bram' : 0 - } - - summary = {} - # Import JSON (Optional) ----------------------------------------------------------------------- if args.json: args = rs_builder.import_args_from_json(parser=parser, json_filename=args.json) @@ -262,71 +246,50 @@ def main(): file_path = os.path.dirname(os.path.realpath(__file__)) rs_builder.copy_images(file_path) - # bram device resources - device_dic = rs_builder.parse_device(args.device_dic, args.device) - - if (args.port_type == "Symmetric"): - if (args.byte_write_enable == True): - data_width = args.DATA_WIDTH - else: - data_width = args.data_width - else: # Asymmetric - if (args.memory_type == "Single_Port"): - data_width = max(args.write_width_A, args.read_width_A) - elif (args.memory_type == "Simple_Dual_Port"): - data_width = max(args.write_width_A, args.read_width_B) - elif (args.memory_type == "True_Dual_Port"): - data_width = max(args.write_width_A, args.read_width_A, args.write_width_B, args.read_width_B) + if (args.byte_write_enable == True): + option_strings_to_remove = ['--data_width'] + parser._actions = [action for action in parser._actions if action.option_strings and action.option_strings[0] not in option_strings_to_remove] + else: + option_strings_to_remove = ['--DATA_WIDTH'] + parser._actions = [action for action in parser._actions if action.option_strings and action.option_strings[0] not in option_strings_to_remove] - Max_Depth = depth_param_limit(data_width, device_dic) + if (args.memory_mapping == "Distributed_RAM"): + option_strings_to_remove = ['--byte_write_enable'] + parser._actions = [action for action in parser._actions if action.option_strings and action.option_strings[0] not in option_strings_to_remove] + if (args.write_width_A >= 288 or args.read_width_A >= 288 or args.write_width_B >= 288 or args.read_width_B >= 288): + parser._actions[11].choices = [1024, 2048, 4096, 8192] + if (args.port_type == "Symmetric"): - parser._actions[14].choices = range(2, Max_Depth+1) - parser._actions[14].default = Max_Depth + option_strings_to_remove = ['--write_width_A', '--write_width_B', '--read_width_A', '--read_width_B', '--write_depth_A'] + parser._actions = [action for action in parser._actions if action.option_strings and action.option_strings[0] not in option_strings_to_remove] else: - depth_list = [1024, 2048, 4096, 8192, 16384, 32768] - parser._actions[12].choices = [value for value in depth_list if value <= Max_Depth] - parser._actions[12].default = Max_Depth + option_strings_to_remove = ['--DATA_WIDTH', '--data_width','--write_depth'] + parser._actions = [action for action in parser._actions if action.option_strings and action.option_strings[0] not in option_strings_to_remove] - if (device_dic['bram'] > 0): - if (args.byte_write_enable == True): - option_strings_to_remove = ['--data_width'] - parser._actions = [action for action in parser._actions if action.option_strings and action.option_strings[0] not in option_strings_to_remove] - else: - option_strings_to_remove = ['--DATA_WIDTH'] - parser._actions = [action for action in parser._actions if action.option_strings and action.option_strings[0] not in option_strings_to_remove] - if (args.memory_mapping == "Distributed_RAM"): - option_strings_to_remove = ['--byte_write_enable'] - parser._actions = [action for action in parser._actions if action.option_strings and action.option_strings[0] not in option_strings_to_remove] - if (args.write_width_A >= 288 or args.read_width_A >= 288 or args.write_width_B >= 288 or args.read_width_B >= 288): - parser._actions[12].choices = [1024, 2048, 4096, 8192] - if (args.port_type == "Symmetric"): - option_strings_to_remove = ['--write_width_A', '--write_width_B', '--read_width_A', '--read_width_B', '--write_depth_A'] - parser._actions = [action for action in parser._actions if action.option_strings and action.option_strings[0] not in option_strings_to_remove] - else: - option_strings_to_remove = ['--DATA_WIDTH', '--data_width','--write_depth'] - parser._actions = [action for action in parser._actions if action.option_strings and action.option_strings[0] not in option_strings_to_remove] - if (args.memory_type in ["Single_Port"]): - dep_dict.update({ - 'common_clk': 'True' - }) - option_strings_to_remove = ['--write_width_B', '--read_width_B'] - parser._actions = [action for action in parser._actions if action.option_strings and action.option_strings[0] not in option_strings_to_remove] - if (args.write_width_A != args.read_width_A): - parser._actions[3].choices = ["Block_RAM"] - elif (args.memory_type in ["Simple_Dual_Port"]): - option_strings_to_remove = ['--write_width_B', '--read_width_A'] - parser._actions = [action for action in parser._actions if action.option_strings and action.option_strings[0] not in option_strings_to_remove] - if (args.write_width_A != args.read_width_B): - parser._actions[3].choices = ["Block_RAM"] - elif (args.memory_type in ["True_Dual_Port"]): - if (args.write_width_A != args.read_width_A or args.write_width_A != args.write_width_B or args.write_width_B != args.read_width_B): - parser._actions[3].choices = ["Block_RAM"] - else: - parser._actions = [action for action in parser._actions if not action.option_strings] + if (args.memory_type in ["Single_Port"]): + dep_dict.update({ + 'common_clk': 'True' + }) + option_strings_to_remove = ['--write_width_B', '--read_width_B'] + parser._actions = [action for action in parser._actions if action.option_strings and action.option_strings[0] not in option_strings_to_remove] + if (args.write_width_A != args.read_width_A): + parser._actions[3].choices = ["Block_RAM"] + + elif (args.memory_type in ["Simple_Dual_Port"]): + option_strings_to_remove = ['--write_width_B', '--read_width_A'] + parser._actions = [action for action in parser._actions if action.option_strings and action.option_strings[0] not in option_strings_to_remove] + if (args.write_width_A != args.read_width_B): + parser._actions[3].choices = ["Block_RAM"] + + elif (args.memory_type in ["True_Dual_Port"]): + if (args.write_width_A != args.read_width_A or args.write_width_A != args.write_width_B or args.write_width_B != args.read_width_B): + parser._actions[3].choices = ["Block_RAM"] + #device_dict contains the number of BRAMs and DSP for the device used. + device_dic = rs_builder.parse_device(args.device_path,args.device) # Create Wrapper ------------------------------------------------------------------------------- - platform = OSFPGAPlatform(io=[], toolchain="raptor", device=args.device) + platform = OSFPGAPlatform(io=[], toolchain="raptor", device="gemini") file_extension = os.path.splitext(args.file_path)[1] if (args.memory_type == "Single_Port"): @@ -353,37 +316,38 @@ def main(): memory_mapping = "Block RAM" else: memory_mapping = "Distributed RAM(LUTs)" + + summary = { + "Type of Memory": memory, + "Mapping": memory_mapping, + } - if (device_dic['bram'] > 0): - summary["Type of Memory"] = memory - summary["Mapping"] = memory_mapping - if args.port_type == "Asymmetric": - if (args.memory_type == "Single_Port"): - summary["Address A"] = math.ceil(math.log2(args.write_depth_A)) - elif args.memory_type == "Simple_Dual_Port": - summary["Address A"] = math.ceil(math.log2(args.write_depth_A)) - summary["Address B"] = math.ceil(math.log2(read_depth_B)) - elif args.memory_type == "True_Dual_Port": - if (args.write_depth_A > read_depth_A): # assigning greater value to addr_A port - write_depthA = args.write_depth_A - else: - write_depthA = read_depth_A - if (write_depth_B > read_depth_B): # assigning greater value to addr_B port - write_depthB = write_depth_B - else: - write_depthB = read_depth_B - summary["Address A"] = math.ceil(math.log2(write_depthA)) - summary["Address B"] = math.ceil(math.log2(write_depthB)) - else: - summary["Address"] = math.ceil(math.log2(args.write_depth)) - if (args.memory_type in ["Simple_Dual_Port", "True_Dual_Port"]): - if (args.common_clk == 1): - summary["Synchronization"] = "True" + if args.port_type == "Asymmetric": + if (args.memory_type == "Single_Port"): + summary["Address A"] = math.ceil(math.log2(args.write_depth_A)) + elif args.memory_type == "Simple_Dual_Port": + summary["Address A"] = math.ceil(math.log2(args.write_depth_A)) + summary["Address B"] = math.ceil(math.log2(read_depth_B)) + elif args.memory_type == "True_Dual_Port": + if (args.write_depth_A > read_depth_A): # assigning greater value to addr_A port + write_depthA = args.write_depth_A + else: + write_depthA = read_depth_A + if (write_depth_B > read_depth_B): # assigning greater value to addr_B port + write_depthB = write_depth_B else: - summary["Synchronization"] = "False" + write_depthB = read_depth_B + summary["Address A"] = math.ceil(math.log2(write_depthA)) + summary["Address B"] = math.ceil(math.log2(write_depthB)) else: - summary["WARNING"] = "No BRAMs in selected device. Select a different device with BRAMs." + summary["Address"] = math.ceil(math.log2(args.write_depth)) + if (args.memory_type in ["Simple_Dual_Port", "True_Dual_Port"]): + if (args.common_clk == 1): + summary["Synchronization"] = "True" + else: + summary["Synchronization"] = "False" + if (args.byte_write_enable == True): data = args.DATA_WIDTH else: @@ -406,13 +370,11 @@ def main(): port_type = args.port_type, file_path_hex = args.file_path, file_extension = file_extension, - byte_write_enable = args.byte_write_enable, - op_mode = args.op_mode + byte_write_enable = args.byte_write_enable ) - if (device_dic['bram'] > 0): - if (args.memory_mapping == "Block_RAM"): - summary["Number of BRAMs"] = module.M * module.N + if (args.memory_mapping == "Block_RAM"): + summary["Number of BRAMs"] = module.M * module.N # Export JSON Template (Optional) -------------------------------------------------------------- if args.json_template: From a54a6f34ede31d0bc51f3aa2f2771812cbdf1820 Mon Sep 17 00:00:00 2001 From: moinijaz Date: Wed, 31 Jul 2024 17:28:14 +0500 Subject: [PATCH 5/5] ocm device parsing updated --- .../on_chip_memory/v1_0/on_chip_memory_gen.py | 178 +++++++++++------- 1 file changed, 108 insertions(+), 70 deletions(-) diff --git a/rapidsilicon/ip/on_chip_memory/v1_0/on_chip_memory_gen.py b/rapidsilicon/ip/on_chip_memory/v1_0/on_chip_memory_gen.py index 70318330..c9f9a0ad 100755 --- a/rapidsilicon/ip/on_chip_memory/v1_0/on_chip_memory_gen.py +++ b/rapidsilicon/ip/on_chip_memory/v1_0/on_chip_memory_gen.py @@ -91,9 +91,17 @@ def get_clkin_ios(port_type, data_width, write_depth, memory_type, write_width_A ("be_B", 0, Pins(math.ceil(write_width_B/9))) ] +def depth_param_limit(data_width, device_dic): + if (data_width > 36): + Max_Depth = math.ceil(int(device_dic['bram'] * 1024) / math.ceil(data_width/36)) + else: + Max_Depth = device_dic['bram'] * 1024 + + return Max_Depth + # on_chip_memory Wrapper ---------------------------------------------------------------------------------- class OCMWrapper(Module): - def __init__(self, platform, write_width_A, write_width_B, read_width_A, read_width_B, memory_type, write_depth, data_width, common_clk, port_type, write_depth_A, read_depth_A, write_depth_B, read_depth_B, memory_mapping, file_path_hex, file_extension, byte_write_enable): + def __init__(self, platform, write_width_A, write_width_B, read_width_A, read_width_B, memory_type, write_depth, data_width, common_clk, port_type, write_depth_A, read_depth_A, write_depth_B, read_depth_B, memory_mapping, file_path_hex, file_extension, byte_write_enable, op_mode): # Clocking --------------------------------------------------------------------------------- platform.add_extension(get_clkin_ios(port_type, data_width, write_depth, memory_type, write_width_A, write_width_B, read_width_A, read_width_B, write_depth_A, write_depth_B, read_depth_A, read_depth_B)) self.clock_domains.cd_sys = ClockDomain(reset_less = True) @@ -101,9 +109,9 @@ def __init__(self, platform, write_width_A, write_width_B, read_width_A, read_wi self.clock_domains.B = ClockDomain(reset_less = True) if port_type == "Asymmetric": - self.submodules.sp = ram = OCM_ASYM(write_width_A, write_width_B, read_width_A, read_width_B, memory_type, common_clk, write_depth_A, read_depth_A, write_depth_B, read_depth_B, memory_mapping, file_path_hex, file_extension, byte_write_enable) + self.submodules.sp = ram = OCM_ASYM(write_width_A, write_width_B, read_width_A, read_width_B, memory_type, common_clk, write_depth_A, read_depth_A, write_depth_B, read_depth_B, memory_mapping, file_path_hex, file_extension, byte_write_enable, op_mode) else: - self.submodules.sp = ram = OCM_SYM(data_width, memory_type, common_clk, write_depth, memory_mapping, file_path_hex, file_extension, byte_write_enable) + self.submodules.sp = ram = OCM_SYM(data_width, memory_type, common_clk, write_depth, memory_mapping, file_path_hex, file_extension, byte_write_enable, op_mode) self.M = ram.m self.N = ram.n @@ -194,6 +202,7 @@ def main(): core_string_param_group.add_argument("--memory_type", type=str, default="Single_Port", choices=["Single_Port", "Simple_Dual_Port", "True_Dual_Port"], help="RAM Type") core_string_param_group.add_argument("--port_type", type=str, default="Symmetric", choices=["Symmetric", "Asymmetric"], help="Ports Type") core_string_param_group.add_argument("--memory_mapping", type=str, default="Block_RAM", choices=["Block_RAM", "Distributed_RAM"], help="Memory mapping on Block RAM and Distributed RAM (LUTs)") + core_string_param_group.add_argument("--op_mode", type=str, default="Read_First", choices=["No_Change", "Write_First", "Read_First"], help="Operation Mode of Memory") # Core bool value parameters. core_bool_param_group = parser.add_argument_group(title="Core bool parameters") @@ -238,6 +247,13 @@ def main(): 'Description' : 'On Chip Memory Generator is an IP Core with native interface. This IP Core simplifies the integration of memory elements, allowing designers to generate customized on-chip memory instances that match their specific requirements. It include the ability to configure memory size, data width, organization (e.g., single-port, dual-port), and various memory types (e.g., single-ported RAM, simple dual-port RAM and true dual port RAM).'} } + device_dic = { + 'dsp' : 0, + 'bram' : 0 + } + + summary = {} + # Import JSON (Optional) ----------------------------------------------------------------------- if args.json: args = rs_builder.import_args_from_json(parser=parser, json_filename=args.json) @@ -246,47 +262,68 @@ def main(): file_path = os.path.dirname(os.path.realpath(__file__)) rs_builder.copy_images(file_path) - if (args.byte_write_enable == True): - option_strings_to_remove = ['--data_width'] - parser._actions = [action for action in parser._actions if action.option_strings and action.option_strings[0] not in option_strings_to_remove] - else: - option_strings_to_remove = ['--DATA_WIDTH'] - parser._actions = [action for action in parser._actions if action.option_strings and action.option_strings[0] not in option_strings_to_remove] + # bram & dsp device resources + device_dic = rs_builder.parse_device(args.device_path, args.device) - if (args.memory_mapping == "Distributed_RAM"): - option_strings_to_remove = ['--byte_write_enable'] - parser._actions = [action for action in parser._actions if action.option_strings and action.option_strings[0] not in option_strings_to_remove] + if (args.port_type == "Symmetric"): + if (args.byte_write_enable == True): + data_width = args.DATA_WIDTH + else: + data_width = args.data_width + else: # Asymmetric + if (args.memory_type == "Single_Port"): + data_width = max(args.write_width_A, args.read_width_A) + elif (args.memory_type == "Simple_Dual_Port"): + data_width = max(args.write_width_A, args.read_width_B) + elif (args.memory_type == "True_Dual_Port"): + data_width = max(args.write_width_A, args.read_width_A, args.write_width_B, args.read_width_B) + + Max_Depth = depth_param_limit(data_width, device_dic) - if (args.write_width_A >= 288 or args.read_width_A >= 288 or args.write_width_B >= 288 or args.read_width_B >= 288): - parser._actions[11].choices = [1024, 2048, 4096, 8192] - if (args.port_type == "Symmetric"): - option_strings_to_remove = ['--write_width_A', '--write_width_B', '--read_width_A', '--read_width_B', '--write_depth_A'] - parser._actions = [action for action in parser._actions if action.option_strings and action.option_strings[0] not in option_strings_to_remove] + parser._actions[14].choices = range(2, Max_Depth+1) + parser._actions[14].default = Max_Depth else: - option_strings_to_remove = ['--DATA_WIDTH', '--data_width','--write_depth'] - parser._actions = [action for action in parser._actions if action.option_strings and action.option_strings[0] not in option_strings_to_remove] + depth_list = [1024, 2048, 4096, 8192, 16384, 32768] + parser._actions[12].choices = [value for value in depth_list if value <= Max_Depth] + parser._actions[12].default = Max_Depth - if (args.memory_type in ["Single_Port"]): - dep_dict.update({ - 'common_clk': 'True' - }) - option_strings_to_remove = ['--write_width_B', '--read_width_B'] - parser._actions = [action for action in parser._actions if action.option_strings and action.option_strings[0] not in option_strings_to_remove] - if (args.write_width_A != args.read_width_A): - parser._actions[3].choices = ["Block_RAM"] - - elif (args.memory_type in ["Simple_Dual_Port"]): - option_strings_to_remove = ['--write_width_B', '--read_width_A'] - parser._actions = [action for action in parser._actions if action.option_strings and action.option_strings[0] not in option_strings_to_remove] - if (args.write_width_A != args.read_width_B): - parser._actions[3].choices = ["Block_RAM"] - - elif (args.memory_type in ["True_Dual_Port"]): - if (args.write_width_A != args.read_width_A or args.write_width_A != args.write_width_B or args.write_width_B != args.read_width_B): - parser._actions[3].choices = ["Block_RAM"] - #device_dict contains the number of BRAMs and DSP for the device used. - device_dic = rs_builder.parse_device(args.device_path,args.device) + if (device_dic['bram'] > 0): + if (args.byte_write_enable == True): + option_strings_to_remove = ['--data_width'] + parser._actions = [action for action in parser._actions if action.option_strings and action.option_strings[0] not in option_strings_to_remove] + else: + option_strings_to_remove = ['--DATA_WIDTH'] + parser._actions = [action for action in parser._actions if action.option_strings and action.option_strings[0] not in option_strings_to_remove] + if (args.memory_mapping == "Distributed_RAM"): + option_strings_to_remove = ['--byte_write_enable'] + parser._actions = [action for action in parser._actions if action.option_strings and action.option_strings[0] not in option_strings_to_remove] + if (args.write_width_A >= 288 or args.read_width_A >= 288 or args.write_width_B >= 288 or args.read_width_B >= 288): + parser._actions[12].choices = [1024, 2048, 4096, 8192] + if (args.port_type == "Symmetric"): + option_strings_to_remove = ['--write_width_A', '--write_width_B', '--read_width_A', '--read_width_B', '--write_depth_A'] + parser._actions = [action for action in parser._actions if action.option_strings and action.option_strings[0] not in option_strings_to_remove] + else: + option_strings_to_remove = ['--DATA_WIDTH', '--data_width','--write_depth'] + parser._actions = [action for action in parser._actions if action.option_strings and action.option_strings[0] not in option_strings_to_remove] + if (args.memory_type in ["Single_Port"]): + dep_dict.update({ + 'common_clk': 'True' + }) + option_strings_to_remove = ['--write_width_B', '--read_width_B'] + parser._actions = [action for action in parser._actions if action.option_strings and action.option_strings[0] not in option_strings_to_remove] + if (args.write_width_A != args.read_width_A): + parser._actions[3].choices = ["Block_RAM"] + elif (args.memory_type in ["Simple_Dual_Port"]): + option_strings_to_remove = ['--write_width_B', '--read_width_A'] + parser._actions = [action for action in parser._actions if action.option_strings and action.option_strings[0] not in option_strings_to_remove] + if (args.write_width_A != args.read_width_B): + parser._actions[3].choices = ["Block_RAM"] + elif (args.memory_type in ["True_Dual_Port"]): + if (args.write_width_A != args.read_width_A or args.write_width_A != args.write_width_B or args.write_width_B != args.read_width_B): + parser._actions[3].choices = ["Block_RAM"] + else: + parser._actions = [action for action in parser._actions if not action.option_strings] # Create Wrapper ------------------------------------------------------------------------------- platform = OSFPGAPlatform(io=[], toolchain="raptor", device="gemini") @@ -316,38 +353,37 @@ def main(): memory_mapping = "Block RAM" else: memory_mapping = "Distributed RAM(LUTs)" - - summary = { - "Type of Memory": memory, - "Mapping": memory_mapping, - } - if args.port_type == "Asymmetric": - if (args.memory_type == "Single_Port"): - summary["Address A"] = math.ceil(math.log2(args.write_depth_A)) - elif args.memory_type == "Simple_Dual_Port": - summary["Address A"] = math.ceil(math.log2(args.write_depth_A)) - summary["Address B"] = math.ceil(math.log2(read_depth_B)) - elif args.memory_type == "True_Dual_Port": - if (args.write_depth_A > read_depth_A): # assigning greater value to addr_A port - write_depthA = args.write_depth_A - else: - write_depthA = read_depth_A - if (write_depth_B > read_depth_B): # assigning greater value to addr_B port - write_depthB = write_depth_B + if (device_dic['bram'] > 0): + summary["Type of Memory"] = memory + summary["Mapping"] = memory_mapping + if args.port_type == "Asymmetric": + if (args.memory_type == "Single_Port"): + summary["Address A"] = math.ceil(math.log2(args.write_depth_A)) + elif args.memory_type == "Simple_Dual_Port": + summary["Address A"] = math.ceil(math.log2(args.write_depth_A)) + summary["Address B"] = math.ceil(math.log2(read_depth_B)) + elif args.memory_type == "True_Dual_Port": + if (args.write_depth_A > read_depth_A): # assigning greater value to addr_A port + write_depthA = args.write_depth_A + else: + write_depthA = read_depth_A + if (write_depth_B > read_depth_B): # assigning greater value to addr_B port + write_depthB = write_depth_B + else: + write_depthB = read_depth_B + summary["Address A"] = math.ceil(math.log2(write_depthA)) + summary["Address B"] = math.ceil(math.log2(write_depthB)) + else: + summary["Address"] = math.ceil(math.log2(args.write_depth)) + if (args.memory_type in ["Simple_Dual_Port", "True_Dual_Port"]): + if (args.common_clk == 1): + summary["Synchronization"] = "True" else: - write_depthB = read_depth_B - summary["Address A"] = math.ceil(math.log2(write_depthA)) - summary["Address B"] = math.ceil(math.log2(write_depthB)) + summary["Synchronization"] = "False" else: - summary["Address"] = math.ceil(math.log2(args.write_depth)) + summary["WARNING"] = "No BRAMs in selected device. Select a different device with BRAMs." - if (args.memory_type in ["Simple_Dual_Port", "True_Dual_Port"]): - if (args.common_clk == 1): - summary["Synchronization"] = "True" - else: - summary["Synchronization"] = "False" - if (args.byte_write_enable == True): data = args.DATA_WIDTH else: @@ -370,11 +406,13 @@ def main(): port_type = args.port_type, file_path_hex = args.file_path, file_extension = file_extension, - byte_write_enable = args.byte_write_enable + byte_write_enable = args.byte_write_enable, + op_mode = args.op_mode ) - if (args.memory_mapping == "Block_RAM"): - summary["Number of BRAMs"] = module.M * module.N + if (device_dic['bram'] > 0): + if (args.memory_mapping == "Block_RAM"): + summary["Number of BRAMs"] = module.M * module.N # Export JSON Template (Optional) -------------------------------------------------------------- if args.json_template: