# -*- tcl -*-

# Clock constraints

# Input master clock for all PLLs
create_clock -name "clock_48" -period 20.834ns [get_ports {clock_48}]
create_clock -name "clock_16" -period 62.500ns [get_ports {clock_16}]
derive_pll_clocks

# RTC clock; asynchronous with all others
create_clock -name "rtc_32khz" -period 30517.578ns [get_ports {rtc_32khz}]
set_clock_groups -asynchronous -group {rtc_32khz}

# Automatically calculate clock uncertainty to jitter and other effects.
derive_clock_uncertainty

# Don't report signaltap clock problems...
set_false_path -to [get_registers sld_signaltap:*]

# -------- PLL clock mappings --------

set master_clk    [get_clocks {pll2|*|clk[0]}]
set sdram_clk     [get_clocks {*|pll3|*|clk[0]}]
set sdram_out_clk [get_clocks {*|pll3|*|clk[1]}]
set sys_clk       [get_clocks {*|pll3|*|clk[2]}]
set flash_clk     [get_clocks {*|pll3|*|clk[3]}]
set usb_clk       [get_clocks {*|pll3|*|clk[4]}]
set hdmi_clk      [get_clocks {*|pll4|*|clk[0]}]
set vid_clk       [get_clocks {*|pll4|*|clk[1]}]

set main_clocks   [get_clocks {pll*|*|clk[*] *|pll*|*|clk[*]}]

# Reset isn't actually a clock, but Quartus thinks it is
create_generated_clock -name rst_n \
    -source [get_nets {*|pll3|*|*clk[2]}] \
    [get_registers *|rst_n]
create_generated_clock -name hard_rst_n \
    -source [get_nets {*|pll3|*|*clk[2]}] \
    [get_registers *|hard_rst_n]

# Reset is asynchronous  with everything as far as we are concerned.
set_clock_groups -asynchronous \
    -group $main_clocks \
    -group [get_clocks {rst_n hard_rst_n}]

# Anything that feeds into a synchronizer is by definition
# asynchronous, but encode it as allowing multicycle of one
# clock, to limit the possible skew (but it is of course not possible
# to eliminate it...)
set synchro_inputs [get_registers *|synchronizer:*|qreg0*]
set_multicycle_path -from [all_clocks] -to $synchro_inputs \
    -start -setup 2
set_multicycle_path -from [all_clocks] -to $synchro_inputs \
    -start -hold 1


# -------- SDRAM I/O constraints --------

set sr_data_out [remove_from_collection [get_ports sr_*] sr_clk]
set sr_data_in  [get_ports {sr_dq[*]}]
set_max_skew -to $sr_data_out 0.100ns
set_input_delay  -clock $sdram_clk 0.500ns  $sr_data_in

#set_multicycle_path -from $sdram_clk -to $sdram_out_clk \
#    -start -setup 2
#set_multicycle_path -from $sdram_clk -to $sdram_out_clk \
#    -start -hold 0

# -------- SDRAM multicycle paths --------

# sdram_mem_ready is deferred by one sys_clk
set cpu_dram_rd [get_registers {*|dram_port:cpu_dram_port|rd[*]}]
set_multicycle_path -from $cpu_dram_rd -to $sys_clk -start -setup 2
set_multicycle_path -from $cpu_dram_rd -to $sys_clk -start -hold 1

# -------- SPI ROM multicycle paths --------

# CPU-writable registers
set romcopy_datalen [get_registers \
 {*|spirom:*|datalen[*] *|spirom:*|cmdlen[*] *|spirom:*|spi_dual *|spirom:*|spi_more *|spirom:*|is_*}]
set romcopy_romcmd [get_registers {*|spirom:*|romcmd[*]}]
set romcopy_ramstart [get_registers {*|spirom:*|ramstart[*]}]
set romcopy_go [get_registers {*|spirom:*|go_* *|spirom:*|irq}]
set romcopy_cpuregs [add_to_collection $romcopy_datalen $romcopy_romcmd]
set romcopy_cpuregs [add_to_collection $romcopy_cpuregs $romcopy_ramstart]
set romcopy_cpuregs [add_to_collection $romcopy_cpuregs $romcopy_go]

# CPU writes to the spirom registers are delayed by one ram_clk
set_multicycle_path -from $sys_clk -to $romcopy_cpuregs -end -setup 2
set_multicycle_path -from $sys_clk -to $romcopy_cpuregs -end -hold 1

# go_spi is delayed by the synchronizer, so other bits in the ROMCOPY_DATALEN
# register have some more time to settle.
set_multicycle_path -from $romcopy_datalen -to $flash_clk -end -setup 2
set_multicycle_path -from $romcopy_datalen -to $flash_clk -end -hold 1

# A load of romcmd does not affect the SPI unit for a minimum of 3 target
# clock cycles (in reality much more, since the CPU needs to
# write datalen in order to start the transfer).
set_multicycle_path -from $romcopy_romcmd -to $flash_clk -end -setup 3
set_multicycle_path -from $romcopy_romcmd -to $flash_clk -end -hold 2

# spi_active to spi_clk_en is a minimum of one clock cycle, which allows
# an extra clock cycle before spi_out_shr needs to stop resetting
set spi_active  [get_registers {*|spirom:*|spi_active}]
set spi_out_shr [get_registers {*|spirom:*|spi_out_shr[*]}]
set_multicycle_path -from $spi_active -to $spi_out_shr -end -setup 2
set_multicycle_path -from $spi_active -to $spi_out_shr -end -hold 1

# Reading ROMCOPY_INPUT while a transaction is pending is not supported.
# The CPU is supposed to wait for IRQ to get asserted; this is extremely
# conservative.
set romcopy_input [get_registers {*|spirom:*|spi_in_shr[*]}]
set_multicycle_path -from $romcopy_input -to $sys_clk -end -setup 2
set_multicycle_path -from $romcopy_input -to $sys_clk -end -hold 1

# -------- CPU/fastmem multicycle paths --------

# We never read and write in the same clock cycle, thus there is a multicycle
# path from the write enable register to anything in the CPU itself
set fast_mem_we [get_keepers {*|fast_mem:fast_mem|*porta_we_reg*}]
set cpu_regs    [get_keepers {*|picorv32:cpu|*}]
set_multicycle_path -from $fast_mem_we -to $cpu_regs -start -setup 2
set_multicycle_path -from $fast_mem_we -to $cpu_regs  -start -hold 1

# -------- Random number generator pins are asynchronous --------
set_false_path -from [get_ports {rngio[*]}] -to [get_keepers *]
