blob: 60f585516d011de88918ee6cc1707689f6344b5f [file] [log] [blame]
// 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 copy import deepcopy
# Provide shortcuts for some commonly used variables
pinmux = top['pinmux']
pinout = top['pinout']
num_mio_inputs = pinmux['io_counts']['muxed']['inouts'] + \
pinmux['io_counts']['muxed']['inputs']
num_mio_outputs = pinmux['io_counts']['muxed']['inouts'] + \
pinmux['io_counts']['muxed']['outputs']
num_mio_pads = pinmux['io_counts']['muxed']['pads']
num_dio_inputs = pinmux['io_counts']['dedicated']['inouts'] + \
pinmux['io_counts']['dedicated']['inputs']
num_dio_outputs = pinmux['io_counts']['dedicated']['inouts'] + \
pinmux['io_counts']['dedicated']['outputs']
num_dio_total = pinmux['io_counts']['dedicated']['inouts'] + \
pinmux['io_counts']['dedicated']['inputs'] + \
pinmux['io_counts']['dedicated']['outputs']
def get_dio_sig(pinmux: {}, pad: {}):
'''Get DIO signal associated with this pad or return None'''
for sig in pinmux["ios"]:
if sig["connection"] == "direct" and pad["name"] == sig["pad"]:
return sig
else:
return None
# Modify the pad lists on the fly, based on target config
maxwidth = 0
muxed_pads = []
dedicated_pads = []
k = 0
for pad in pinout["pads"]:
if pad["connection"] == "muxed":
if pad["name"] not in target["pinout"]["remove_pads"]:
maxwidth = max(maxwidth, len(pad["name"]))
muxed_pads.append(pad)
else:
k = pad["idx"]
if pad["name"] not in target["pinout"]["remove_pads"]:
maxwidth = max(maxwidth, len(pad["name"]))
dedicated_pads.append(pad)
for pad in target["pinout"]["add_pads"]:
# Since these additional pads have not been elaborated in the merge phase,
# we need to add their global index here.
amended_pad = deepcopy(pad)
amended_pad.update({"idx" : k})
dedicated_pads.append(pad)
k += 1
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_im_defs, undriven_im_defs = lib.get_dangling_im_def(top["inter_signal"]["definitions"])
%>\
% if target["name"] != "asic":
module chip_${top["name"]}_${target["name"]} #(
// Path to a VMEM file containing the contents of the boot ROM, which will be
// baked into the FPGA bitstream.
parameter BootRomInitFile = "test_rom_fpga_${target["name"]}.32.vmem",
// Path to a VMEM file containing the contents of the emulated OTP, which will be
// baked into the FPGA bitstream.
parameter OtpCtrlMemInitFile = "otp_img_fpga_${target["name"]}.vmem"
) (
% else:
module chip_${top["name"]}_${target["name"]} #(
parameter bit SecRomCtrlDisableScrambling = 1'b0
) (
% endif
<%
removed_port_names = []
%>\
// Dedicated Pads
% for pad in dedicated_pads:
<%
sig = get_dio_sig(pinmux, pad)
if pad["name"] in target["pinout"]["remove_ports"]:
port_comment = "// Removed port: "
removed_port_names.append(pad["name"])
else:
port_comment = ""
if sig is not None:
comment = "// Dedicated Pad for {}".format(sig["name"])
else:
comment = "// Manual Pad"
%>\
${port_comment}${pad["port_type"]} ${pad["name"]}, ${comment}
% endfor
// Muxed Pads
% for pad in muxed_pads:
<%
if pad["name"] in target["pinout"]["remove_ports"]:
port_comment = "// Removed port: "
removed_port_names.append(pad["name"])
else:
port_comment = ""
%>\
${port_comment}${pad["port_type"]} ${pad["name"]}${" " if loop.last else ","} // MIO Pad ${pad["idx"]}
% endfor
);
import top_${top["name"]}_pkg::*;
import prim_pad_wrapper_pkg::*;
% if target["pinmux"]["special_signals"]:
////////////////////////////
// Special Signal Indices //
////////////////////////////
% for entry in target["pinmux"]["special_signals"]:
<% param_name = (lib.Name.from_snake_case(entry["name"]) +
lib.Name(["pad", "idx"])).as_camel_case()
%>\
localparam int ${param_name} = ${entry["idx"]};
% endfor
% endif
// DFT and Debug signal positions in the pinout.
localparam pinmux_pkg::target_cfg_t PinmuxTargetCfg = '{
tck_idx: TckPadIdx,
tms_idx: TmsPadIdx,
trst_idx: TrstNPadIdx,
tdi_idx: TdiPadIdx,
tdo_idx: TdoPadIdx,
tap_strap0_idx: Tap0PadIdx,
tap_strap1_idx: Tap1PadIdx,
dft_strap0_idx: Dft0PadIdx,
dft_strap1_idx: Dft1PadIdx,
// TODO: check whether there is a better way to pass these USB-specific params
usb_dp_idx: DioUsbdevUsbDp,
usb_dn_idx: DioUsbdevUsbDn,
usb_sense_idx: MioInUsbdevSense,
// Pad types for attribute WARL behavior
dio_pad_type: {
<%
pad_attr = []
for sig in list(reversed(top["pinmux"]["ios"])):
if sig["connection"] != "muxed":
pad_attr.append((sig['name'], sig["attr"]))
%>\
% for name, attr in pad_attr:
${attr}${" " if loop.last else ","} // DIO ${name}
% endfor
},
mio_pad_type: {
<%
pad_attr = []
for pad in list(reversed(pinout["pads"])):
if pad["connection"] == "muxed":
pad_attr.append(pad["type"])
%>\
% for attr in pad_attr:
${attr}${" " if loop.last else ","} // MIO Pad ${len(pad_attr) - loop.index - 1}
% endfor
}
};
////////////////////////
// Signal definitions //
////////////////////////
% if removed_port_names:
// Net definitions for removed ports
% endif
% for port in removed_port_names:
wire ${port};
% endfor
pad_attr_t [pinmux_reg_pkg::NMioPads-1:0] mio_attr;
pad_attr_t [pinmux_reg_pkg::NDioPads-1:0] dio_attr;
logic [pinmux_reg_pkg::NMioPads-1:0] mio_out;
logic [pinmux_reg_pkg::NMioPads-1:0] mio_oe;
logic [pinmux_reg_pkg::NMioPads-1:0] mio_in;
logic [pinmux_reg_pkg::NMioPads-1:0] mio_in_raw;
logic [pinmux_reg_pkg::NDioPads-1:0] dio_out;
logic [pinmux_reg_pkg::NDioPads-1:0] dio_oe;
logic [pinmux_reg_pkg::NDioPads-1:0] dio_in;
logic unused_mio_in_raw;
assign unused_mio_in_raw = ^mio_in_raw;
// Manual pads
% for pad in dedicated_pads:
<%
pad_prefix = pad["name"].lower()
%>\
% if not get_dio_sig(pinmux, pad):
logic manual_in_${pad_prefix}, manual_out_${pad_prefix}, manual_oe_${pad_prefix};
% endif
% endfor
% for pad in dedicated_pads:
<%
pad_prefix = pad["name"].lower()
%>\
% if not get_dio_sig(pinmux, pad):
pad_attr_t manual_attr_${pad_prefix};
% endif
% endfor
% if target["pinout"]["remove_pads"]:
/////////////////////////
// Stubbed pad tie-off //
/////////////////////////
// Only signals going to non-custom pads need to be tied off.
logic [${len(pinout["pads"])-1}:0] unused_sig;
% for pad in pinout["pads"]:
% if pad["connection"] == 'muxed':
% if pad["name"] in target["pinout"]["remove_pads"]:
assign mio_in[${pad["idx"]}] = 1'b0;
assign mio_in_raw[${pad["idx"]}] = 1'b0;
assign unused_sig[${loop.index}] = mio_out[${pad["idx"]}] ^ mio_oe[${pad["idx"]}];
% endif
% else:
% if pad["name"] in target["pinout"]["remove_pads"]:
<%
## Only need to tie off if this is not a custom pad.
sig = get_dio_sig(pinmux, pad)
if sig is not None:
sig_index = lib.get_io_enum_literal(sig, 'dio')
%>\
% if sig is not None:
assign dio_in[${lib.get_io_enum_literal(sig, 'dio')}] = 1'b0;
assign unused_sig[${loop.index}] = dio_out[${sig_index}] ^ dio_oe[${sig_index}];
% endif
% endif
% endif
% endfor
%endif
//////////////////////
// Padring Instance //
//////////////////////
ast_pkg::ast_clks_t ast_base_clks;
% if target["name"] == "asic":
// AST signals needed in padring
logic scan_rst_n;
prim_mubi_pkg::mubi4_t scanmode;
% endif
padring #(
// Padring specific counts may differ from pinmux config due
// to custom, stubbed or added pads.
.NDioPads(${len(dedicated_pads)}),
.NMioPads(${len(muxed_pads)}),
% if target["name"] == "asic":
.PhysicalPads(1),
.NIoBanks(int'(IoBankCount)),
.DioScanRole ({
% for pad in list(reversed(dedicated_pads)):
scan_role_pkg::${lib.Name.from_snake_case('dio_pad_' + pad["name"] + '_scan_role').as_camel_case()}${"" if loop.last else ","}
% endfor
}),
.MioScanRole ({
% for pad in list(reversed(muxed_pads)):
scan_role_pkg::${lib.Name.from_snake_case('mio_pad_' + pad["name"] + '_scan_role').as_camel_case()}${"" if loop.last else ","}
% endfor
}),
.DioPadBank ({
% for pad in list(reversed(dedicated_pads)):
${lib.Name.from_snake_case('io_bank_' + pad["bank"]).as_camel_case()}${" " if loop.last else ","} // ${pad['name']}
% endfor
}),
.MioPadBank ({
% for pad in list(reversed(muxed_pads)):
${lib.Name.from_snake_case('io_bank_' + pad["bank"]).as_camel_case()}${" " if loop.last else ","} // ${pad['name']}
% endfor
}),
% endif
\
\
.DioPadType ({
% for pad in list(reversed(dedicated_pads)):
${pad["type"]}${" " if loop.last else ","} // ${pad['name']}
% endfor
}),
.MioPadType ({
% for pad in list(reversed(muxed_pads)):
${pad["type"]}${" " if loop.last else ","} // ${pad['name']}
% endfor
})
) u_padring (
// This is only used for scan and DFT purposes
% if target["name"] == "asic":
.clk_scan_i ( ast_base_clks.clk_sys ),
.scanmode_i ( scanmode ),
% else:
.clk_scan_i ( 1'b0 ),
.scanmode_i ( prim_mubi_pkg::MuBi4False ),
% endif
.dio_in_raw_o ( ),
// Chip IOs
.dio_pad_io ({
% for pad in list(reversed(dedicated_pads)):
% if re.match(r"`INOUT_A?", pad["port_type"]):
`ifdef ANALOGSIM
'0,
`else
${pad["name"]}${"" if loop.last else ","}
`endif
% else:
${pad["name"]}${"" if loop.last else ","}
% endif
% endfor
}),
.mio_pad_io ({
% for pad in list(reversed(muxed_pads)):
% if re.match(r"`INOUT_A?", pad["port_type"]):
`ifdef ANALOGSIM
'0,
`else
${pad["name"]}${"" if loop.last else ","}
`endif
% else:
${pad["name"]}${"" if loop.last else ","}
% endif
% endfor
}),
// Core-facing
% for port in ["in_o", "out_i", "oe_i", "attr_i"]:
.dio_${port} ({
% for pad in list(reversed(dedicated_pads)):
<%
sig = get_dio_sig(pinmux, pad)
%>\
% if sig is None:
manual_${port[:-2]}_${pad["name"].lower()}${"" if loop.last else ","}
% else:
dio_${port[:-2]}[${lib.get_io_enum_literal(sig, 'dio')}]${"" if loop.last else ","}
% endif
% endfor
}),
% endfor
% for port in ["in_o", "out_i", "oe_i", "attr_i", "in_raw_o"]:
<%
sig_name = 'mio_' + port[:-2]
indices = list(reversed(list(pad['idx'] for pad in muxed_pads)))
%>\
.mio_${port} (${lib.make_bit_concatenation(sig_name, indices, 6)})${"" if loop.last else ","}
% endfor
);
###################################################################
## USB for CW305 ##
###################################################################
% if target["name"] == "cw305":
logic usb_dp_pullup_en;
logic usb_dn_pullup_en;
logic usb_rx_d;
logic usb_tx_d;
logic usb_tx_se0;
logic usb_tx_use_d_se0;
logic usb_rx_enable;
// Connect the DP pad
assign dio_in[DioUsbdevUsbDp] = manual_in_usb_p;
assign manual_out_usb_p = dio_out[DioUsbdevUsbDp];
assign manual_oe_usb_p = dio_oe[DioUsbdevUsbDp];
assign manual_attr_usb_p = dio_attr[DioUsbdevUsbDp];
// Connect the DN pad
assign dio_in[DioUsbdevUsbDn] = manual_in_usb_n;
assign manual_out_usb_n = dio_out[DioUsbdevUsbDn];
assign manual_oe_usb_n = dio_oe[DioUsbdevUsbDn];
assign manual_attr_usb_n = dio_attr[DioUsbdevUsbDn];
// Connect DN pullup
assign manual_out_io_usb_dnpullup0 = usb_dn_pullup_en;
assign manual_oe_io_usb_dnpullup0 = 1'b1;
assign manual_attr_io_dnpullup0 = '0;
// Connect DP pullup
assign manual_out_io_usb_dppullup0 = usb_dp_pullup_en;
assign manual_oe_io_usb_dppullup0 = 1'b1;
assign manual_attr_io_dppullup0 = '0;
// Tie-off unused signals
assign usb_rx_d = 1'b0;
% endif
###################################################################
## USB for CW310 ##
###################################################################
% if target["name"] == "cw310":
// TODO: generalize this USB mux code and align with other tops.
// Only use the UPHY on CW310, which does not support pin flipping.
logic usb_dp_pullup_en;
logic usb_dn_pullup_en;
logic usb_rx_d;
logic usb_tx_d;
logic usb_tx_se0;
logic usb_rx_enable;
// DioUsbdevUsbDn
assign manual_attr_io_usb_dn_tx = '0;
assign manual_out_io_usb_dn_tx = dio_out[DioUsbdevUsbDn];
assign manual_oe_io_usb_dn_tx = 1'b1;
assign dio_in[DioUsbdevUsbDn] = manual_in_io_usb_dn_rx;
// DioUsbdevUsbDp
assign manual_attr_io_usb_dp_tx = '0;
assign manual_out_io_usb_dp_tx = dio_out[DioUsbdevUsbDp];
assign manual_oe_io_usb_dp_tx = 1'b1;
assign dio_in[DioUsbdevUsbDp] = manual_in_io_usb_dp_rx;
assign manual_attr_io_usb_oe_n = '0;
assign manual_out_io_usb_oe_n = ~dio_oe[DioUsbdevUsbDp];
assign manual_oe_io_usb_oe_n = 1'b1;
// DioUsbdevD
assign manual_attr_io_usb_d_rx = '0;
assign usb_rx_d = manual_in_io_usb_d_rx;
// Pull-up / soft connect pin
assign manual_attr_io_usb_connect = '0;
assign manual_out_io_usb_connect = usb_dp_pullup_en;
assign manual_oe_io_usb_connect = 1'b1;
// Set SPD to full-speed
assign manual_attr_io_usb_speed = '0;
assign manual_out_io_usb_speed = 1'b1;
assign manual_oe_io_usb_speed = 1'b1;
// TUSB1106 low-power mode
assign manual_attr_io_usb_suspend = '0;
assign manual_out_io_usb_suspend = !usb_rx_enable;
assign manual_oe_io_usb_suspend = 1'b1;
logic unused_usb_sigs;
assign unused_usb_sigs = ^{
usb_dn_pullup_en,
usb_tx_d,
usb_tx_se0,
manual_in_io_usb_connect,
manual_in_io_usb_oe_n,
manual_in_io_usb_speed,
manual_in_io_usb_suspend,
// DP and DN are broken out into multiple unidirectional pins
dio_oe[DioUsbdevUsbDp],
dio_oe[DioUsbdevUsbDn],
dio_attr[DioUsbdevUsbDp],
dio_attr[DioUsbdevUsbDn]
};
% endif
###################################################################
## AST For all targets ##
###################################################################
//////////////////////////////////
// AST - Common for all targets //
//////////////////////////////////
// pwrmgr interface
pwrmgr_pkg::pwr_ast_req_t base_ast_pwr;
pwrmgr_pkg::pwr_ast_rsp_t ast_base_pwr;
// assorted ast status
ast_pkg::ast_pwst_t ast_pwst;
ast_pkg::ast_pwst_t ast_pwst_h;
// TLUL interface
tlul_pkg::tl_h2d_t base_ast_bus;
tlul_pkg::tl_d2h_t ast_base_bus;
// synchronization clocks / rests
clkmgr_pkg::clkmgr_out_t clkmgr_aon_clocks;
rstmgr_pkg::rstmgr_out_t rstmgr_aon_resets;
// external clock
logic ext_clk;
// monitored clock
logic sck_monitor;
// observe interface
logic [7:0] fla_obs;
logic [7:0] otp_obs;
ast_pkg::ast_obs_ctrl_t obs_ctrl;
// otp power sequence
otp_ctrl_pkg::otp_ast_req_t otp_ctrl_otp_ast_pwr_seq;
otp_ctrl_pkg::otp_ast_rsp_t otp_ctrl_otp_ast_pwr_seq_h;
logic usb_ref_pulse;
logic usb_ref_val;
// adc
ast_pkg::adc_ast_req_t adc_req;
ast_pkg::adc_ast_rsp_t adc_rsp;
// entropy source interface
// The entropy source pacakge definition should eventually be moved to es
entropy_src_pkg::entropy_src_rng_req_t es_rng_req;
entropy_src_pkg::entropy_src_rng_rsp_t es_rng_rsp;
logic es_rng_fips;
// entropy distribution network
edn_pkg::edn_req_t ast_edn_edn_req;
edn_pkg::edn_rsp_t ast_edn_edn_rsp;
// alerts interface
ast_pkg::ast_alert_rsp_t ast_alert_rsp;
ast_pkg::ast_alert_req_t ast_alert_req;
// Flash connections
prim_mubi_pkg::mubi4_t flash_bist_enable;
logic flash_power_down_h;
logic flash_power_ready_h;
// clock bypass req/ack
prim_mubi_pkg::mubi4_t io_clk_byp_req;
prim_mubi_pkg::mubi4_t io_clk_byp_ack;
prim_mubi_pkg::mubi4_t all_clk_byp_req;
prim_mubi_pkg::mubi4_t all_clk_byp_ack;
prim_mubi_pkg::mubi4_t hi_speed_sel;
prim_mubi_pkg::mubi4_t div_step_down_req;
// DFT connections
logic scan_en;
lc_ctrl_pkg::lc_tx_t dft_en;
pinmux_pkg::dft_strap_test_req_t dft_strap_test;
// Debug connections
logic [ast_pkg::Ast2PadOutWidth-1:0] ast2pinmux;
logic [ast_pkg::Pad2AstInWidth-1:0] pad2ast;
// Jitter enable
prim_mubi_pkg::mubi4_t jen;
// reset domain connections
import rstmgr_pkg::PowerDomains;
import rstmgr_pkg::DomainAonSel;
import rstmgr_pkg::Domain0Sel;
// Memory configuration connections
ast_pkg::spm_rm_t ast_ram_1p_cfg;
ast_pkg::spm_rm_t ast_rf_cfg;
ast_pkg::spm_rm_t ast_rom_cfg;
ast_pkg::dpm_rm_t ast_ram_2p_fcfg;
ast_pkg::dpm_rm_t ast_ram_2p_lcfg;
prim_ram_1p_pkg::ram_1p_cfg_t ram_1p_cfg;
prim_ram_2p_pkg::ram_2p_cfg_t ram_2p_cfg;
prim_rom_pkg::rom_cfg_t rom_cfg;
// conversion from ast structure to memory centric structures
assign ram_1p_cfg = '{
ram_cfg: '{
cfg_en: ast_ram_1p_cfg.marg_en,
cfg: ast_ram_1p_cfg.marg
},
rf_cfg: '{
cfg_en: ast_rf_cfg.marg_en,
cfg: ast_rf_cfg.marg
}
};
assign ram_2p_cfg = '{
a_ram_fcfg: '{
cfg_en: ast_ram_2p_fcfg.marg_en_a,
cfg: ast_ram_2p_fcfg.marg_a
},
a_ram_lcfg: '{
cfg_en: ast_ram_2p_lcfg.marg_en_a,
cfg: ast_ram_2p_lcfg.marg_a
},
b_ram_fcfg: '{
cfg_en: ast_ram_2p_fcfg.marg_en_b,
cfg: ast_ram_2p_fcfg.marg_b
},
b_ram_lcfg: '{
cfg_en: ast_ram_2p_lcfg.marg_en_b,
cfg: ast_ram_2p_lcfg.marg_b
}
};
assign rom_cfg = '{
cfg_en: ast_rom_cfg.marg_en,
cfg: ast_rom_cfg.marg
};
//////////////////////////////////
// AST - Custom for targets //
//////////////////////////////////
<%
ast = [m for m in top["module"] if m["name"] == "ast"]
assert(len(ast) == 1)
ast = ast[0]
%>\
assign ast_base_pwr.main_pok = ast_pwst.main_pok;
logic [rstmgr_pkg::PowerDomains-1:0] por_n;
assign por_n = {ast_pwst.main_pok, ast_pwst.aon_pok};
% if target["name"] == "asic":
logic [ast_pkg::UsbCalibWidth-1:0] usb_io_pu_cal;
// external clock comes in at a fixed position
assign ext_clk = mio_in_raw[MioPadIoc6];
assign pad2ast = { manual_in_ast_misc,
mio_in_raw[MioPadIoc3],
mio_in_raw[MioPadIoc2],
mio_in_raw[MioPadIoc1],
mio_in_raw[MioPadIob2],
mio_in_raw[MioPadIob1],
mio_in_raw[MioPadIob0],
mio_in_raw[MioPadIoa5],
mio_in_raw[MioPadIoa4]
};
// AST does not use all clocks / resets forwarded to it
logic unused_slow_clk_en;
assign unused_slow_clk_en = base_ast_pwr.slow_clk_en;
logic unused_pwr_clamp;
assign unused_pwr_clamp = base_ast_pwr.pwr_clamp;
logic usb_diff_rx_obs;
% else:
// TODO: Hook this up when FPGA pads are updated
assign ext_clk = '0;
assign pad2ast = '0;
logic clk_main, clk_usb_48mhz, clk_aon, rst_n, srst_n;
clkgen_xil7series # (
.AddClkBuf(0)
) clkgen (
.clk_i(manual_in_io_clk),
.rst_ni(manual_in_por_n),
.srst_ni(srst_n),
.clk_main_o(clk_main),
.clk_48MHz_o(clk_usb_48mhz),
.clk_aon_o(clk_aon),
.rst_no(rst_n)
);
logic [31:0] fpga_info;
usr_access_xil7series u_info (
.info_o(fpga_info)
);
ast_pkg::clks_osc_byp_t clks_osc_byp;
assign clks_osc_byp = '{
usb: clk_usb_48mhz,
sys: clk_main,
io: clk_main,
aon: clk_aon
};
% endif
prim_mubi_pkg::mubi4_t ast_init_done;
ast #(
.EntropyStreams(ast_pkg::EntropyStreams),
.AdcChannels(ast_pkg::AdcChannels),
.AdcDataWidth(ast_pkg::AdcDataWidth),
.UsbCalibWidth(ast_pkg::UsbCalibWidth),
.Ast2PadOutWidth(ast_pkg::Ast2PadOutWidth),
.Pad2AstInWidth(ast_pkg::Pad2AstInWidth)
) u_ast (
% if target["name"] == "asic":
// external POR
.por_ni ( manual_in_por_n ),
// USB IO Pull-up Calibration Setting
.usb_io_pu_cal_o ( usb_io_pu_cal ),
// adc
.adc_a0_ai ( CC1 ),
.adc_a1_ai ( CC2 ),
// Direct short to PAD
.ast2pad_t0_ao ( IOA2 ),
.ast2pad_t1_ao ( IOA3 ),
% else:
// external POR
.por_ni ( rst_n ),
// USB IO Pull-up Calibration Setting
.usb_io_pu_cal_o ( ),
// clocks' oschillator bypass for FPGA
.clk_osc_byp_i ( clks_osc_byp ),
// adc
.adc_a0_ai ( '0 ),
.adc_a1_ai ( '0 ),
// Direct short to PAD
.ast2pad_t0_ao ( ),
.ast2pad_t1_ao ( ),
% endif
// clocks and resets supplied for detection
.sns_clks_i ( clkmgr_aon_clocks ),
.sns_rsts_i ( rstmgr_aon_resets ),
.sns_spi_ext_clk_i ( sck_monitor ),
// tlul
.tl_i ( base_ast_bus ),
.tl_o ( ast_base_bus ),
// init done indication
.ast_init_done_o ( ast_init_done ),
// buffered clocks & resets
% for port, clk in ast["clock_connections"].items():
.${port} (${clk}),
% endfor
% for port, reset in ast["reset_connections"].items():
.${port} (${lib.get_reset_path(top, reset)}),
% endfor
.clk_ast_ext_i ( ext_clk ),
// pok test for FPGA
.vcc_supp_i ( 1'b1 ),
.vcaon_supp_i ( 1'b1 ),
.vcmain_supp_i ( 1'b1 ),
.vioa_supp_i ( 1'b1 ),
.viob_supp_i ( 1'b1 ),
// pok
.ast_pwst_o ( ast_pwst ),
.ast_pwst_h_o ( ast_pwst_h ),
// main regulator
.main_env_iso_en_i ( base_ast_pwr.pwr_clamp_env ),
.main_pd_ni ( base_ast_pwr.main_pd_n ),
// pdm control (flash)/otp
.flash_power_down_h_o ( flash_power_down_h ),
.flash_power_ready_h_o ( flash_power_ready_h ),
.otp_power_seq_i ( otp_ctrl_otp_ast_pwr_seq ),
.otp_power_seq_h_o ( otp_ctrl_otp_ast_pwr_seq_h ),
// system source clock
.clk_src_sys_en_i ( base_ast_pwr.core_clk_en ),
// need to add function in clkmgr
.clk_src_sys_jen_i ( jen ),
.clk_src_sys_o ( ast_base_clks.clk_sys ),
.clk_src_sys_val_o ( ast_base_pwr.core_clk_val ),
// aon source clock
.clk_src_aon_o ( ast_base_clks.clk_aon ),
.clk_src_aon_val_o ( ast_base_pwr.slow_clk_val ),
// io source clock
.clk_src_io_en_i ( base_ast_pwr.io_clk_en ),
.clk_src_io_o ( ast_base_clks.clk_io ),
.clk_src_io_val_o ( ast_base_pwr.io_clk_val ),
.clk_src_io_48m_o ( div_step_down_req ),
// usb source clock
.usb_ref_pulse_i ( usb_ref_pulse ),
.usb_ref_val_i ( usb_ref_val ),
.clk_src_usb_en_i ( base_ast_pwr.usb_clk_en ),
.clk_src_usb_o ( ast_base_clks.clk_usb ),
.clk_src_usb_val_o ( ast_base_pwr.usb_clk_val ),
// adc
.adc_pd_i ( adc_req.pd ),
.adc_chnsel_i ( adc_req.channel_sel ),
.adc_d_o ( adc_rsp.data ),
.adc_d_val_o ( adc_rsp.data_valid ),
// rng
.rng_en_i ( es_rng_req.rng_enable ),
.rng_fips_i ( es_rng_fips ),
.rng_val_o ( es_rng_rsp.rng_valid ),
.rng_b_o ( es_rng_rsp.rng_b ),
// entropy
.entropy_rsp_i ( ast_edn_edn_rsp ),
.entropy_req_o ( ast_edn_edn_req ),
// alerts
.alert_rsp_i ( ast_alert_rsp ),
.alert_req_o ( ast_alert_req ),
// dft
.dft_strap_test_i ( dft_strap_test ),
.lc_dft_en_i ( dft_en ),
.fla_obs_i ( fla_obs ),
.otp_obs_i ( otp_obs ),
.otm_obs_i ( '0 ),
.usb_obs_i ( usb_diff_rx_obs ),
.obs_ctrl_o ( obs_ctrl ),
// pinmux related
.padmux2ast_i ( pad2ast ),
.ast2padmux_o ( ast2pinmux ),
.ext_freq_is_96m_i ( hi_speed_sel ),
.all_clk_byp_req_i ( all_clk_byp_req ),
.all_clk_byp_ack_o ( all_clk_byp_ack ),
.io_clk_byp_req_i ( io_clk_byp_req ),
.io_clk_byp_ack_o ( io_clk_byp_ack ),
.flash_bist_en_o ( flash_bist_enable ),
// Memory configuration connections
.dpram_rmf_o ( ast_ram_2p_fcfg ),
.dpram_rml_o ( ast_ram_2p_lcfg ),
.spram_rm_o ( ast_ram_1p_cfg ),
.sprgf_rm_o ( ast_rf_cfg ),
.sprom_rm_o ( ast_rom_cfg ),
// scan
.dft_scan_md_o ( scanmode ),
.scan_shift_en_o ( scan_en ),
.scan_reset_no ( scan_rst_n )
);
###################################################################
## ASIC ##
###################################################################
% if target["name"] == "asic":
//////////////////////////////////
// Manual Pad / Signal Tie-offs //
//////////////////////////////////
assign manual_out_ast_misc = 1'b0;
assign manual_oe_ast_misc = 1'b0;
always_comb begin
// constantly enable pull-down
manual_attr_ast_misc = '0;
manual_attr_ast_misc.pull_select = 1'b0;
manual_attr_ast_misc.pull_en = 1'b1;
end
assign manual_out_por_n = 1'b0;
assign manual_oe_por_n = 1'b0;
assign manual_out_cc1 = 1'b0;
assign manual_oe_cc1 = 1'b0;
assign manual_out_cc2 = 1'b0;
assign manual_oe_cc2 = 1'b0;
assign manual_out_flash_test_mode0 = 1'b0;
assign manual_oe_flash_test_mode0 = 1'b0;
assign manual_out_flash_test_mode1 = 1'b0;
assign manual_oe_flash_test_mode1 = 1'b0;
assign manual_out_flash_test_volt = 1'b0;
assign manual_oe_flash_test_volt = 1'b0;
assign manual_out_otp_ext_volt = 1'b0;
assign manual_oe_otp_ext_volt = 1'b0;
// These pad attributes currently tied off permanently (these are all input-only pads).
assign manual_attr_por_n = '0;
assign manual_attr_cc1 = '0;
assign manual_attr_cc2 = '0;
assign manual_attr_flash_test_mode0 = '0;
assign manual_attr_flash_test_mode1 = '0;
assign manual_attr_flash_test_volt = '0;
assign manual_attr_otp_ext_volt = '0;
logic unused_manual_sigs;
assign unused_manual_sigs = ^{
manual_in_cc2,
manual_in_cc1,
manual_in_flash_test_volt,
manual_in_flash_test_mode0,
manual_in_flash_test_mode1,
manual_in_otp_ext_volt
};
///////////////////////////////
// Differential USB Receiver //
///////////////////////////////
// TODO: generalize this USB mux code and align with other tops.
// Connect the D+ pad
// Note that we use two pads in parallel for the D+ channel to meet electrical specifications.
assign dio_in[DioUsbdevUsbDp] = manual_in_usb_p;
assign manual_out_usb_p = dio_out[DioUsbdevUsbDp];
assign manual_oe_usb_p = dio_oe[DioUsbdevUsbDp];
assign manual_attr_usb_p = dio_attr[DioUsbdevUsbDp];
// Connect the D- pads
// Note that we use two pads in parallel for the D- channel to meet electrical specifications.
assign dio_in[DioUsbdevUsbDn] = manual_in_usb_n;
assign manual_out_usb_n = dio_out[DioUsbdevUsbDn];
assign manual_oe_usb_n = dio_oe[DioUsbdevUsbDn];
assign manual_attr_usb_n = dio_attr[DioUsbdevUsbDn];
logic usb_rx_d;
// Pullups and differential receiver enable
logic usb_dp_pullup_en, usb_dn_pullup_en;
logic usb_rx_enable;
prim_usb_diff_rx #(
.CalibW(ast_pkg::UsbCalibWidth)
) u_prim_usb_diff_rx (
.input_pi ( USB_P ),
.input_ni ( USB_N ),
.input_en_i ( usb_rx_enable ),
.core_pok_h_i ( ast_pwst_h.aon_pok ),
.pullup_p_en_i ( usb_dp_pullup_en ),
.pullup_n_en_i ( usb_dn_pullup_en ),
.calibration_i ( usb_io_pu_cal ),
.usb_diff_rx_obs_o ( usb_diff_rx_obs ),
.input_o ( usb_rx_d )
);
//////////////////////
// Top-level design //
//////////////////////
top_${top["name"]} #(
% if target["name"] != "asic":
.PinmuxAonTargetCfg(PinmuxTargetCfg)
% else:
.PinmuxAonTargetCfg(PinmuxTargetCfg),
.SecAesAllowForcingMasks(1'b1),
.SecRomCtrlDisableScrambling(SecRomCtrlDisableScrambling)
% endif
) top_${top["name"]} (
// ast connections
.por_n_i ( por_n ),
.clk_main_i ( ast_base_clks.clk_sys ),
.clk_io_i ( ast_base_clks.clk_io ),
.clk_usb_i ( ast_base_clks.clk_usb ),
.clk_aon_i ( ast_base_clks.clk_aon ),
.clks_ast_o ( clkmgr_aon_clocks ),
.clk_main_jitter_en_o ( jen ),
.rsts_ast_o ( rstmgr_aon_resets ),
.sck_monitor_o ( sck_monitor ),
.pwrmgr_ast_req_o ( base_ast_pwr ),
.pwrmgr_ast_rsp_i ( ast_base_pwr ),
.sensor_ctrl_ast_alert_req_i ( ast_alert_req ),
.sensor_ctrl_ast_alert_rsp_o ( ast_alert_rsp ),
.sensor_ctrl_ast_status_i ( ast_pwst.io_pok ),
.usb_dp_pullup_en_o ( usb_dp_pullup_en ),
.usb_dn_pullup_en_o ( usb_dn_pullup_en ),
.usbdev_usb_rx_d_i ( usb_rx_d ),
.usbdev_usb_tx_d_o ( ),
.usbdev_usb_tx_se0_o ( ),
.usbdev_usb_tx_use_d_se0_o ( ),
.usbdev_usb_rx_enable_o ( usb_rx_enable ),
.usbdev_usb_ref_val_o ( usb_ref_val ),
.usbdev_usb_ref_pulse_o ( usb_ref_pulse ),
.ast_tl_req_o ( base_ast_bus ),
.ast_tl_rsp_i ( ast_base_bus ),
.adc_req_o ( adc_req ),
.adc_rsp_i ( adc_rsp ),
.ast_edn_req_i ( ast_edn_edn_req ),
.ast_edn_rsp_o ( ast_edn_edn_rsp ),
.obs_ctrl_i ( obs_ctrl ),
.otp_ctrl_otp_ast_pwr_seq_o ( otp_ctrl_otp_ast_pwr_seq ),
.otp_ctrl_otp_ast_pwr_seq_h_i ( otp_ctrl_otp_ast_pwr_seq_h ),
.otp_obs_o ( otp_obs ),
.flash_bist_enable_i ( flash_bist_enable ),
.flash_power_down_h_i ( flash_power_down_h ),
.flash_power_ready_h_i ( flash_power_ready_h ),
.flash_obs_o ( fla_obs ),
.es_rng_req_o ( es_rng_req ),
.es_rng_rsp_i ( es_rng_rsp ),
.es_rng_fips_o ( es_rng_fips ),
.io_clk_byp_req_o ( io_clk_byp_req ),
.io_clk_byp_ack_i ( io_clk_byp_ack ),
.all_clk_byp_req_o ( all_clk_byp_req ),
.all_clk_byp_ack_i ( all_clk_byp_ack ),
.hi_speed_sel_o ( hi_speed_sel ),
.div_step_down_req_i ( div_step_down_req ),
.ast2pinmux_i ( ast2pinmux ),
.calib_rdy_i ( ast_init_done ),
.ast_init_done_i ( ast_init_done ),
// Flash test mode voltages
.flash_test_mode_a_io ( {FLASH_TEST_MODE1,
FLASH_TEST_MODE0} ),
.flash_test_voltage_h_io ( FLASH_TEST_VOLT ),
// OTP external voltage
.otp_ext_voltage_h_io ( OTP_EXT_VOLT ),
// Multiplexed I/O
.mio_in_i ( mio_in ),
.mio_out_o ( mio_out ),
.mio_oe_o ( mio_oe ),
// Dedicated I/O
.dio_in_i ( dio_in ),
.dio_out_o ( dio_out ),
.dio_oe_o ( dio_oe ),
// Pad attributes
.mio_attr_o ( mio_attr ),
.dio_attr_o ( dio_attr ),
// Memory attributes
.ram_1p_cfg_i ( ram_1p_cfg ),
.ram_2p_cfg_i ( ram_2p_cfg ),
.rom_cfg_i ( rom_cfg ),
// DFT signals
.ast_lc_dft_en_o ( dft_en ),
.dft_strap_test_o ( dft_strap_test ),
.dft_hold_tap_sel_i ( '0 ),
.scan_rst_ni ( scan_rst_n ),
.scan_en_i ( scan_en ),
.scanmode_i ( scanmode ),
// FPGA build info
.fpga_info_i ( '0 )
);
% endif
###################################################################
## FPGA shared ##
###################################################################
% if target["name"] in ["cw310", "cw305"]:
//////////////////
// PLL for FPGA //
//////////////////
assign manual_attr_io_clk = '0;
assign manual_out_io_clk = 1'b0;
assign manual_oe_io_clk = 1'b0;
assign manual_attr_por_n = '0;
assign manual_out_por_n = 1'b0;
assign manual_oe_por_n = 1'b0;
assign manual_attr_por_button_n = '0;
assign manual_out_por_button_n = 1'b0;
assign manual_oe_por_button_n = 1'b0;
% if target["name"] == "cw305":
assign srst_n = manual_in_por_button_n;
% elif target["name"] == "cw310":
assign srst_n = manual_in_por_button_n & manual_in_jtag_srst_n;
assign manual_attr_jtag_srst_n = '0;
assign manual_out_jtag_srst_n = 1'b0;
assign manual_oe_jtag_srst_n = 1'b0;
% endif
% if target["name"] == "cw305":
// TODO: follow-up later and hardwire all ast connects that do not
// exist for this target
assign otp_obs_o = '0;
% endif
//////////////////////
// Top-level design //
//////////////////////
// the rst_ni pin only goes to AST
// the rest of the logic generates reset based on the 'pok' signal.
// for verilator purposes, make these two the same.
prim_mubi_pkg::mubi4_t lc_clk_bypass; // TODO Tim
// TODO: align this with ASIC version to minimize the duplication.
// Also need to add AST simulation and FPGA emulation models for things like entropy source -
// otherwise Verilator / FPGA will hang.
top_${top["name"]} #(
% if target["name"] == "cw310":
.SecAesMasking(1'b1),
.SecAesSBoxImpl(aes_pkg::SBoxImplDom),
.SecAesStartTriggerDelay(40),
.SecAesAllowForcingMasks(1'b1),
.KmacEnMasking(0),
.KmacSwKeyMasked(1),
.SecKmacCmdDelay(40),
.SecKmacIdleAcceptSwMsg(1'b1),
.KeymgrKmacEnMasking(0),
.CsrngSBoxImpl(aes_pkg::SBoxImplLut),
.OtbnRegFile(otbn_pkg::RegFileFPGA),
.SecOtbnMuteUrnd(1'b1),
.SecOtbnSkipUrndReseedAtStart(1'b1),
.OtpCtrlMemInitFile(OtpCtrlMemInitFile),
.UsbdevRcvrWakeTimeUs(10000),
% elif target["name"] == "cw305":
.SecAesMasking(1'b1),
.SecAesSBoxImpl(aes_pkg::SBoxImplDom),
.SecAesStartTriggerDelay(40),
.SecAesAllowForcingMasks(1'b1),
.SecAesSkipPRNGReseeding(1'b1),
.UsbdevStub(1'b1),
% else:
.SecAesMasking(1'b0),
.SecAesSBoxImpl(aes_pkg::SBoxImplLut),
.KmacEnMasking(1'b0),
.KeymgrKmacEnMasking(0),
.SecAesStartTriggerDelay(0),
.SecAesAllowForcingMasks(1'b0),
.SecAesSkipPRNGReseeding(1'b0),
.EntropySrcStub(1'b1),
.CsrngSBoxImpl(aes_pkg::SBoxImplLut),
.OtbnRegFile(otbn_pkg::RegFileFPGA),
.OtbnStub(1'b1),
.OtpCtrlMemInitFile(OtpCtrlMemInitFile),
% endif
.RomCtrlBootRomInitFile(BootRomInitFile),
.RvCoreIbexRegFile(ibex_pkg::RegFileFPGA),
.RvCoreIbexPipeLine(1),
.RvCoreIbexSecureIbex(0),
.SramCtrlRetAonInstrExec(0),
.SramCtrlMainInstrExec(1),
.PinmuxAonTargetCfg(PinmuxTargetCfg)
) top_${top["name"]} (
.por_n_i ( por_n ),
.clk_main_i ( ast_base_clks.clk_sys ),
.clk_io_i ( ast_base_clks.clk_io ),
.clk_usb_i ( ast_base_clks.clk_usb ),
.clk_aon_i ( ast_base_clks.clk_aon ),
.clks_ast_o ( clkmgr_aon_clocks ),
.clk_main_jitter_en_o ( jen ),
.rsts_ast_o ( rstmgr_aon_resets ),
.sck_monitor_o ( sck_monitor ),
.pwrmgr_ast_req_o ( base_ast_pwr ),
.pwrmgr_ast_rsp_i ( ast_base_pwr ),
.usb_dp_pullup_en_o ( usb_dp_pullup_en ),
.usb_dn_pullup_en_o ( usb_dn_pullup_en ),
.usbdev_usb_rx_d_i ( usb_rx_d ),
.usbdev_usb_tx_d_o ( usb_tx_d ),
.usbdev_usb_tx_se0_o ( usb_tx_se0 ),
.usbdev_usb_tx_use_d_se0_o ( usb_tx_use_d_se0 ),
.usbdev_usb_rx_enable_o ( usb_rx_enable ),
.usbdev_usb_ref_val_o ( usb_ref_val ),
.usbdev_usb_ref_pulse_o ( usb_ref_pulse ),
.ast_edn_req_i ( ast_edn_edn_req ),
.ast_edn_rsp_o ( ast_edn_edn_rsp ),
.obs_ctrl_i ( obs_ctrl ),
.flash_bist_enable_i ( flash_bist_enable ),
.flash_power_down_h_i ( 1'b0 ),
.flash_power_ready_h_i ( 1'b1 ),
.flash_obs_o ( flash_obs ),
.io_clk_byp_req_o ( io_clk_byp_req ),
.io_clk_byp_ack_i ( io_clk_byp_ack ),
.all_clk_byp_req_o ( all_clk_byp_req ),
.all_clk_byp_ack_i ( all_clk_byp_ack ),
.hi_speed_sel_o ( hi_speed_sel ),
.div_step_down_req_i ( div_step_down_req ),
.fpga_info_i ( fpga_info ),
% if target["name"] != "cw305":
.ast_tl_req_o ( base_ast_bus ),
.ast_tl_rsp_i ( ast_base_bus ),
.adc_req_o ( adc_req ),
.adc_rsp_i ( adc_rsp ),
.otp_ctrl_otp_ast_pwr_seq_o ( otp_ctrl_otp_ast_pwr_seq ),
.otp_ctrl_otp_ast_pwr_seq_h_i ( otp_ctrl_otp_ast_pwr_seq_h ),
.otp_obs_o ( otp_obs ),
.sensor_ctrl_ast_alert_req_i ( ast_alert_req ),
.sensor_ctrl_ast_alert_rsp_o ( ast_alert_rsp ),
.sensor_ctrl_ast_status_i ( ast_pwst.io_pok ),
.es_rng_req_o ( es_rng_req ),
.es_rng_rsp_i ( es_rng_rsp ),
.es_rng_fips_o ( es_rng_fips ),
.ast2pinmux_i ( ast2pinmux ),
.calib_rdy_i ( ast_init_done ),
.ast_init_done_i ( ast_init_done ),
% endif
// Multiplexed I/O
.mio_in_i ( mio_in ),
.mio_out_o ( mio_out ),
.mio_oe_o ( mio_oe ),
// Dedicated I/O
.dio_in_i ( dio_in ),
.dio_out_o ( dio_out ),
.dio_oe_o ( dio_oe ),
// Pad attributes
.mio_attr_o ( mio_attr ),
.dio_attr_o ( dio_attr ),
// Memory attributes
.ram_1p_cfg_i ( '0 ),
.ram_2p_cfg_i ( '0 ),
.rom_cfg_i ( '0 ),
// DFT signals
.dft_hold_tap_sel_i ( '0 ),
.scan_rst_ni ( 1'b1 ),
.scan_en_i ( 1'b0 ),
.scanmode_i ( prim_mubi_pkg::MuBi4False )
);
% endif
###################################################################
## CW310/305 capture board interface ##
###################################################################
% if target["name"] in ["cw310", "cw305"]:
/////////////////////////////////////////////////////
// ChipWhisperer CW310/305 Capture Board Interface //
/////////////////////////////////////////////////////
// This is used to interface OpenTitan as a target with a capture board trough the ChipWhisperer
// 20-pin connector. This is used for SCA/FI experiments only.
logic unused_inputs;
% if target["name"] == "cw305":
assign unused_inputs = manual_in_io_clkout ^ manual_in_io_trigger ^ manual_in_io_utx_debug;
% else:
assign unused_inputs = manual_in_io_clkout ^ manual_in_io_trigger;
% endif
// Synchronous clock output to capture board.
assign manual_out_io_clkout = manual_in_io_clk;
assign manual_oe_io_clkout = 1'b1;
// Capture trigger.
// We use the clkmgr_aon_idle signal of the IP of interest to form a precise capture trigger.
// GPIO[11:9] is used for selecting the IP of interest. The encoding is as follows (see
// hint_names_e enum in clkmgr_pkg.sv for details).
//
// IP - GPIO[11:9] - Index for clkmgr_aon_idle
// ------------------------------------------------------------
// AES - 000 - 0
// HMAC - 001 - 1
// KMAC - 010 - 2 - not implemented on CW305
// OTBN (IO_DIV4) - 011 - 3 - not implemented on CW305
// OTBN - 100 - 4 - not implemented on CW305
//
// In addition, GPIO8 is used for gating the capture trigger in software.
// Note that GPIO[11:8] are connected to LED[3:0] on the CW310.
// On the CW305, GPIO[9,8] are connected to LED[5,7].
clkmgr_pkg::hint_names_e trigger_sel;
% if target["name"] == "cw305":
assign trigger_sel = mio_out[MioOutGpioGpio9] ? clkmgr_pkg::HintMainHmac :
clkmgr_pkg::HintMainAes;
% else:
always_comb begin : trigger_sel_mux
unique case ({mio_out[MioOutGpioGpio11], mio_out[MioOutGpioGpio10], mio_out[MioOutGpioGpio9]})
3'b000: trigger_sel = clkmgr_pkg::HintMainAes;
3'b001: trigger_sel = clkmgr_pkg::HintMainHmac;
3'b010: trigger_sel = clkmgr_pkg::HintMainKmac;
3'b100: trigger_sel = clkmgr_pkg::HintMainOtbn;
default: trigger_sel = clkmgr_pkg::HintMainAes;
endcase;
end
% endif
prim_mubi_pkg::mubi4_t clk_trans_idle, manual_in_io_clk_idle;
assign clk_trans_idle = top_${top["name"]}.clkmgr_aon_idle[trigger_sel];
logic clk_io_div4_trigger_en, manual_in_io_clk_trigger_en;
logic clk_io_div4_trigger_oe, manual_in_io_clk_trigger_oe;
assign clk_io_div4_trigger_en = mio_out[MioOutGpioGpio8];
assign clk_io_div4_trigger_oe = mio_oe[MioOutGpioGpio8];
// Synchronize signals to manual_in_io_clk.
prim_flop_2sync #(
.Width ($bits(clk_trans_idle) + 2)
) u_sync_trigger (
.clk_i (manual_in_io_clk),
.rst_ni(manual_in_por_n),
.d_i ({clk_trans_idle, clk_io_div4_trigger_en, clk_io_div4_trigger_oe}),
.q_o ({manual_in_io_clk_idle, manual_in_io_clk_trigger_en, manual_in_io_clk_trigger_oe})
);
// Generate the actual trigger signal.
assign manual_attr_io_trigger = '0;
assign manual_oe_io_trigger = manual_in_io_clk_trigger_oe;
assign manual_out_io_trigger = manual_in_io_clk_trigger_en &
prim_mubi_pkg::mubi4_test_false_strict(manual_in_io_clk_idle);
% endif
## This separate UART debugging output is needed for the CW305 only.
% if target["name"] == "cw305":
// UART Tx for debugging. The UART itself is connected to the capture board.
assign manual_out_io_utx_debug = top_${top["name"]}.cio_uart0_tx_d2p;
assign manual_oe_io_utx_debug = 1'b1;
% endif
endmodule : chip_${top["name"]}_${target["name"]}