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..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,145 +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) - - 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" + summary["Output"] = "Unregistered Output" else: - summary["Input"] = "Unregistered and Signed" - if (args.reg_out): - summary["Output"] = "Registered 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: @@ -357,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 7683d96e..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,178 +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) - 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 dd91277b..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,112 +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)) - + 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: @@ -260,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/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 88ba6029..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 @@ -1481,7 +1481,7 @@ 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, 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 72783289..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 @@ -975,7 +975,7 @@ 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, 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 78543773..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,6 +91,14 @@ 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): @@ -239,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) @@ -247,45 +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"] + 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") @@ -315,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: @@ -373,8 +410,9 @@ def main(): 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: diff --git a/rapidsilicon/lib/common.py b/rapidsilicon/lib/common.py index 7a6e40bb..1be8b958 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')] = (int(fnum_bram)) + elif sub_dummy.attrib.get('type') == 'dsp': + fnum_dsp = sub_dummy.attrib.get('num') + device_dict[sub_dummy.attrib.get('type')] = (int(fnum_dsp)) + + return device_dict \ No newline at end of file