diff --git a/hw/top_darjeeling/templates/toplevel.sv.tpl b/hw/top_darjeeling/templates/toplevel.sv.tpl index 0805edb7ae562d..fad412efe14d94 100644 --- a/hw/top_darjeeling/templates/toplevel.sv.tpl +++ b/hw/top_darjeeling/templates/toplevel.sv.tpl @@ -5,6 +5,7 @@ ${gencmd} <% import re import topgen.lib as lib +from reggen.params import Parameter from topgen.clocks import Clocks from topgen.resets import Resets @@ -22,7 +23,15 @@ 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"]]) +num_im = 0 +for x in top["inter_signal"]["external"]: + if "width" in x: + if isinstance(x["width"], Parameter): + num_im += x["width"].default + else: + num_im += x["width"] + else: + num_im += 1 max_sigwidth = max([x["width"] if "width" in x else 1 for x in top["pinmux"]["ios"]]) max_sigwidth = len("{}".format(max_sigwidth)) @@ -54,7 +63,7 @@ module top_${top["name"]} #( <% continue %> % endif // parameters for ${m['name']} - % for p_exp in [p for p in m["param_list"] if p.get("expose") == "true" ]: + % for p_exp in [p for p in m["param_list"] if p.get("local") == "false" and p.get("expose") == "true" ]: <% p_type = p_exp.get('type') p_type_word = p_type + ' ' if p_type else '' @@ -65,7 +74,7 @@ module top_${top["name"]} #( params_follow = not loop.last or loop.parent.index < last_modidx_with_params comma_char = ',' if params_follow else '' %>\ - % if 12 + len(p_lhs) + 3 + len(p_rhs) + 1 < 100: + % if 12 + len(p_lhs) + 3 + len(str(p_rhs)) + 1 < 100: parameter ${p_lhs} = ${p_rhs}${comma_char} % else: parameter ${p_lhs} = @@ -97,7 +106,11 @@ module top_${top["name"]} #( // Inter-module Signal External type % for sig in top["inter_signal"]["external"]: + % if isinstance(sig["width"], Parameter): + ${lib.get_direction(sig)} ${lib.im_defname(sig)} [${sig["width"].name_top}-1:0] ${sig["signame"]}, + % else: ${lib.get_direction(sig)} ${lib.im_defname(sig)} ${lib.bitarray(sig["width"],1)} ${sig["signame"]}, + % endif % endfor % endif @@ -123,6 +136,29 @@ module top_${top["name"]} #( // Compile-time random constants import top_${top["name"]}_rnd_cnst_pkg::*; + // Local Parameters +% for m in top["module"]: + % if not lib.is_inst(m): +<% continue %> + % endif + // local parameters for ${m['name']} + % for p_exp in [p for p in m["param_list"] if p.get("local") == "true" and 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 13 + len(p_lhs) + 3 + len(str(p_rhs)) + 1 < 100: + localparam ${p_lhs} = ${p_rhs}; + % else: + localparam ${p_lhs} = + ${p_rhs}; + % endif + % endfor +% endfor + // Signals logic [${num_mio_inputs - 1}:0] mio_p2d; logic [${num_mio_outputs - 1}:0] mio_d2p; @@ -189,7 +225,11 @@ module top_${top["name"]} #( // define inter-module signals % endif % for sig in top["inter_signal"]["definitions"]: + % if isinstance(sig["width"], Parameter): + ${lib.im_defname(sig)} [${sig["width"].name_top}-1:0] ${sig["signame"]}; + % else: ${lib.im_defname(sig)} ${lib.bitarray(sig["width"],1)} ${sig["signame"]}; + % endif % endfor ## Mixed connection to port @@ -215,19 +255,28 @@ module top_${top["name"]} #( ## 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']): +<% + width = sig['width'].default if isinstance(sig['width'], Parameter) else sig['width'] +%>\ + % for idx in range(sig['end_idx'], 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']): +<% + width = sig['width'].default if isinstance(sig['width'], Parameter) else sig['width'] +%>\ + % for idx in range(sig['end_idx'], 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']): +<% + width = sig['width'].default if isinstance(sig['width'], Parameter) else sig['width'] +%>\ + % for idx in range(sig['end_idx'], width): assign ${sig["signame"]}[${idx}] = ${sig["default"]}; % endfor % endfor diff --git a/hw/top_earlgrey/data/autogen/top_earlgrey.gen.hjson b/hw/top_earlgrey/data/autogen/top_earlgrey.gen.hjson index ab6543f08f5814..ef33bd4c1108c9 100644 --- a/hw/top_earlgrey/data/autogen/top_earlgrey.gen.hjson +++ b/hw/top_earlgrey/data/autogen/top_earlgrey.gen.hjson @@ -882,6 +882,7 @@ desc: Instantiates 2-flop synchronizers on all GPIO inputs if set to 1. type: bit default: "1" + local: "false" expose: "true" name_top: GpioGpioAsyncOn } @@ -890,6 +891,7 @@ desc: Enable HW straps sampling logic for GPIO inputs at initial cold boot type: bit default: "0" + local: "false" expose: "true" name_top: GpioGpioAsHwStrapsEn } @@ -977,6 +979,7 @@ desc: Sram Entries. Word size is 32bit width. type: spi_device_pkg::sram_type_e default: spi_device_pkg::DefaultSramType + local: "false" expose: "true" name_top: SpiDeviceSramType } @@ -1091,6 +1094,7 @@ ''' type: int default: "0" + local: "false" expose: "true" name_top: I2c0InputDelayCycles } @@ -1183,6 +1187,7 @@ ''' type: int default: "0" + local: "false" expose: "true" name_top: I2c1InputDelayCycles } @@ -1275,6 +1280,7 @@ ''' type: int default: "0" + local: "false" expose: "true" name_top: I2c2InputDelayCycles } @@ -1483,6 +1489,7 @@ desc: VMEM file to initialize the OTP macro. type: "" default: '''""''' + local: "false" expose: "true" name_top: OtpCtrlMemInitFile } @@ -1930,6 +1937,7 @@ ''' type: bit default: top_pkg::SecVolatileRawUnlockEn + local: "false" expose: "true" name_top: SecLcCtrlVolatileRawUnlockEn } @@ -1938,6 +1946,7 @@ desc: When 1, a TLUL-based DMI interface is used. When 0, a JTAG TAP is used. type: bit default: "0" + local: "false" expose: "true" name_top: LcCtrlUseDmiInterface } @@ -2006,6 +2015,7 @@ desc: Chip generation number. type: logic [15:0] default: 16'h 4001 + local: "false" expose: "true" name_top: LcCtrlSiliconCreatorId } @@ -2014,6 +2024,7 @@ desc: Chip revision number. type: logic [15:0] default: 16'h 0002 + local: "false" expose: "true" name_top: LcCtrlProductId } @@ -2022,6 +2033,7 @@ desc: Chip revision number. type: logic [7:0] default: 8'h 01 + local: "false" expose: "true" name_top: LcCtrlRevisionId } @@ -2030,6 +2042,7 @@ desc: JTAG ID code. type: logic [31:0] default: jtag_id_pkg::LC_CTRL_JTAG_IDCODE + local: "false" expose: "true" name_top: LcCtrlIdcodeValue } @@ -2821,6 +2834,7 @@ desc: Stub out the core of entropy_src logic type: bit default: "0" + local: "false" expose: "true" name_top: UsbdevStub } @@ -2829,6 +2843,7 @@ desc: Maximum number of microseconds for the differential receiver to become operational type: int default: "100" + local: "false" expose: "true" name_top: UsbdevRcvrWakeTimeUs } @@ -3484,6 +3499,7 @@ ''' type: bit default: 1'b1 + local: "false" expose: "true" name_top: SecRstmgrAonCheck } @@ -3492,6 +3508,7 @@ desc: The maximum synchronization delay for parent / child reset checks. type: int default: "2" + local: "false" expose: "true" name_top: SecRstmgrAonMaxSyncDelay } @@ -4240,6 +4257,7 @@ ''' type: bit default: top_pkg::SecVolatileRawUnlockEn + local: "false" expose: "true" name_top: SecPinmuxAonVolatileRawUnlockEn } @@ -4248,6 +4266,7 @@ desc: Target specific pinmux configuration. type: pinmux_pkg::target_cfg_t default: pinmux_pkg::DefaultTargetCfg + local: "false" expose: "true" name_top: PinmuxAonTargetCfg } @@ -5119,6 +5138,7 @@ desc: Support execution from SRAM type: bit default: "0" + local: "false" expose: "true" name_top: SramCtrlRetAonInstrExec } @@ -5127,6 +5147,7 @@ desc: Number of PRINCE half rounds for the SRAM scrambling feature type: int default: "3" + local: "false" expose: "true" name_top: SramCtrlRetAonNumPrinceRoundsHalf } @@ -5350,6 +5371,7 @@ desc: Compile-time option to enable flash scrambling type: bit default: "1" + local: "false" expose: "true" name_top: SecFlashCtrlScrambleEn } @@ -5358,6 +5380,7 @@ desc: Depth of program fifo type: int default: "4" + local: "false" expose: "true" name_top: FlashCtrlProgFifoDepth } @@ -5366,6 +5389,7 @@ desc: Depth of read fifo type: int default: "16" + local: "false" expose: "true" name_top: FlashCtrlRdFifoDepth } @@ -5730,6 +5754,7 @@ desc: RISC-V debug module JTAG ID code. type: logic [31:0] default: jtag_id_pkg::RV_DM_JTAG_IDCODE + local: "false" expose: "true" name_top: RvDmIdcodeValue } @@ -5738,6 +5763,7 @@ desc: When 1, a TLUL-based DMI interface is used. When 0, a JTAG TAP is used. type: bit default: "0" + local: "false" expose: "true" name_top: RvDmUseDmiInterface } @@ -5753,6 +5779,7 @@ ''' type: bit default: 1'b0 + local: "false" expose: "true" name_top: SecRvDmVolatileRawUnlockEn } @@ -6158,6 +6185,7 @@ desc: Disable (0) or enable (1) support for 192-bit key lengths (AES-192). type: bit default: 1'b1 + local: "false" expose: "false" name_top: AesAES192Enable } @@ -6170,6 +6198,7 @@ ''' type: bit default: "1" + local: "false" expose: "true" name_top: SecAesMasking } @@ -6178,6 +6207,7 @@ desc: Selection of the S-Box implementation. See aes_pkg.sv. type: aes_pkg::sbox_impl_e default: aes_pkg::SBoxImplDom + local: "false" expose: "true" name_top: SecAesSBoxImpl } @@ -6190,6 +6220,7 @@ ''' type: int unsigned default: "0" + local: "false" expose: "true" name_top: SecAesStartTriggerDelay } @@ -6203,6 +6234,7 @@ ''' type: bit default: 1'b0 + local: "false" expose: "true" name_top: SecAesAllowForcingMasks } @@ -6216,6 +6248,7 @@ ''' type: bit default: 1'b0 + local: "false" expose: "true" name_top: SecAesSkipPRNGReseeding } @@ -6449,6 +6482,7 @@ desc: Disable(0) or enable(1) first-order masking of Keccak round. type: bit default: "1" + local: "false" expose: "true" name_top: KmacEnMasking } @@ -6463,6 +6497,7 @@ ''' type: bit default: "0" + local: "false" expose: "true" name_top: KmacSwKeyMasked } @@ -6477,6 +6512,7 @@ ''' type: int default: "0" + local: "false" expose: "true" name_top: SecKmacCmdDelay } @@ -6490,6 +6526,7 @@ ''' type: bit default: "0" + local: "false" expose: "true" name_top: SecKmacIdleAcceptSwMsg } @@ -6694,6 +6731,7 @@ desc: Stub out the core of Otbn logic type: bit default: "0" + local: "false" expose: "true" name_top: OtbnStub } @@ -6702,6 +6740,7 @@ desc: Selection of the register file implementation. See otbn_pkg.sv. type: otbn_pkg::regfile_e default: otbn_pkg::RegFileFF + local: "false" expose: "true" name_top: OtbnRegFile } @@ -6725,6 +6764,7 @@ ''' type: bit default: "0" + local: "false" expose: "true" name_top: SecOtbnMuteUrnd } @@ -6738,6 +6778,7 @@ ''' type: bit default: "0" + local: "false" expose: "true" name_top: SecOtbnSkipUrndReseedAtStart } @@ -6941,6 +6982,7 @@ ''' type: bit default: "0" + local: "false" expose: "true" name_top: KeymgrUseOtpSeedsInsteadOfFlash } @@ -6949,6 +6991,7 @@ desc: Flag indicating with kmac masking is enabled type: bit default: "1" + local: "false" expose: "true" name_top: KeymgrKmacEnMasking } @@ -7321,6 +7364,7 @@ desc: Selection of the S-Box implementation. See aes_pkg.sv. type: aes_pkg::sbox_impl_e default: aes_pkg::SBoxImplCanright + local: "false" expose: "true" name_top: CsrngSBoxImpl } @@ -7452,6 +7496,7 @@ desc: Number of 384-bit entries in the esfinal FIFO type: int default: "3" + local: "false" expose: "true" name_top: EntropySrcEsFifoDepth } @@ -7460,6 +7505,7 @@ desc: Number of 32-bit entries in the distr FIFO type: int unsigned default: "2" + local: "false" expose: "true" name_top: EntropySrcDistrFifoDepth } @@ -7468,6 +7514,7 @@ desc: Stub out the core of entropy_src logic type: bit default: "0" + local: "false" expose: "true" name_top: EntropySrcStub } @@ -7873,6 +7920,7 @@ desc: Support execution from SRAM type: bit default: "1" + local: "false" expose: "true" name_top: SramCtrlMainInstrExec } @@ -7881,6 +7929,7 @@ desc: Number of PRINCE half rounds for the SRAM scrambling feature type: int default: "2" + local: "false" expose: "true" name_top: SramCtrlMainNumPrinceRoundsHalf } @@ -8034,6 +8083,7 @@ desc: Contents of ROM type: "" default: '''""''' + local: "false" expose: "true" name_top: RomCtrlBootRomInitFile } @@ -8068,6 +8118,7 @@ ''' type: bit default: 1'b0 + local: "false" expose: "true" name_top: SecRomCtrlDisableScrambling } @@ -8287,6 +8338,7 @@ desc: Enable PMP type: bit default: "1" + local: "false" expose: "true" name_top: RvCoreIbexPMPEnable } @@ -8295,6 +8347,7 @@ desc: PMP Granularity type: int unsigned default: "0" + local: "false" expose: "true" name_top: RvCoreIbexPMPGranularity } @@ -8303,6 +8356,7 @@ desc: PMP number of regions type: int unsigned default: "16" + local: "false" expose: "true" name_top: RvCoreIbexPMPNumRegions } @@ -8311,6 +8365,7 @@ desc: "Number of the MHPM counter " type: int unsigned default: "2" + local: "false" expose: "true" name_top: RvCoreIbexMHPMCounterNum } @@ -8319,6 +8374,7 @@ desc: "Width of the MHPM Counter " type: int unsigned default: "32" + local: "false" expose: "true" name_top: RvCoreIbexMHPMCounterWidth } @@ -8327,6 +8383,7 @@ desc: RV32E type: bit default: "0" + local: "false" expose: "true" name_top: RvCoreIbexRV32E } @@ -8335,6 +8392,7 @@ desc: RV32M type: ibex_pkg::rv32m_e default: ibex_pkg::RV32MSingleCycle + local: "false" expose: "true" name_top: RvCoreIbexRV32M } @@ -8343,6 +8401,7 @@ desc: RV32B type: ibex_pkg::rv32b_e default: ibex_pkg::RV32BOTEarlGrey + local: "false" expose: "true" name_top: RvCoreIbexRV32B } @@ -8351,6 +8410,7 @@ desc: Reg file type: ibex_pkg::regfile_e default: ibex_pkg::RegFileFF + local: "false" expose: "true" name_top: RvCoreIbexRegFile } @@ -8359,6 +8419,7 @@ desc: Branch target ALU type: bit default: "1" + local: "false" expose: "true" name_top: RvCoreIbexBranchTargetALU } @@ -8367,6 +8428,7 @@ desc: Write back stage type: bit default: "1" + local: "false" expose: "true" name_top: RvCoreIbexWritebackStage } @@ -8375,6 +8437,7 @@ desc: Instruction cache type: bit default: "1" + local: "false" expose: "true" name_top: RvCoreIbexICache } @@ -8383,6 +8446,7 @@ desc: Instruction cache ECC type: bit default: "1" + local: "false" expose: "true" name_top: RvCoreIbexICacheECC } @@ -8391,6 +8455,7 @@ desc: Scramble instruction cach type: bit default: "1" + local: "false" expose: "true" name_top: RvCoreIbexICacheScramble } @@ -8399,6 +8464,7 @@ desc: Branch predictor type: bit default: "0" + local: "false" expose: "true" name_top: RvCoreIbexBranchPredictor } @@ -8407,6 +8473,7 @@ desc: Enable degug trigger type: bit default: "1" + local: "false" expose: "true" name_top: RvCoreIbexDbgTriggerEn } @@ -8415,6 +8482,7 @@ desc: Number of debug hardware break type: int default: "4" + local: "false" expose: "true" name_top: RvCoreIbexDbgHwBreakNum } @@ -8423,6 +8491,7 @@ desc: "Width of the MHPM Counter " type: bit default: "1" + local: "false" expose: "true" name_top: RvCoreIbexSecureIbex } @@ -8431,6 +8500,7 @@ desc: Halt address type: int unsigned default: tl_main_pkg::ADDR_SPACE_RV_DM__MEM + dm::HaltAddress[31:0] + local: "false" expose: "true" name_top: RvCoreIbexDmHaltAddr } @@ -8439,6 +8509,7 @@ desc: Exception address type: int unsigned default: tl_main_pkg::ADDR_SPACE_RV_DM__MEM + dm::ExceptionAddress[31:0] + local: "false" expose: "true" name_top: RvCoreIbexDmExceptionAddr } @@ -8447,6 +8518,7 @@ desc: Pipe line type: bit default: "0" + local: "false" expose: "true" name_top: RvCoreIbexPipeLine } diff --git a/hw/top_earlgrey/rtl/autogen/top_earlgrey.sv b/hw/top_earlgrey/rtl/autogen/top_earlgrey.sv index 8405c618911e7b..dbd5bf433b3042 100644 --- a/hw/top_earlgrey/rtl/autogen/top_earlgrey.sv +++ b/hw/top_earlgrey/rtl/autogen/top_earlgrey.sv @@ -224,6 +224,50 @@ module top_earlgrey #( // Compile-time random constants import top_earlgrey_rnd_cnst_pkg::*; + // Local Parameters + // local parameters for uart0 + // local parameters for uart1 + // local parameters for uart2 + // local parameters for uart3 + // local parameters for gpio + // local parameters for spi_device + // local parameters for i2c0 + // local parameters for i2c1 + // local parameters for i2c2 + // local parameters for pattgen + // local parameters for rv_timer + // local parameters for otp_ctrl + // local parameters for lc_ctrl + // local parameters for alert_handler + // local parameters for spi_host0 + // local parameters for spi_host1 + // local parameters for usbdev + // local parameters for pwrmgr_aon + // local parameters for rstmgr_aon + // local parameters for clkmgr_aon + // local parameters for sysrst_ctrl_aon + // local parameters for adc_ctrl_aon + // local parameters for pwm_aon + // local parameters for pinmux_aon + // local parameters for aon_timer_aon + // local parameters for sensor_ctrl_aon + // local parameters for sram_ctrl_ret_aon + // local parameters for flash_ctrl + // local parameters for rv_dm + // local parameters for rv_plic + // local parameters for aes + // local parameters for hmac + // local parameters for kmac + // local parameters for otbn + // local parameters for keymgr + // local parameters for csrng + // local parameters for entropy_src + // local parameters for edn0 + // local parameters for edn1 + // local parameters for sram_ctrl_main + // local parameters for rom_ctrl + // local parameters for rv_core_ibex + // Signals logic [56:0] mio_p2d; logic [74:0] mio_d2p; @@ -781,6 +825,7 @@ module top_earlgrey #( edn_pkg::edn_rsp_t unused_edn1_edn_rsp7; // assign partial inter-module tie-off + assign unused_otp_ctrl_sram_otp_key_rsp3 = otp_ctrl_sram_otp_key_rsp[3]; assign unused_edn1_edn_rsp1 = edn1_edn_rsp[1]; assign unused_edn1_edn_rsp2 = edn1_edn_rsp[2]; diff --git a/hw/top_earlgrey/templates/toplevel.sv.tpl b/hw/top_earlgrey/templates/toplevel.sv.tpl index d78088657f66c7..6caaa01ab84b5b 100644 --- a/hw/top_earlgrey/templates/toplevel.sv.tpl +++ b/hw/top_earlgrey/templates/toplevel.sv.tpl @@ -5,6 +5,7 @@ ${gencmd} <% import re import topgen.lib as lib +from reggen.params import Parameter from topgen.clocks import Clocks from topgen.resets import Resets @@ -22,7 +23,15 @@ 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"]]) +num_im = 0 +for x in top["inter_signal"]["external"]: + if "width" in x: + if isinstance(x["width"], Parameter): + num_im += x["width"].default + else: + num_im += x["width"] + else: + num_im += 1 max_sigwidth = max([x["width"] if "width" in x else 1 for x in top["pinmux"]["ios"]]) max_sigwidth = len("{}".format(max_sigwidth)) @@ -52,7 +61,7 @@ module top_${top["name"]} #( <% continue %> % endif // parameters for ${m['name']} - % for p_exp in [p for p in m["param_list"] if p.get("expose") == "true" ]: + % for p_exp in [p for p in m["param_list"] if p.get("local") == "false" and p.get("expose") == "true" ]: <% p_type = p_exp.get('type') p_type_word = p_type + ' ' if p_type else '' @@ -63,7 +72,7 @@ module top_${top["name"]} #( params_follow = not loop.last or loop.parent.index < last_modidx_with_params comma_char = ',' if params_follow else '' %>\ - % if 12 + len(p_lhs) + 3 + len(p_rhs) + 1 < 100: + % if 12 + len(p_lhs) + 3 + len(str(p_rhs)) + 1 < 100: parameter ${p_lhs} = ${p_rhs}${comma_char} % else: parameter ${p_lhs} = @@ -95,7 +104,11 @@ module top_${top["name"]} #( // Inter-module Signal External type % for sig in top["inter_signal"]["external"]: + % if isinstance(sig["width"], Parameter): + ${lib.get_direction(sig)} ${lib.im_defname(sig)} [${sig["width"].name_top}-1:0] ${sig["signame"]}, + % else: ${lib.get_direction(sig)} ${lib.im_defname(sig)} ${lib.bitarray(sig["width"],1)} ${sig["signame"]}, + % endif % endfor % endif @@ -121,6 +134,29 @@ module top_${top["name"]} #( // Compile-time random constants import top_${top["name"]}_rnd_cnst_pkg::*; + // Local Parameters +% for m in top["module"]: + % if not lib.is_inst(m): +<% continue %> + % endif + // local parameters for ${m['name']} + % for p_exp in [p for p in m["param_list"] if p.get("local") == "true" and 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 13 + len(p_lhs) + 3 + len(str(p_rhs)) + 1 < 100: + localparam ${p_lhs} = ${p_rhs}; + % else: + localparam ${p_lhs} = + ${p_rhs}; + % endif + % endfor +% endfor + // Signals logic [${num_mio_inputs - 1}:0] mio_p2d; logic [${num_mio_outputs - 1}:0] mio_d2p; @@ -187,7 +223,11 @@ module top_${top["name"]} #( // define inter-module signals % endif % for sig in top["inter_signal"]["definitions"]: + % if isinstance(sig["width"], Parameter): + ${lib.im_defname(sig)} [${sig["width"].name_top}-1:0] ${sig["signame"]}; + % else: ${lib.im_defname(sig)} ${lib.bitarray(sig["width"],1)} ${sig["signame"]}; + % endif % endfor ## Mixed connection to port @@ -213,19 +253,29 @@ module top_${top["name"]} #( ## 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']): +<% + width = sig['width'].default if isinstance(sig['width'], Parameter) else sig['width'] +%>\ + % for idx in range(sig['end_idx'], 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']): +<% + width = sig['width'].default if isinstance(sig['width'], Parameter) else sig['width'] +%>\ + % for idx in range(sig['end_idx'], 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']): +<% + width = sig['width'].default if isinstance(sig['width'], Parameter) else sig['width'] +%>\ + % for idx in range(sig['end_idx'], width): assign ${sig["signame"]}[${idx}] = ${sig["default"]}; % endfor % endfor diff --git a/util/reggen/inter_signal.py b/util/reggen/inter_signal.py index e1cbd19339827b..ae73069f56e045 100644 --- a/util/reggen/inter_signal.py +++ b/util/reggen/inter_signal.py @@ -2,10 +2,11 @@ # Licensed under the Apache License, Version 2.0, see LICENSE for details. # SPDX-License-Identifier: Apache-2.0 -from typing import Dict, Optional +from typing import Dict, Optional, Union from reggen.lib import (check_keys, check_name, check_str, check_optional_str, check_int) +from reggen.params import Parameter class InterSignal: @@ -16,9 +17,12 @@ def __init__(self, package: Optional[str], signal_type: str, act: str, - width: int, + width: Union[int, Parameter], default: Optional[str]): - assert 0 < width + if isinstance(width, Parameter): + assert 0 < width.default + else: + assert 0 < width self.name = name self.desc = desc self.struct = struct @@ -29,7 +33,7 @@ def __init__(self, self.default = default @staticmethod - def from_raw(what: str, raw: object) -> 'InterSignal': + def from_raw(params: dict, what: str, raw: object) -> 'InterSignal': rd = check_keys(raw, what, ['name', 'struct', 'type', 'act'], ['desc', 'package', 'width', 'default']) @@ -52,9 +56,21 @@ def from_raw(what: str, raw: object) -> 'InterSignal': signal_type = check_name(rd['type'], 'type field of ' + what) act = check_name(rd['act'], 'act field of ' + what) - width = check_int(rd.get('width', 1), 'width field of ' + what) - if width <= 0: - raise ValueError('width field of {} is not positive.'.format(what)) + + try: + width = check_int(rd.get('width', 1), 'width field of ' + what) + except ValueError: + # Value error raised since it is not an int, lets try to find out if it is a Parameter + width = params.get(rd.get('width')) + width.default = check_int(width.default, 'width field of ' + what) + if width.default <= 0: + raise ValueError('width field of {} is not positive.'.format(what)) + # Parameter must be exposed to create a top-level (local) param + if not width.expose: + raise ValueError('width field of {} is not exposed.'.format(what)) + else: + if width <= 0: + raise ValueError('width field of {} is not positive.'.format(what)) default = check_optional_str(rd.get('default'), 'default field of ' + what) diff --git a/util/reggen/ip_block.py b/util/reggen/ip_block.py index f468b84770289e..fce877b0b78302 100644 --- a/util/reggen/ip_block.py +++ b/util/reggen/ip_block.py @@ -339,6 +339,7 @@ def from_raw(param_defaults: List[Tuple[str, str]], 'inter_signal_list field') inter_signals = [ InterSignal.from_raw( + params, 'entry {} of the inter_signal_list field'.format(idx + 1), entry) for idx, entry in enumerate(r_inter_signals) ] diff --git a/util/reggen/params.py b/util/reggen/params.py index 673edf8b0810a6..f141083d02f5d6 100644 --- a/util/reggen/params.py +++ b/util/reggen/params.py @@ -78,14 +78,17 @@ def __init__(self, desc: Optional[str], param_type: str, default: str, + local: bool, expose: bool): super().__init__(name, desc, param_type) self.default = default + self.local = local self.expose = expose def as_dict(self) -> Dict[str, object]: rd = super().as_dict() rd['default'] = self.default + rd['local'] = 'true' if self.local else 'false' rd['expose'] = 'true' if self.expose else 'false' return rd @@ -256,14 +259,12 @@ def _parse_parameter(where: str, raw: object) -> BaseParam: 'default field of {}, (an integer parameter)' .format(name)) - if local: - if expose: - raise ValueError('At {}, the localparam {} cannot be exposed to ' - 'the top-level.' - .format(where, name)) - return LocalParam(name, desc, param_type, value=default) + if local and expose: + return Parameter(name, desc, param_type, default, local, expose) + elif local: + return LocalParam(name, desc, param_type, default) else: - return Parameter(name, desc, param_type, default, expose) + return Parameter(name, desc, param_type, default, local, expose) # Note: With a modern enough Python, we'd like this to derive from @@ -378,6 +379,11 @@ def from_raw(where: str, raw: object) -> 'ReggenParams': def get_localparams(self) -> List[LocalParam]: ret = [] for param in self.by_name.values(): + # Emit local params at reg_pkg level for full local params and local params that + # are exposed to the top if isinstance(param, LocalParam): ret.append(param) + elif isinstance(param, Parameter) and param.local: + ret.append(param) + return ret diff --git a/util/topgen.py b/util/topgen.py index b1688d160d0c88..3b258169e5576c 100755 --- a/util/topgen.py +++ b/util/topgen.py @@ -151,6 +151,7 @@ def generate_xbars(top: Dict[str, object], out_path: Path) -> None: "inter_signal_list field") obj["inter_signal_list"] = [ InterSignal.from_raw( + {}, "entry {} of the inter_signal_list field".format(idx + 1), entry) for idx, entry in enumerate(r_inter_signal_list) ] @@ -1134,7 +1135,7 @@ def main(): """.format(top_name=top_name, seed=completecfg["rnd_cnst_seed"]) genhjson_path.write_text(genhdr + gencmd + - hjson.dumps(completecfg, for_json=True) + '\n') + hjson.dumps(completecfg, for_json=True, default=vars) + '\n') # Generate Rust toplevel definitions if not args.no_rust: diff --git a/util/topgen/intermodule.py b/util/topgen/intermodule.py index 7b2938d751f101..2977a43c853680 100644 --- a/util/topgen/intermodule.py +++ b/util/topgen/intermodule.py @@ -10,6 +10,7 @@ from reggen.ip_block import IpBlock from reggen.inter_signal import InterSignal +from reggen.params import Parameter from reggen.validate import check_int from topgen import lib @@ -644,13 +645,18 @@ def check_intermodule_field(sig: OrderedDict, width = 1 if "width" not in sig: sig["width"] = 1 + elif isinstance(sig["width"], Parameter): + width, err = check_int(sig["width"].default, sig["name"]) + if err: + log.error(f"{prefix} Inter-module {sig["inst_name"]}.{sig["name"]} 'width' " + "should be int type.") + error += 1 elif not isinstance(sig["width"], int): width, err = check_int(sig["width"], sig["name"]) if err: - log.error("{prefix} Inter-module {inst}.{sig} 'width' " - "should be int type.".format(prefix=prefix, - inst=sig["inst_name"], - sig=sig["name"])) + log.error(f"{prefix} Inter-module {sig["inst_name"]}.{sig["name"]} 'width' " + "should be int type.") + error += 1 else: # convert to int value @@ -821,20 +827,26 @@ def check_intermodule(topcfg: Dict, prefix: str) -> int: # Determine if broadcast or one-to-N log.debug("Handling inter-sig {} {}".format(req_struct['name'], total_width)) + + if isinstance(req_struct["width"], Parameter): + width = int(req_struct["width"].default) + else: + width = req_struct["width"] + req_struct["end_idx"] = -1 - if req_struct["width"] > 1 or len(rsps) != 1: + if width > 1 or len(rsps) != 1: # If req width is same to the every width of rsps ==> broadcast - if len(rsps) * [req_struct["width"]] == widths: + if len(rsps) * [width] == widths: log.debug("broadcast type") req_struct["top_type"] = "broadcast" # If req width is same as total width of rsps ==> one-to-N - elif req_struct["width"] == total_width: + elif width == total_width: log.debug("one-to-N type") req_struct["top_type"] = "one-to-N" # one-to-N connection is not fully populated - elif req_struct["width"] > total_width: + elif width > total_width: log.debug("partial one-to-N type") req_struct["top_type"] = "partial-one-to-N" req_struct["end_idx"] = len(rsps) @@ -950,8 +962,13 @@ def im_netname(sig: OrderedDict, # custom default has been specified if obj["default"]: return obj["default"] - return "{package}::{struct}_DEFAULT".format( - package=obj["package"], struct=obj["struct"].upper()) + if isinstance(sig["width"], Parameter): + return "{{{param}{{{package}::{struct}_DEFAULT}}}}".format( + param=sig["width"].name_top, package=obj["package"], + struct=obj["struct"].upper()) + else: + return "{package}::{struct}_DEFAULT".format( + package=obj["package"], struct=obj["struct"].upper()) return "" diff --git a/util/topgen/merge.py b/util/topgen/merge.py index 61ad7d6db633c3..1b06ae79745cd2 100644 --- a/util/topgen/merge.py +++ b/util/topgen/merge.py @@ -166,6 +166,14 @@ def elaborate_instance(instance, block: IpBlock): # to convert and copy them here. instance["inter_signal_list"] = [s.as_dict() for s in block.inter_signals] + # If we have width-parametrized intersignal, we need to update the intersignal param name + # the the instance mangled param name + for s in instance["inter_signal_list"]: + if isinstance(s['width'], Parameter): + for p in instance["param_list"]: + if p['name'] == s['width'].name: + s['width'].name_top = p['name_top'] + # An instance must either have a 'base_addr' address or a 'base_addrs' # address, but can't have both. base_addrs = instance.get('base_addrs')