diff --git a/quicklogic/common/cmake/quicklogic_jlink.cmake b/quicklogic/common/cmake/quicklogic_jlink.cmake index 85254d15de..527c5fd56e 100644 --- a/quicklogic/common/cmake/quicklogic_jlink.cmake +++ b/quicklogic/common/cmake/quicklogic_jlink.cmake @@ -66,24 +66,15 @@ function(ADD_JLINK_OUTPUT) add_file_target(FILE ${WORK_DIR_REL}/${IOMUX_CONFIG} GENERATED) # Convert the binary bitstream to a JLINK script - set(BIT_AS_JLINK "top.bit.jlink") - - add_custom_command( - OUTPUT ${WORK_DIR}/${BIT_AS_JLINK} - COMMAND ${PYTHON3} -m quicklogic_fasm.bitstream_to_jlink ${BITSTREAM_LOC} ${WORK_DIR}/${BIT_AS_JLINK} - DEPENDS ${BITSTREAM} - ) - - add_file_target(FILE ${WORK_DIR_REL}/${BIT_AS_JLINK} GENERATED) - - # Concatenate th bitstream JLink script and the IOMUX config JLink script set(OUT_JLINK "top.jlink") add_custom_command( OUTPUT ${WORK_DIR}/${OUT_JLINK} - COMMAND cat ${WORK_DIR}/${BIT_AS_JLINK} ${WORK_DIR}/${IOMUX_CONFIG} >${WORK_DIR}/${OUT_JLINK} - DEPENDS ${WORK_DIR}/${BIT_AS_JLINK} ${WORK_DIR}/${IOMUX_CONFIG} + COMMAND ${PYTHON3} -m quicklogic_fasm.bitstream_to_jlink ${BITSTREAM_LOC} ${WORK_DIR}/${OUT_JLINK} + DEPENDS ${BITSTREAM} ${WORK_DIR}/${IOMUX_CONFIG} ) + add_file_target(FILE ${WORK_DIR_REL}/${OUT_JLINK} GENERATED) + add_custom_target(${PARENT}_jlink DEPENDS ${WORK_DIR}/${OUT_JLINK}) diff --git a/quicklogic/common/cmake/quicklogic_openocd.cmake b/quicklogic/common/cmake/quicklogic_openocd.cmake index d4b83c7bb7..008e35896f 100644 --- a/quicklogic/common/cmake/quicklogic_openocd.cmake +++ b/quicklogic/common/cmake/quicklogic_openocd.cmake @@ -66,24 +66,16 @@ function(ADD_OPENOCD_OUTPUT) add_file_target(FILE ${WORK_DIR_REL}/${IOMUX_CONFIG} GENERATED) # Convert the binary bitstream to a OpenOCD script - set(BIT_AS_OPENOCD "top.bit.openocd") - - add_custom_command( - OUTPUT ${WORK_DIR}/${BIT_AS_OPENOCD} - COMMAND ${PYTHON3} -m quicklogic_fasm.bitstream_to_openocd ${BITSTREAM_LOC} ${WORK_DIR}/${BIT_AS_OPENOCD} - DEPENDS ${BITSTREAM} - ) - - add_file_target(FILE ${WORK_DIR_REL}/${BIT_AS_OPENOCD} GENERATED) - - # Concatenate the bitstream OpenOCD script and the IOMUX config OpenOCD script set(OUT_OPENOCD "top.openocd") + add_custom_command( OUTPUT ${WORK_DIR}/${OUT_OPENOCD} - COMMAND head -n -1 ${WORK_DIR}/${BIT_AS_OPENOCD} > ${WORK_DIR}/${OUT_OPENOCD} && cat ${WORK_DIR}/${IOMUX_CONFIG} >> ${WORK_DIR}/${OUT_OPENOCD} && echo '}' >> ${WORK_DIR}/${OUT_OPENOCD} - DEPENDS ${WORK_DIR}/${BIT_AS_OPENOCD} ${WORK_DIR}/${IOMUX_CONFIG} + COMMAND ${PYTHON3} -m quicklogic_fasm.bitstream_to_openocd ${BITSTREAM_LOC} ${WORK_DIR}/${OUT_OPENOCD} + DEPENDS ${BITSTREAM} ${WORK_DIR}/${IOMUX_CONFIG} ) + add_file_target(FILE ${WORK_DIR_REL}/${OUT_OPENOCD} GENERATED) + add_custom_target(${PARENT}_openocd DEPENDS ${WORK_DIR}/${OUT_OPENOCD}) endfunction() diff --git a/quicklogic/pp3/utils/eos_s3_iomux_config.py b/quicklogic/pp3/utils/eos_s3_iomux_config.py index 3d5faa79bc..0dfc84ebc8 100755 --- a/quicklogic/pp3/utils/eos_s3_iomux_config.py +++ b/quicklogic/pp3/utils/eos_s3_iomux_config.py @@ -22,13 +22,57 @@ "SDIOMUX": ["PB-SDIOMUX", ], } -# Default configuration of the IOMUX pad -PAD_DEFAULT = { +# Default configuration of the specific IOMUX pads +PADS_1 = { + 2, 3, 4, 5, 6, 7, 10, 11, 12, 13, 18, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 35, 37, 40, 41, 42, 43 +} +PAD_DEFAULTS_1 = { + "func_sel": 0, + "ctrl_sel": "A0", + "mode": "output", + "pull": "none", + "drive": 4, + "slew": "slow", + "schmitt": 0 +} +PADS_2 = {6, 14, 15, 17, 34, 36, 38, 39, 44, 45} +PAD_DEFAULTS_2 = { + "func_sel": 0, + "ctrl_sel": "others", + "mode": "output", + "pull": "none", + "drive": 4, + "slew": "slow", + "schmitt": 0 +} +PADS_3 = {8, 9, 19, 20} +PAD_DEFAULTS_3 = { + "func_sel": 0, + "ctrl_sel": "A0", + "mode": "inout", + "pull": "down", + "drive": 4, + "slew": "slow", + "schmitt": 0 +} +PADS_4 = {0, 1} +PAD_DEFAULTS_4 = { "func_sel": 0, - "ctrl_sel": 0, - "mode": "none", + "ctrl_sel": "A0", + "mode": "output", + "pull": "up", + "drive": 4, + "slew": "slow", + "schmitt": 0 +} +PADS_5 = {16} +PAD_DEFAULTS_5 = { + "func_sel": 0, + "ctrl_sel": "A0", + "mode": "inout", "pull": "none", - "drive": 2, + "drive": 4, "slew": "slow", "schmitt": 0 } @@ -53,9 +97,6 @@ def generate_iomux_register_content(config): pad = int(pad) reg = 0 - # Patch default settings with settings read from the config file - pad_cfg = dict(PAD_DEFAULT, **pad_cfg) - func_sel = pad_cfg["func_sel"] assert func_sel in [0, 1], func_sel reg |= func_sel @@ -137,6 +178,55 @@ def generate_iomux_register_content(config): return iomux_regs +def get_pad_no(pad_alias): + pad = None + + match = re.match(r"^IO_([0-9]+)$", pad_alias) + if match is not None: + pad = int(match.group(1)) + + if pad is None or pad < 0 or pad >= 46: + print("Pad not found or out of range: {}".format(pad)) + return -1 + + return pad + + +def pad_defconfig_lookup(pad): + pad_config = None + + if pad in PADS_1: + pad_config = PAD_DEFAULTS_1 + elif pad in PADS_2: + pad_config = PAD_DEFAULTS_2 + elif pad in PADS_3: + pad_config = PAD_DEFAULTS_3 + elif pad in PADS_4: + pad_config = PAD_DEFAULTS_4 + elif pad in PADS_5: + pad_config = PAD_DEFAULTS_5 + else: + raise ValueError( + "Unknown default IOMUX configuration for pad: {}".format(pad) + ) + + return pad_config + + +def prepare_default_config(pad_map): + config = {"pads": {}} + + # Populate IO config with default configuration for each pad + for pin in pad_map.items(): + pad = get_pad_no(pin[1]) + if (pad == -1): + continue + + config["pads"][str(pad)] = pad_defconfig_lookup(pad) + + return config + + # ============================================================================= @@ -179,16 +269,44 @@ def main(): required=True, help='Pin map CSV file' ) + parser.add_argument( + "--default-config", + action="store_true", + help='generate default IOMUX config that will be overlaid by the design' + ) parser.add_argument( "--output-format", default=None, type=str, - help='Output format of IOMUX commands (openocd/jlink)' + help='Output format of IOMUX commands (openocd/jlink/binary)' ) args = parser.parse_args() + pad_map = {} + pad_alias_map = {} + + # Read pinmap + for pin_map_entry in csv.DictReader(args.map): + + if pin_map_entry['type'] not in IOB_TYPES: + continue + + name = pin_map_entry['name'] + alias = "" + if 'alias' in pin_map_entry: + alias = pin_map_entry['alias'] + pad_alias_map[alias] = name + pad_map[name] = alias + else: + pad_map[name] = name + + if (args.default_config): + config = prepare_default_config(pad_map) + else: + config = {"pads": {}} + # Read the requested configurtion from a JSON file if args.json is not None: @@ -197,7 +315,17 @@ def main(): exit(-1) with open(args.json, "r") as fp: - config = json.load(fp) + json_config = json.load(fp) + + # Overlay default config + for design_pad, pad_config in json_config["pads"].items(): + if (args.default_config): + config["pads"][str(design_pad)] = dict( + config["pads"][str(design_pad)], **pad_config + ) + else: + defconfig = pad_defconfig_lookup(int(design_pad)) + config["pads"][design_pad] = dict(defconfig, **pad_config) # Generate the config according to the EBLIF netlist and PCF constraints. else: @@ -206,23 +334,6 @@ def main(): print("Use either '--json' or '--pcf' + '--eblif' options!") exit(-1) - pad_map = {} - pad_alias_map = {} - - for pin_map_entry in csv.DictReader(args.map): - - if pin_map_entry['type'] not in IOB_TYPES: - continue - - name = pin_map_entry['name'] - alias = "" - if 'alias' in pin_map_entry: - alias = pin_map_entry['alias'] - pad_alias_map[alias] = name - pad_map[name] = alias - else: - pad_map[name] = name - # Read and parse PCF with open(args.pcf, "r") as fp: pcf = list(parse_simple_pcf(fp)) @@ -231,9 +342,6 @@ def main(): with open(args.eblif, "r") as fp: eblif = parse_blif(fp) - # Build the config - config = {"pads": {}} - eblif_inputs = eblif["inputs"]["args"] eblif_outputs = eblif["outputs"]["args"] @@ -261,19 +369,14 @@ def main(): if pad_name in pad_alias_map: pad_alias = pad_name - pad = None - - match = re.match(r"^IO_([0-9]+)$", pad_alias) - if match is not None: - pad = int(match.group(1)) - - # Pad not found or out of range - if pad is None or pad < 0 or pad >= 46: + pad_no = get_pad_no(pad_alias) + if (pad_no == -1): continue # Detect inouts: is_inout_in = constraint.net + '_$inp' in eblif_inputs is_inout_out = constraint.net + '_$out' in eblif_outputs + if is_inout_in and is_inout_out: pad_config = { "ctrl_sel": "fabric", @@ -296,7 +399,14 @@ def main(): else: assert False, (constraint.net, constraint.pad) - config["pads"][str(pad)] = pad_config + # Overlay default config + if (args.default_config): + config["pads"][str(pad_no)] = dict( + config["pads"][str(pad_no)], **pad_config + ) + else: + defconfig = pad_defconfig_lookup(pad_no) + config["pads"][str(pad_no)] = dict(defconfig, **pad_config) # Convert the config to IOMUX register content iomux_regs = generate_iomux_register_content(config)