| // Copyright lowRISC contributors. |
| // Licensed under the Apache License, Version 2.0, see LICENSE for details. |
| // SPDX-License-Identifier: Apache-2.0 |
| ${gencmd} |
| <% |
| import re |
| import topgen.lib as lib |
| from topgen.clocks import Clocks |
| from topgen.resets import Resets |
| |
| num_mio_inputs = top['pinmux']['io_counts']['muxed']['inouts'] + \ |
| top['pinmux']['io_counts']['muxed']['inputs'] |
| num_mio_outputs = top['pinmux']['io_counts']['muxed']['inouts'] + \ |
| top['pinmux']['io_counts']['muxed']['outputs'] |
| num_mio_pads = top['pinmux']['io_counts']['muxed']['pads'] |
| |
| num_dio_inputs = top['pinmux']['io_counts']['dedicated']['inouts'] + \ |
| top['pinmux']['io_counts']['dedicated']['inputs'] |
| num_dio_outputs = top['pinmux']['io_counts']['dedicated']['inouts'] + \ |
| top['pinmux']['io_counts']['dedicated']['outputs'] |
| num_dio_total = top['pinmux']['io_counts']['dedicated']['inouts'] + \ |
| top['pinmux']['io_counts']['dedicated']['inputs'] + \ |
| top['pinmux']['io_counts']['dedicated']['outputs'] |
| |
| num_im = sum([x["width"] if "width" in x else 1 for x in top["inter_signal"]["external"]]) |
| |
| max_sigwidth = max([x["width"] if "width" in x else 1 for x in top["pinmux"]["ios"]]) |
| max_sigwidth = len("{}".format(max_sigwidth)) |
| |
| cpu_clk = top['clocks'].hier_paths['top'] + "clk_proc_main" |
| |
| unused_resets = lib.get_unused_resets(top) |
| unused_im_defs, undriven_im_defs = lib.get_dangling_im_def(top["inter_signal"]["definitions"]) |
| |
| has_toplevel_rom = False |
| for m in top['memory']: |
| if m['type'] == 'rom': |
| has_toplevel_rom = True |
| |
| %>\ |
| module top_${top["name"]} #( |
| // Manually defined parameters |
| % if not lib.is_rom_ctrl(top["module"]): |
| parameter BootRomInitFile = "", |
| % endif |
| |
| // Auto-inferred parameters |
| % for m in top["module"]: |
| % if not lib.is_inst(m): |
| <% continue %> |
| % endif |
| // parameters for ${m['name']} |
| % for p_exp in [p for p in m["param_list"] if p.get("expose") == "true" ]: |
| <% |
| p_type = p_exp.get('type') |
| p_type_word = p_type + ' ' if p_type else '' |
| |
| p_lhs = f'{p_type_word}{p_exp["name_top"]}' |
| p_rhs = p_exp['default'] |
| %>\ |
| % if 12 + len(p_lhs) + 3 + len(p_rhs) + 1 < 100: |
| parameter ${p_lhs} = ${p_rhs}${"" if loop.parent.last & loop.last else ","} |
| % else: |
| parameter ${p_lhs} = |
| ${p_rhs}${"" if loop.parent.last & loop.last else ","} |
| % endif |
| % endfor |
| % endfor |
| ) ( |
| % if num_mio_pads != 0: |
| // Multiplexed I/O |
| input ${lib.bitarray(num_mio_pads, max_sigwidth)} mio_in_i, |
| output logic ${lib.bitarray(num_mio_pads, max_sigwidth)} mio_out_o, |
| output logic ${lib.bitarray(num_mio_pads, max_sigwidth)} mio_oe_o, |
| % endif |
| % if num_dio_total != 0: |
| // Dedicated I/O |
| input ${lib.bitarray(num_dio_total, max_sigwidth)} dio_in_i, |
| output logic ${lib.bitarray(num_dio_total, max_sigwidth)} dio_out_o, |
| output logic ${lib.bitarray(num_dio_total, max_sigwidth)} dio_oe_o, |
| % endif |
| |
| % if "pinmux" in top: |
| // pad attributes to padring |
| output prim_pad_wrapper_pkg::pad_attr_t [pinmux_reg_pkg::NMioPads-1:0] mio_attr_o, |
| output prim_pad_wrapper_pkg::pad_attr_t [pinmux_reg_pkg::NDioPads-1:0] dio_attr_o, |
| % endif |
| |
| % if num_im != 0: |
| |
| // Inter-module Signal External type |
| % for sig in top["inter_signal"]["external"]: |
| ${lib.get_direction(sig)} ${lib.im_defname(sig)} ${lib.bitarray(sig["width"],1)} ${sig["signame"]}, |
| % endfor |
| |
| % endif |
| |
| // All externally supplied clocks |
| % for clk in top['clocks'].typed_clocks().ast_clks: |
| input ${clk}, |
| % endfor |
| |
| // All clocks forwarded to ast |
| output clkmgr_pkg::clkmgr_out_t clks_ast_o, |
| output rstmgr_pkg::rstmgr_out_t rsts_ast_o, |
| |
| input scan_rst_ni, // reset used for test mode |
| input scan_en_i, |
| input prim_mubi_pkg::mubi4_t scanmode_i // lc_ctrl_pkg::On for Scan |
| ); |
| |
| import tlul_pkg::*; |
| import top_pkg::*; |
| import tl_main_pkg::*; |
| import top_${top["name"]}_pkg::*; |
| // Compile-time random constants |
| import top_${top["name"]}_rnd_cnst_pkg::*; |
| |
| // Signals |
| logic [${num_mio_inputs - 1}:0] mio_p2d; |
| logic [${num_mio_outputs - 1}:0] mio_d2p; |
| logic [${num_mio_outputs - 1}:0] mio_en_d2p; |
| logic [${num_dio_total - 1}:0] dio_p2d; |
| logic [${num_dio_total - 1}:0] dio_d2p; |
| logic [${num_dio_total - 1}:0] dio_en_d2p; |
| % for m in top["module"]: |
| % if not lib.is_inst(m): |
| <% continue %> |
| % endif |
| <% |
| block = name_to_block[m['type']] |
| inouts, inputs, outputs = block.xputs |
| %>\ |
| // ${m["name"]} |
| % for p_in in inputs + inouts: |
| logic ${lib.bitarray(p_in.bits.width(), max_sigwidth)} cio_${m["name"]}_${p_in.name}_p2d; |
| % endfor |
| % for p_out in outputs + inouts: |
| logic ${lib.bitarray(p_out.bits.width(), max_sigwidth)} cio_${m["name"]}_${p_out.name}_d2p; |
| logic ${lib.bitarray(p_out.bits.width(), max_sigwidth)} cio_${m["name"]}_${p_out.name}_en_d2p; |
| % endfor |
| % endfor |
| |
| |
| <% |
| # Interrupt source 0 is tied to 0 to conform RISC-V PLIC spec. |
| # So, total number of interrupts are the number of entries in the list + 1 |
| interrupt_num = sum([x["width"] if "width" in x else 1 for x in top["interrupt"]]) + 1 |
| %>\ |
| logic [${interrupt_num-1}:0] intr_vector; |
| // Interrupt source list |
| % for m in top["module"]: |
| <% |
| block = name_to_block[m['type']] |
| %>\ |
| % if not lib.is_inst(m): |
| <% continue %> |
| % endif |
| % for intr in block.interrupts: |
| % if intr.bits.width() != 1: |
| logic [${intr.bits.width()-1}:0] intr_${m["name"]}_${intr.name}; |
| % else: |
| logic intr_${m["name"]}_${intr.name}; |
| % endif |
| % endfor |
| % endfor |
| |
| // Alert list |
| prim_alert_pkg::alert_tx_t [alert_pkg::NAlerts-1:0] alert_tx; |
| prim_alert_pkg::alert_rx_t [alert_pkg::NAlerts-1:0] alert_rx; |
| |
| % if not top["alert"]: |
| for (genvar k = 0; k < alert_pkg::NAlerts; k++) begin : gen_alert_tie_off |
| // tie off if no alerts present in the system |
| assign alert_tx[k].alert_p = 1'b0; |
| assign alert_tx[k].alert_n = 1'b1; |
| end |
| % endif |
| |
| ## Inter-module Definitions |
| % if len(top["inter_signal"]["definitions"]) >= 1: |
| // define inter-module signals |
| % endif |
| % for sig in top["inter_signal"]["definitions"]: |
| ${lib.im_defname(sig)} ${lib.bitarray(sig["width"],1)} ${sig["signame"]}; |
| % endfor |
| |
| ## Mixed connection to port |
| ## Index greater than 0 means a port is assigned to an inter-module array |
| ## whereas an index of 0 means a port is directly driven by a module |
| // define mixed connection to port |
| % for port in top['inter_signal']['external']: |
| % if port['conn_type'] and port['index'] > 0: |
| % if port['direction'] == 'in': |
| assign ${port['netname']}[${port['index']}] = ${port['signame']}; |
| % else: |
| assign ${port['signame']} = ${port['netname']}[${port['index']}]; |
| % endif |
| % elif port['conn_type']: |
| % if port['direction'] == 'in': |
| assign ${port['netname']} = ${port['signame']}; |
| % else: |
| assign ${port['signame']} = ${port['netname']}; |
| % endif |
| % endif |
| % endfor |
| |
| ## Partial inter-module definition tie-off |
| // define partial inter-module tie-off |
| % for sig in unused_im_defs: |
| % for idx in range(sig['end_idx'], sig['width']): |
| ${lib.im_defname(sig)} unused_${sig["signame"]}${idx}; |
| % endfor |
| % endfor |
| |
| // assign partial inter-module tie-off |
| % for sig in unused_im_defs: |
| % for idx in range(sig['end_idx'], sig['width']): |
| assign unused_${sig["signame"]}${idx} = ${sig["signame"]}[${idx}]; |
| % endfor |
| % endfor |
| % for sig in undriven_im_defs: |
| % for idx in range(sig['end_idx'], sig['width']): |
| assign ${sig["signame"]}[${idx}] = ${sig["default"]}; |
| % endfor |
| % endfor |
| |
| ## Inter-module signal collection |
| |
| % for m in top["module"]: |
| % if m["type"] == "otp_ctrl": |
| // OTP HW_CFG Broadcast signals. |
| // TODO(#6713): The actual struct breakout and mapping currently needs to |
| // be performed by hand. |
| assign csrng_otp_en_csrng_sw_app_read = otp_ctrl_otp_hw_cfg.data.en_csrng_sw_app_read; |
| assign entropy_src_otp_en_entropy_src_fw_read = otp_ctrl_otp_hw_cfg.data.en_entropy_src_fw_read; |
| assign entropy_src_otp_en_entropy_src_fw_over = otp_ctrl_otp_hw_cfg.data.en_entropy_src_fw_over; |
| assign sram_ctrl_main_otp_en_sram_ifetch = otp_ctrl_otp_hw_cfg.data.en_sram_ifetch; |
| assign lc_ctrl_otp_device_id = otp_ctrl_otp_hw_cfg.data.device_id; |
| assign lc_ctrl_otp_manuf_state = otp_ctrl_otp_hw_cfg.data.manuf_state; |
| assign keymgr_otp_device_id = otp_ctrl_otp_hw_cfg.data.device_id; |
| |
| logic unused_otp_hw_cfg_bits; |
| assign unused_otp_hw_cfg_bits = ^{ |
| otp_ctrl_otp_hw_cfg.valid, |
| otp_ctrl_otp_hw_cfg.data.hw_cfg_digest, |
| otp_ctrl_otp_hw_cfg.data.unallocated |
| }; |
| % endif |
| % endfor |
| |
| // See #7978 This below is a hack. |
| // This is because ast is a comportable-like module that sits outside |
| // of top_${top["name"]}'s boundary. |
| assign clks_ast_o = ${top['clocks'].hier_paths['top'][:-1]}; |
| assign rsts_ast_o = ${top['resets'].hier_paths['top'][:-1]}; |
| |
| // ibex specific assignments |
| // TODO: This should be further automated in the future. |
| assign rv_core_ibex_irq_timer = intr_rv_timer_timer_expired_hart0_timer0; |
| assign rv_core_ibex_hart_id = '0; |
| |
| ## Not all top levels have a rom controller. |
| ## For those that do not, reference the ROM directly. |
| % if lib.is_rom_ctrl(top["module"]): |
| assign rv_core_ibex_boot_addr = ADDR_SPACE_ROM_CTRL__ROM; |
| % else: |
| assign rv_core_ibex_boot_addr = ADDR_SPACE_ROM; |
| % endif |
| |
| ## Not all top levels have a lifecycle controller. |
| ## For those that do not, always enable ibex. |
| % if not lib.is_lc_ctrl(top["module"]): |
| assign rv_core_ibex_lc_cpu_en = lc_ctrl_pkg::On; |
| % endif |
| |
| // Struct breakout module tool-inserted DFT TAP signals |
| pinmux_jtag_breakout u_dft_tap_breakout ( |
| .req_i (pinmux_aon_dft_jtag_req), |
| .rsp_o (pinmux_aon_dft_jtag_rsp), |
| .tck_o (), |
| .trst_no (), |
| .tms_o (), |
| .tdi_o (), |
| .tdo_i (1'b0), |
| .tdo_oe_i (1'b0) |
| ); |
| |
| // Wire up alert handler LPGs |
| prim_mubi_pkg::mubi4_t [alert_pkg::NLpg-1:0] lpg_cg_en; |
| prim_mubi_pkg::mubi4_t [alert_pkg::NLpg-1:0] lpg_rst_en; |
| |
| <% |
| # get all known typed clocks and add them to a dict |
| # this is used to generate the tie-off assignments further below |
| clocks = top['clocks'] |
| assert isinstance(clocks, Clocks) |
| typed_clocks = clocks.typed_clocks() |
| known_clocks = {} |
| for clk in typed_clocks.all_clocks(): |
| known_clocks.update({top['clocks'].hier_paths['lpg'] + clk.split('clk_')[-1]: 1}) |
| |
| # get all known resets and add them to a dict |
| # this is used to generate the tie-off assignments further below |
| resets = top['resets'] |
| assert isinstance(resets, Resets) |
| output_rsts = resets.get_top_resets() |
| known_resets = {} |
| for rst in output_rsts: |
| for dom in top['power']['domains']: |
| if rst.shadowed: |
| path = lib.get_reset_lpg_path(top, resets.get_reset_by_name(rst.name)._asdict(), True, dom) |
| known_resets.update({ |
| path: 1 |
| }) |
| path = lib.get_reset_lpg_path(top, resets.get_reset_by_name(rst.name)._asdict(), False, dom) |
| known_resets.update({ |
| path: 1 |
| }) |
| %>\ |
| |
| % for k, lpg in enumerate(top['alert_lpgs']): |
| // ${lpg['name']} |
| <% |
| cg_en = top['clocks'].hier_paths['lpg'] + lpg['clock_connection'].split('.clk_')[-1] |
| rst_en = lib.get_reset_lpg_path(top, lpg['reset_connection']) |
| known_clocks[cg_en] = 0 |
| known_resets[rst_en] = 0 |
| %>\ |
| assign lpg_cg_en[${k}] = ${cg_en}; |
| assign lpg_rst_en[${k}] = ${rst_en}; |
| % endfor |
| |
| // tie-off unused connections |
| <% k = 0 %>\ |
| % for clk, unused in known_clocks.items(): |
| % if unused: |
| prim_mubi_pkg::mubi4_t unused_cg_en_${k}; |
| assign unused_cg_en_${k} = ${clk};<% k += 1 %> |
| % endif |
| % endfor |
| <% k = 0 %>\ |
| % for rst, unused in known_resets.items(): |
| % if unused: |
| prim_mubi_pkg::mubi4_t unused_rst_en_${k}; |
| assign unused_rst_en_${k} = ${rst};<% k += 1 %> |
| % endif |
| % endfor |
| |
| // Peripheral Instantiation |
| |
| <% alert_idx = 0 %> |
| % for m in top["module"]: |
| <% |
| if not lib.is_inst(m): |
| continue |
| |
| block = name_to_block[m['type']] |
| inouts, inputs, outputs = block.xputs |
| |
| port_list = inputs + outputs + inouts |
| max_sigwidth = max(len(x.name) for x in port_list) if port_list else 0 |
| max_intrwidth = (max(len(x.name) for x in block.interrupts) |
| if block.interrupts else 0) |
| %>\ |
| % if m["param_list"] or block.alerts: |
| ${m["type"]} #( |
| % if block.alerts: |
| <% |
| w = len(block.alerts) |
| slice = str(alert_idx+w-1) + ":" + str(alert_idx) |
| %>\ |
| .AlertAsyncOn(alert_handler_reg_pkg::AsyncOn[${slice}])${"," if m["param_list"] else ""} |
| % endif |
| % for i in m["param_list"]: |
| .${i["name"]}(${i["name_top" if i.get("expose") == "true" or i.get("randtype", "none") != "none" else "default"]})${"," if not loop.last else ""} |
| % endfor |
| ) u_${m["name"]} ( |
| % else: |
| ${m["type"]} u_${m["name"]} ( |
| % endif |
| % for p_in in inputs + inouts: |
| % if loop.first: |
| |
| // Input |
| % endif |
| .${lib.ljust("cio_"+p_in.name+"_i",max_sigwidth+9)} (cio_${m["name"]}_${p_in.name}_p2d), |
| % endfor |
| % for p_out in outputs + inouts: |
| % if loop.first: |
| |
| // Output |
| % endif |
| .${lib.ljust("cio_"+p_out.name+"_o", max_sigwidth+9)} (cio_${m["name"]}_${p_out.name}_d2p), |
| .${lib.ljust("cio_"+p_out.name+"_en_o",max_sigwidth+9)} (cio_${m["name"]}_${p_out.name}_en_d2p), |
| % endfor |
| % for intr in block.interrupts: |
| % if loop.first: |
| |
| // Interrupt |
| % endif |
| .${lib.ljust("intr_"+intr.name+"_o",max_intrwidth+7)} (intr_${m["name"]}_${intr.name}), |
| % endfor |
| % if block.alerts: |
| % for alert in block.alerts: |
| // [${alert_idx}]: ${alert.name}<% alert_idx += 1 %> |
| % endfor |
| .alert_tx_o ( alert_tx[${slice}] ), |
| .alert_rx_i ( alert_rx[${slice}] ), |
| % endif |
| ## TODO: Inter-module Connection |
| % if m.get('inter_signal_list'): |
| |
| // Inter-module signals |
| % for sig in m['inter_signal_list']: |
| ## TODO: handle below condition in lib.py |
| % if sig['type'] == "req_rsp": |
| .${lib.im_portname(sig,"req")}(${lib.im_netname(sig, "req")}), |
| .${lib.im_portname(sig,"rsp")}(${lib.im_netname(sig, "rsp")}), |
| % elif sig['type'] == "io": |
| .${lib.im_portname(sig,"io")}(${lib.im_netname(sig, "io")}), |
| % elif sig['type'] == "uni": |
| ## TODO: Broadcast type |
| ## TODO: default for logic type |
| .${lib.im_portname(sig)}(${lib.im_netname(sig)}), |
| % endif |
| % endfor |
| % endif |
| % if m["type"] == "rv_plic": |
| .intr_src_i (intr_vector), |
| % endif |
| % if m["type"] == "pinmux": |
| |
| .periph_to_mio_i (mio_d2p ), |
| .periph_to_mio_oe_i (mio_en_d2p ), |
| .mio_to_periph_o (mio_p2d ), |
| |
| .mio_attr_o, |
| .mio_out_o, |
| .mio_oe_o, |
| .mio_in_i, |
| |
| .periph_to_dio_i (dio_d2p ), |
| .periph_to_dio_oe_i (dio_en_d2p ), |
| .dio_to_periph_o (dio_p2d ), |
| |
| .dio_attr_o, |
| .dio_out_o, |
| .dio_oe_o, |
| .dio_in_i, |
| |
| % endif |
| % if m["type"] == "alert_handler": |
| // alert signals |
| .alert_rx_o ( alert_rx ), |
| .alert_tx_i ( alert_tx ), |
| // synchronized clock gated / reset asserted |
| // indications for each alert |
| .lpg_cg_en_i ( lpg_cg_en ), |
| .lpg_rst_en_i ( lpg_rst_en ), |
| % endif |
| % if block.scan: |
| .scanmode_i, |
| % endif |
| % if block.scan_reset: |
| .scan_rst_ni, |
| % endif |
| % if block.scan_en: |
| .scan_en_i, |
| % endif |
| |
| // Clock and reset connections |
| % for k, v in m["clock_connections"].items(): |
| .${k} (${v}), |
| % endfor |
| % for port, reset in m["reset_connections"].items(): |
| % if lib.is_shadowed_port(block, port): |
| .${lib.shadow_name(port)} (${lib.get_reset_path(top, reset, True)}), |
| % endif: |
| .${port} (${lib.get_reset_path(top, reset)})${"," if not loop.last else ""} |
| % endfor |
| ); |
| % endfor |
| // interrupt assignments |
| <% base = interrupt_num %>\ |
| assign intr_vector = { |
| % for intr in top["interrupt"][::-1]: |
| <% base -= intr["width"] %>\ |
| intr_${intr["name"]}, // IDs [${base} +: ${intr['width']}] |
| % endfor |
| 1'b 0 // ID [0 +: 1] is a special case and tied to zero. |
| }; |
| |
| // TL-UL Crossbar |
| % for xbar in top["xbar"]: |
| <% |
| name_len = max([len(x["name"]) for x in xbar["nodes"]]); |
| %>\ |
| xbar_${xbar["name"]} u_xbar_${xbar["name"]} ( |
| % for k, v in xbar["clock_connections"].items(): |
| .${k} (${v}), |
| % endfor |
| % for port, reset in xbar["reset_connections"].items(): |
| .${port} (${lib.get_reset_path(top, reset)}), |
| % endfor |
| |
| ## Inter-module signal |
| % for sig in xbar["inter_signal_list"]: |
| <% assert sig['type'] == "req_rsp" %>\ |
| // port: ${sig['name']} |
| .${lib.im_portname(sig,"req")}(${lib.im_netname(sig, "req")}), |
| .${lib.im_portname(sig,"rsp")}(${lib.im_netname(sig, "rsp")}), |
| |
| % endfor |
| |
| .scanmode_i |
| ); |
| % endfor |
| |
| % if "pinmux" in top: |
| // Pinmux connections |
| // All muxed inputs |
| % for sig in top["pinmux"]["ios"]: |
| % if sig["connection"] == "muxed" and sig["type"] in ["inout", "input"]: |
| <% literal = lib.get_io_enum_literal(sig, 'mio_in') %>\ |
| assign cio_${sig["name"]}_p2d${"[" + str(sig["idx"]) +"]" if sig["idx"] !=-1 else ""} = mio_p2d[${literal}]; |
| % endif |
| % endfor |
| |
| // All muxed outputs |
| % for sig in top["pinmux"]["ios"]: |
| % if sig["connection"] == "muxed" and sig["type"] in ["inout", "output"]: |
| <% literal = lib.get_io_enum_literal(sig, 'mio_out') %>\ |
| assign mio_d2p[${literal}] = cio_${sig["name"]}_d2p${"[" + str(sig["idx"]) +"]" if sig["idx"] !=-1 else ""}; |
| % endif |
| % endfor |
| |
| // All muxed output enables |
| % for sig in top["pinmux"]["ios"]: |
| % if sig["connection"] == "muxed" and sig["type"] in ["inout", "output"]: |
| <% literal = lib.get_io_enum_literal(sig, 'mio_out') %>\ |
| assign mio_en_d2p[${literal}] = cio_${sig["name"]}_en_d2p${"[" + str(sig["idx"]) +"]" if sig["idx"] !=-1 else ""}; |
| % endif |
| % endfor |
| |
| // All dedicated inputs |
| <% idx = 0 %>\ |
| logic [${num_dio_total-1}:0] unused_dio_p2d; |
| assign unused_dio_p2d = dio_p2d; |
| % for sig in top["pinmux"]["ios"]: |
| <% literal = lib.get_io_enum_literal(sig, 'dio') %>\ |
| % if sig["connection"] != "muxed" and sig["type"] in ["inout"]: |
| assign cio_${sig["name"]}_p2d${"[" + str(sig["idx"]) +"]" if sig["idx"] !=-1 else ""} = dio_p2d[${literal}]; |
| % elif sig["connection"] != "muxed" and sig["type"] in ["input"]: |
| assign cio_${sig["name"]}_p2d${"[" + str(sig["idx"]) +"]" if sig["idx"] !=-1 else ""} = dio_p2d[${literal}]; |
| % endif |
| % endfor |
| |
| // All dedicated outputs |
| % for sig in top["pinmux"]["ios"]: |
| <% literal = lib.get_io_enum_literal(sig, 'dio') %>\ |
| % if sig["connection"] != "muxed" and sig["type"] in ["inout"]: |
| assign dio_d2p[${literal}] = cio_${sig["name"]}_d2p${"[" + str(sig["idx"]) +"]" if sig["idx"] !=-1 else ""}; |
| % elif sig["connection"] != "muxed" and sig["type"] in ["input"]: |
| assign dio_d2p[${literal}] = 1'b0; |
| % elif sig["connection"] != "muxed" and sig["type"] in ["output"]: |
| assign dio_d2p[${literal}] = cio_${sig["name"]}_d2p${"[" + str(sig["idx"]) +"]" if sig["idx"] !=-1 else ""}; |
| % endif |
| % endfor |
| |
| // All dedicated output enables |
| % for sig in top["pinmux"]["ios"]: |
| <% literal = lib.get_io_enum_literal(sig, 'dio') %>\ |
| % if sig["connection"] != "muxed" and sig["type"] in ["inout"]: |
| assign dio_en_d2p[${literal}] = cio_${sig["name"]}_en_d2p${"[" + str(sig["idx"]) +"]" if sig["idx"] !=-1 else ""}; |
| % elif sig["connection"] != "muxed" and sig["type"] in ["input"]: |
| assign dio_en_d2p[${literal}] = 1'b0; |
| % elif sig["connection"] != "muxed" and sig["type"] in ["output"]: |
| assign dio_en_d2p[${literal}] = cio_${sig["name"]}_en_d2p${"[" + str(sig["idx"]) +"]" if sig["idx"] !=-1 else ""}; |
| % endif |
| % endfor |
| |
| % endif |
| |
| // make sure scanmode_i is never X (including during reset) |
| `ASSERT_KNOWN(scanmodeKnown, scanmode_i, clk_main_i, 0) |
| |
| endmodule |