[syn] This adds a simple testsynthesis flow for DC This adds a similar makefile based test synthesis flow for DC analogous to the AscentLint flow. It allows to run a simple wire-load-model-based synthesis of individual IPs or the top-level. Two example targets are provided within this PR, and they can be called by stepping into `hw/syn` and running: ``` make ip-aes_syn make systems-top_earlgrey_syn ``` Area, timing, power and link reports will be written to `hw/syn/reports` once synthesis has completed. Note that this is only a starting point and will soon be extended. Also, this requires a technology setup scripts and the corresponding technology wrapper primitives to be present under `hw/foundry/syn/dc` and `hw/foundry/ip/prim_<tech id>/` The integration into the dvsim dashboard (analogous to AscentLint) is in the making and will follow in a subsequent PR (together with more documentation). Signed-off-by: Michael Schaffner <msf@opentitan.org>
diff --git a/hw/ip/aes/aes.core b/hw/ip/aes/aes.core index 23083d7..cf9c36c 100644 --- a/hw/ip/aes/aes.core +++ b/hw/ip/aes/aes.core
@@ -73,3 +73,13 @@ verilator_options: - "-Wall" + syn: + <<: *default_target + # set default to DC once + # this option is available + # olofk/edalize#89 + default_tool: icarus + parameters: + - SYNTHESIS=true + +
diff --git a/hw/syn/Makefile b/hw/syn/Makefile new file mode 100644 index 0000000..4e2932b --- /dev/null +++ b/hw/syn/Makefile
@@ -0,0 +1,67 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +# +# Makefile with synthesis targets for OpenTitan + +CORE_ROOT ?= ../../ +REPORT_DIR ?= reports +# this directory contains the library setup file (setup.tcl) +LIB_SETUP_SCRIPT ?= `pwd`/../foundry/syn/dc/setup.tcl +# sources for DC +TOOL_SRCS = ./tools/dc/start-dc.sh \ + ./tools/dc/run-syn.tcl \ + ./tools/dc/constraints.sdc + +IPS ?= ip-aes \ + systems-top_earlgrey +# ip-alert_handler \ +# ip-flash_ctrl \ +# ip-gpio \ +# ip-hmac \ +# ip-i2c \ +# ip-nmi_gen \ +# ip-padctrl \ +# ip-padring \ +# ip-pinmux \ +# ip-rv_core_ibex \ +# ip-rv_dm \ +# ip-rv_plic_example \ +# ip-rv_timer \ +# ip-spi_device \ +# ip-uart \ +# ip-usbdev \ +# ip-usb_fs_nb_pe \ +# ip-usbuart \ +# tlul-socket_1n \ +# tlul-socket_m1 \ +# tlul-adapter_reg \ +# tlul-adapter_sram \ +# tlul-sram2tlul \ + + +ips_syn = $(addsuffix _syn, $(IPS)) + +###################### +# synthesis targets # +###################### + +all: clean + @echo Discovered synth targets: + @echo -e "\n $(patsubst %,%\\n,$(strip $(ips_syn)))" + $(MAKE) $(ips_lint) + +$(ips_syn): + mkdir -p ${REPORT_DIR} + fusesoc --cores-root ${CORE_ROOT} run --target=syn --tool=icarus --setup lowrisc:$(subst -,:,$(patsubst %_syn,%,$@)) + cp ${TOOL_SRCS} build/lowrisc_*$(subst -,_,$(patsubst %_syn,%,$@))*/syn-icarus/ + export TOP_ENTITY="$(patsubst ip-%,%,$(patsubst tlul-%,%,$(patsubst systems-%,%,$(patsubst %_syn,%,$@))))" && \ + export LIB_SETUP_SCRIPT=${LIB_SETUP_SCRIPT} && \ + cd build/lowrisc_*$(subst -,_,$(patsubst %_syn,%,$@))*/syn-icarus/ && ./start-dc.sh -f run-syn.tcl + cp build/lowrisc_*$(subst -,_,$(patsubst %_syn,%,$@))*/syn-icarus/REPORTS/*.rpt ${REPORT_DIR}/ + +clean: + rm -rf build + rm -rf ${REPORT_DIR}/* + +.PHONY: all $(ips_syn) clean
diff --git a/hw/syn/tools/dc/constraints.sdc b/hw/syn/tools/dc/constraints.sdc new file mode 100644 index 0000000..a3bc2d3 --- /dev/null +++ b/hw/syn/tools/dc/constraints.sdc
@@ -0,0 +1,161 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +# +# Generic constraints file for simple testsynthesis flow +# This held very simple for now and needs to be refined + +# note that we do not fix hold timing in this flow +set SETUP_CLOCK_UNCERTAINTY 0.5 + +# TODO: consider splitting this into per-IP .sdc files +if {$TOP_ENTITY == "top_earlgrey"} { + +puts "Applying constraints for top level" + +# note: this does not account for clock insertion delay and +# there are no pads instantiated in the netlist (yet) + +##################### +# main clock # +##################### +set MAIN_CLK_PIN clk_i +set MAIN_RST_PIN rst_ni +# 125 MHz +set MAIN_TCK 8.0 +set_ideal_network ${MAIN_CLK_PIN} +set_ideal_network ${MAIN_RST_PIN} + +create_clock ${MAIN_CLK_PIN} -period ${MAIN_TCK} +set_clock_uncertainty ${SETUP_CLOCK_UNCERTAINTY} ${MAIN_CLK_PIN} + +set IN_DEL 5.5 +set OUT_DEL 5.5 + +set_input_delay ${IN_DEL} [get_ports mio_in_i*] -clock ${MAIN_CLK_PIN} +set_input_delay ${IN_DEL} [get_ports scanmode_i] -clock ${MAIN_CLK_PIN} +set_input_delay ${IN_DEL} [get_ports dio_uart_rx_i] -clock ${MAIN_CLK_PIN} + +set_output_delay ${OUT_DEL} [get_ports mio_out_o*] -clock ${MAIN_CLK_PIN} +set_output_delay ${OUT_DEL} [get_ports mio_oe_o*] -clock ${MAIN_CLK_PIN} +set_output_delay ${OUT_DEL} [get_ports dio_uart_tx_o] -clock ${MAIN_CLK_PIN} +set_output_delay ${OUT_DEL} [get_ports dio_uart_tx_en_o] -clock ${MAIN_CLK_PIN} + +##################### +# USB clock # +##################### +set USB_CLK_PIN clk_usb_48mhz_i +# 50MHz +set USB_TCK 20.0 +set_ideal_network ${USB_CLK_PIN} + +create_clock ${USB_CLK_PIN} -period ${USB_TCK} +set_clock_uncertainty ${SETUP_CLOCK_UNCERTAINTY} ${USB_CLK_PIN} + +set IN_DEL 17.0 +set OUT_DEL 17.0 + +set_input_delay ${IN_DEL} [get_ports dio_usbdev_sense_i] -clock ${USB_CLK_PIN} +set_input_delay ${IN_DEL} [get_ports dio_usbdev_dp_i] -clock ${USB_CLK_PIN} +set_input_delay ${IN_DEL} [get_ports dio_usbdev_dn_i] -clock ${USB_CLK_PIN} + +set_output_delay ${OUT_DEL} [get_ports dio_usbdev_pullup_o] -clock ${USB_CLK_PIN} +set_output_delay ${OUT_DEL} [get_ports dio_usbdev_pullup_en_o] -clock ${USB_CLK_PIN} +set_output_delay ${OUT_DEL} [get_ports dio_usbdev_dp_o] -clock ${USB_CLK_PIN} +set_output_delay ${OUT_DEL} [get_ports dio_usbdev_dp_en_o] -clock ${USB_CLK_PIN} +set_output_delay ${OUT_DEL} [get_ports dio_usbdev_dn_o] -clock ${USB_CLK_PIN} +set_output_delay ${OUT_DEL} [get_ports dio_usbdev_dn_en_o] -clock ${USB_CLK_PIN} + +##################### +# JTAG clock # +##################### +set JTAG_CLK_PIN jtag_tck_i +set JTAG_RST_PIN jtag_trst_ni +# 40MHz +set JTAG_TCK 25.0 +set_ideal_network ${JTAG_CLK_PIN} +set_ideal_network ${JTAG_RST_PIN} + +create_clock ${JTAG_CLK_PIN} -period ${JTAG_TCK} +set_clock_uncertainty ${SETUP_CLOCK_UNCERTAINTY} ${JTAG_CLK_PIN} + +set IN_DEL 10.0 +set OUT_DEL 10.0 + +set_input_delay ${IN_DEL} [get_ports jtag_tms_i] -clock ${JTAG_CLK_PIN} +set_input_delay ${IN_DEL} [get_ports jtag_td_i] -clock ${JTAG_CLK_PIN} + +set_output_delay ${OUT_DEL} [get_ports jtag_td_o] -clock ${JTAG_CLK_PIN} + +##################### +# SPI clock # +##################### +set SPI_CLK_PIN dio_spi_device_sck_i +# 62.5MHz +set SPI_TCK 16.0 +set_ideal_network ${SPI_CLK_PIN} + +create_clock ${SPI_CLK_PIN} -period ${SPI_TCK} +set_clock_uncertainty ${SETUP_CLOCK_UNCERTAINTY} ${SPI_CLK_PIN} + +set IN_DEL 6.0 +set OUT_DEL 6.0 + +set_input_delay ${IN_DEL} [get_ports dio_spi_device_csb_i] -clock ${SPI_CLK_PIN} +set_input_delay ${IN_DEL} [get_ports dio_spi_device_mosi_i] -clock ${SPI_CLK_PIN} + +set_output_delay ${OUT_DEL} [get_ports dio_spi_device_miso_o] -clock ${SPI_CLK_PIN} +set_output_delay ${OUT_DEL} [get_ports dio_spi_device_miso_en_o] -clock ${SPI_CLK_PIN} + +##################### +# CDC # +##################### + +# this may need some refinement (and max delay / skew needs to be constrained) +set_clock_groups -name group1 -async -group ${MAIN_CLK_PIN} \ + -group ${JTAG_CLK_PIN} \ + -group ${USB_CLK_PIN} \ + -group ${SPI_CLK_PIN} + +# loopback path can be considered to be a false path +set_false_path -from dio_uart_rx_i -to dio_uart_tx_o + +} else { + +##################### +# main clock # +##################### +set MAIN_CLK_PIN clk_i +set MAIN_RST_PIN rst_ni +# set main clock to 125 MHz +set MAIN_TCK 8.0 +set_ideal_network ${MAIN_CLK_PIN} +set_ideal_network ${MAIN_RST_PIN} +set_clock_uncertainty ${SETUP_CLOCK_UNCERTAINTY} ${MAIN_CLK_PIN} + +# other timing constraint in ns +set IN_DEL 1.0 +set OUT_DEL 1.0 +set DELAY ${MAIN_TCK} + +create_clock ${MAIN_CLK_PIN} -period ${MAIN_TCK} + +# in to out +set_max_delay ${DELAY} -from [all_inputs] -to [all_outputs] +# in to reg / reg to out +set_input_delay ${IN_DEL} [remove_from_collection [all_inputs] {${MAIN_CLK_PIN}}] -clock ${MAIN_CLK_PIN} +set_output_delay ${OUT_DEL} [all_outputs] -clock ${MAIN_CLK_PIN} + +} + +##################### +# Common # +##################### + +# attach load and drivers to IOs to get a more realistic estimate +set_driving_cell -no_design_rule -lib_cell ${driving_cell} -pin X [all_inputs] +set_load [load_of ${load_lib}/${load_cell}/A] [all_outputs] + +# set a nonzero critical range to be able to spot the violating paths better +# in the report +set_critical_range 0.5 ${TOP_ENTITY}
diff --git a/hw/syn/tools/dc/run-syn.tcl b/hw/syn/tools/dc/run-syn.tcl new file mode 100644 index 0000000..409bbfc --- /dev/null +++ b/hw/syn/tools/dc/run-syn.tcl
@@ -0,0 +1,146 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +# +# Simple tcl script for DC to do some wire-load-model-based test syntheses. + +##################### +## PREPARE FLOW ## +##################### + +# tool setup +source [getenv "LIB_SETUP_SCRIPT"] + +# paths +set WORKLIB "WORK" +set REPDIR "REPORTS" +set DDCDIR "DDC" +set VLOGDIR "NETLISTS" + +exec mkdir -p ${REPDIR} ${DDCDIR} ${VLOGDIR} ${WORKLIB} + +# define work lib path +define_design_lib WORK -path $WORKLIB + +####################### +## DESIGN SOURCES ### +####################### + +# just compile the "core" toplevel at the moment +# might want to switch to top_earlgrey_asic later on (with pads) +set TOP_ENTITY [getenv "TOP_ENTITY"] + +# read source list generated by fusesoc +set fp [open [ls "*.scr"] r] +set file_data [read $fp] +close $fp +set data [split $file_data "\n"] + +# this TECH_LIB_SEL selects the appropriate technology by defining +# PRIM_DEFAULT_IMPL=prim_pkg::Impl<tech identifier> +# TECH_LIB_SEL is set inside the library setup script +set DEFINE "PRIM_DEFAULT_IMPL=${PRIM_DEFAULT_IMPL} " +# go through fusesoc file list and separate +defines from actual source files +set SRC {} +foreach item $data { + if {[string range $item 0 7] == "+define+"} { + set DEFINE "${DEFINE}[string range $item 8 end] " + } elseif {[string range $item 0 7] == "+incdir+"} { + lappend search_path "[string range $item 8 end]" + } else { + lappend SRC $item + } +} + +# additional parameters +set PARAMS "" + +########################### +## ELABORATE DESIGN ## +########################### + +# delete previous designs. +remove_design -designs +sh rm -rf $WORKLIB/* + +analyze -define ${DEFINE} -format sv ${SRC} +elaborate ${TOP_ENTITY} -parameters ${PARAMS} +link > "${REPDIR}/${TOP_ENTITY}_link.rpt" + +write_file -format ddc -hierarchy -output "${DDCDIR}/${TOP_ENTITY}_elab.ddc" +write_file -format verilog -hierarchy -output "${DDCDIR}/${TOP_ENTITY}_elab.v" + +############################# +## CLOCK GATING SETUP ## +############################# + +# be more specific if defaults do not suffice +# set_clock_gating_style -num_stages 1 \ +# -positive_edge_logic integrated \ +# -control_point before \ +# -control_signal scan_enable + +########################### +## APPLY CONSTRAINTS ## +########################### + +source constraints.sdc + +# If hold time should be fixed +# set_fix_hold ${CLK_PIN} + +###################### +## MAP DESIGN ## +###################### + +# TODO: we may have to disable a couple of optimizations in order +# to prevent the tool from optimizing away dummy logic or logic from blocks +# that are only half-finished + +# preserve hierarchy for reports +compile_ultra -gate_clock -scan -no_autoungroup + +################# +## REPORTS ## +################# + +report_timing -nosplit -nworst 100 > "${REPDIR}/${TOP_ENTITY}_timing.rpt" +report_timing -nosplit -nworst 1000 -input -net -trans -cap > "${REPDIR}/${TOP_ENTITY}_timing_long.rpt" +report_area -hier -nosplit > "${REPDIR}/${TOP_ENTITY}_area.rpt" +report_power -hier -nosplit > "${REPDIR}/${TOP_ENTITY}_power.rpt" +report_constraints -all_violators > "${REPDIR}/${TOP_ENTITY}_constraints.rpt" + +################# +## NETLIST ## +################# + +# change_names -rules verilog -hierarchy +# define_name_rules fixbackslashes -allowed "A-Za-z0-9_" -first_restricted "\\" -remove_chars +# change_names -rule fixbackslashes -h +write_file -format ddc -hierarchy -output "${DDCDIR}/${TOP_ENTITY}_mapped.ddc" +write_file -format verilog -hierarchy -output "${VLOGDIR}/${TOP_ENTITY}_mapped.v" + +# ############################## +# ## INCREMENTAL FLATTENING ## +# ############################## + +# compile_ultra -inc + +# ################# +# ## REPORTS ## +# ################# + +# report_timing -nosplit -nworst 100 > "${REPDIR}/${TOP_ENTITY}_flat_timing.rpt" +# report_timing -nosplit -nworst 1000 -input -net -trans -cap > "${REPDIR}/${TOP_ENTITY}_flat_timing_long.rpt" +# report_area -hier -nosplit > "${REPDIR}/${TOP_ENTITY}_flat_area.rpt" +# report_power -hier -nosplit > "${REPDIR}/${TOP_ENTITY}_flat_power.rpt" +# report_constraints -all_violators > "${REPDIR}/${TOP_ENTITY}_flat_constraints.rpt" + +# ################# +# ## NETLIST ## +# ################# + +# write_file -format ddc -hierarchy -output "${DDCDIR}/${TOP_ENTITY}_flat.ddc" +# write_file -format verilog -hierarchy -output "${VLOGDIR}/${TOP_ENTITY}_flat.v" + +exit
diff --git a/hw/syn/tools/dc/start-dc.sh b/hw/syn/tools/dc/start-dc.sh new file mode 100755 index 0000000..03520fa --- /dev/null +++ b/hw/syn/tools/dc/start-dc.sh
@@ -0,0 +1,4 @@ +#!/bin/bash + +# this is needed for the terminal to respond correctly within DC +TERM="dtterm" dc_shell-xg-t $@
diff --git a/hw/top_earlgrey/top_earlgrey.core b/hw/top_earlgrey/top_earlgrey.core index 6d36122..664c511 100644 --- a/hw/top_earlgrey/top_earlgrey.core +++ b/hw/top_earlgrey/top_earlgrey.core
@@ -96,3 +96,13 @@ mode: lint-only verilator_options: - "-Wall" + + syn: + <<: *default_target + # set default to DC once + # this option is available + # olofk/edalize#89 + default_tool: icarus + parameters: + - SYNTHESIS=true + toplevel: top_earlgrey