platform.tcl 11.2 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#
# Copyright (C) 2017 Jens Korinth, TU Darmstadt
#
# This file is part of Tapasco (TPC).
#
# Tapasco is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Tapasco is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with Tapasco.  If not, see <http://www.gnu.org/licenses/>.
#
# @file		platform.tcl
# @brief	Platform skeleton implementations.
# @author	J. Korinth, TU Darmstadt (jk@esa.tu-darmstadt.de)
#
namespace eval platform {
24
  namespace export create
25
  namespace export generate
26
27
  namespace export get_address_map

28
29
30
31
32
33
34
35
  # Creates the platform infrastructure, consisting of a number of subsystems.
  # Subsystems "host", "clocks_and_resets", "memory", "intc" and "tapasco" are
  # mandatory, their wiring pre-defined. Custom subsystems can be instantiated
  # by implementing a "create_custom_subsystem_<NAME>" proc in platform::, where
  # <NAME> is a placeholder for the name of the subsystem.
  proc create {} {
    set instance [current_bd_instance]
    # create mandatory subsystems
36
    set ss_host    [tapasco::subsystem::create "host"]
37
    set ss_cnrs    [tapasco::subsystem::create "clocks_and_resets" true]
38
39
40
    set ss_mem     [tapasco::subsystem::create "memory"]
    set ss_intc    [tapasco::subsystem::create "intc"]
    set ss_tapasco [tapasco::subsystem::create "tapasco"]
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59

    set sss [list $ss_cnrs $ss_host $ss_intc $ss_mem $ss_tapasco]

    foreach ss $sss {
      set name [string trim $ss "/"]
      set cmd  "create_subsystem_$name"
      puts "Creating subsystem $name ..."
      if {[llength [info commands $cmd]] == 0} {
        error "Platform does not implement mandatory command $cmd!"
      }
      current_bd_instance $ss
      eval $cmd
      current_bd_instance $instance
    }

    # create custom subsystems
    foreach ss [info commands create_custom_subsystem_*] {
      set name [regsub {.*create_custom_subsystem_(.*)} $ss {\1}]
      puts "Creating custom subsystem $name ..."
60
      current_bd_instance [tapasco::subsystem::create $name]
61
62
63
64
65
66
      eval $ss
      current_bd_instance $instance
    }

    wire_subsystem_wires
    wire_subsystem_intfs
67
68
69
70
71
72
73
74
75
76
77
78
79
80
    construct_address_map
  }

  proc connect_subsystems {} {
    foreach s {host design mem} {
      connect_bd_net [get_bd_pins -of_objects [get_bd_cells] -filter "NAME == ${s}_clk && DIR == O"] \
        [get_bd_pins -of_objects [get_bd_cells] -filter "NAME =~ ${s}_clk && DIR == I"]
      connect_bd_net [get_bd_pins -of_objects [get_bd_cells] -filter "NAME == ${s}_interconnect_resetn && DIR == O"] \
        [get_bd_pins -of_objects [get_bd_cells] -filter "NAME =~ ${s}_interconnect_resetn && DIR == I"] \
      connect_bd_net [get_bd_pins -of_objects [get_bd_cells] -filter "NAME == ${s}_peripheral_resetn && DIR == O"] \
        [get_bd_pins -of_objects [get_bd_cells] -filter "NAME =~ ${s}_peripheral_resetn && DIR == I"] \
      connect_bd_net [get_bd_pins -of_objects [get_bd_cells] -filter "NAME == ${s}_peripheral_reset && DIR == O"] \
        [get_bd_pins -of_objects [get_bd_cells] -filter "NAME =~ ${s}_peripheral_resetn && DIR == O"] \
    }
81
82
83
84
85
86
  }

  proc create_subsystem_tapasco {} {
    set port [create_bd_intf_pin -vlnv [tapasco::get_vlnv "aximm_intf"] -mode Slave "S_TAPASCO"]
    set tapasco_status [tapasco::createTapascoStatus "tapasco_status"]
    connect_bd_intf_net $port [get_bd_intf_pins -of_objects $tapasco_status -filter "VLNV == [tapasco::get_vlnv aximm_intf] && MODE == Slave"]
87
    connect_bd_net [tapasco::subsystem::get_port "design" "clk"] [get_bd_pins -of_objects $tapasco_status -filter {TYPE == clk && DIR == I}]
88
    connect_bd_net [tapasco::subsystem::get_port "design" "rst" "peripheral" "reset"] [get_bd_pins -of_objects $tapasco_status -filter {TYPE == rst && DIR == I}]
89
90
91
  }

  proc wire_subsystem_wires {} {
92
93
    foreach p [get_bd_pins -quiet -of_objects [get_bd_cells] -filter {INTF == false && DIR == I}] {
      if {[llength [get_bd_nets -quiet -of_objects $p]] == 0} {
94
95
96
        set name [get_property NAME $p]
        set type [get_property TYPE $p]
        puts "Looking for matching source for $p ($name) with type $type ..."
97
        set src [lsort [get_bd_pins -quiet -of_objects [get_bd_cells] -filter "NAME == $name && TYPE == $type && INTF == false && DIR == O"]]
98
99
100
101
102
103
104
105
106
107
108
        if {[llength $src] > 0} {
          puts "  found pin: $src, connecting $p -> $src"
          connect_bd_net $src $p
        } else {
          puts "  found no matching pin for $p"
        }
      }
    }
  }

  proc wire_subsystem_intfs {} {
109
110
    foreach p [get_bd_intf_pins -quiet -of_objects [get_bd_cells] -filter {MODE == Slave}] {
      if {[llength [get_bd_intf_nets -quiet -of_objects $p]] == 0} {
111
112
113
        set name [regsub {^S_} [get_property NAME $p] {M_}]
        set vlnv [get_property VLNV $p]
        puts "Looking for matching source for $p ($name) with VLNV $vlnv ..."
114
        set srcs [lsort [get_bd_intf_pins -quiet -of_objects [get_bd_cells] -filter "NAME == $name && VLNV == $vlnv && MODE == Master"]]
115
        foreach src $srcs {
116
          if {[llength [get_bd_intf_nets -quiet -of_objects $src]] == 0} {
117
118
119
120
121
122
123
124
125
126
127
            puts "  found pin: $src, connecting $p -> $src"
            connect_bd_intf_net $src $p
            break
          } else {
            puts "  found no matching pin for $p"
          }
        }
      }
    }
  }

128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
  # Checks all current runs at given step for errors, outputs their log files in case.
  # @param synthesis Checks synthesis runs if true, implementation runs otherwise.
  proc check_run_errors {{synthesis true}} {
    if {$synthesis} {
      set failed_runs [get_runs -filter "IS_SYNTHESIS == 1 && PROGRESS != {100%}"]
    } else {
      set failed_runs [get_runs -filter "IS_IMPLEMENTATION == 1 && PROGRESS != {100%}"]
    }
    # check number of failed runs
    if {[llength $failed_runs] > 0} {
      puts "at least one run failed, check these logs for errors:"
      foreach r $failed_runs {
        puts "  [get_property DIRECTORY $r]/runme.log"
      }
      exit 1
    }
  }

  # Platform API: Main entry point to generate the bitstream.
  proc generate {} {
    global bitstreamname
    # generate bitstream from given design and report utilization / timing closure
    set jobs [tapasco::get_number_of_processors]
    puts "  using $jobs parallel jobs"

    generate_target all [get_files system.bd]
    set synth_run [get_runs synth_1]
    set_property -dict [list \
      strategy Flow_PerfOptimized_high \
      STEPS.SYNTH_DESIGN.ARGS.DIRECTIVE AlternateRoutability \
      STEPS.SYNTH_DESIGN.ARGS.RETIMING true \
    ] $synth_run
    current_run $synth_run
    launch_runs -jobs $jobs $synth_run
    wait_on_run $synth_run
    if {[get_property PROGRESS $synth_run] != {100%}} { check_run_errors true }
    open_run $synth_run

    # call plugins
    tapasco::call_plugins "post-synth"

    set impl_run [get_runs impl_1]
    set_property -dict [list \
      STEPS.ROUTE_DESIGN.ARGS.DIRECTIVE Explore \
      STEPS.PHYS_OPT_DESIGN.IS_ENABLED true \
    ] $impl_run
    current_run $impl_run
    launch_runs -jobs $jobs -to_step route_design $impl_run
    wait_on_run $impl_run
    if {[get_property PROGRESS $impl_run] != {100%}} { check_run_errors false }
    open_run $impl_run

    # call plugins
    tapasco::call_plugins "post-impl"

    if {[get_property PROGRESS [get_runs $impl_run]] != "100%"} {
      error "ERROR: impl failed!"
    }
    report_timing_summary -warn_on_violation -file timing.txt
    report_utilization -file utilization.txt
    report_utilization -file utilization_userlogic.txt -cells [get_cells -hierarchical -filter {NAME =~ *target_ip_*}]
    report_power -file power.txt
    set wns [tapasco::get_wns_from_timing_report "timing.txt"]
    if {$wns >= -0.3} {
      write_bitstream -force "${bitstreamname}.bit"
    } else {
      error "timing failure, WNS: $wns"
    }
  }
197
198
199
200
201
202
203

  # Returns the base address of the PEs in the device address space.
  proc get_pe_base_address {} {
    error "Platform does not implement mandatory proc get_pe_base_address!"
  }

  proc get_address_map {{pe_base ""}} {
204
    set max64 [expr "1 << 64"]
205
206
    if {$pe_base == ""} { set pe_base [get_pe_base_address] }
    set peam [::arch::get_address_map $pe_base]
207
    puts "Computing addresses for masters ..."
208
209
    foreach m [tapasco::get_aximm_interfaces [get_bd_cells -filter {PATH !~ /uArch/*}]] {
      switch -glob [get_property NAME $m] {
210
211
212
213
214
215
216
        "M_DMA"     { foreach {base stride range} [list 0x00300000 0x10000 0     ] {} }
        "M_INTC"    { foreach {base stride range} [list 0x00400000 0x10000 0     ] {} }
        "M_MSIX"    { foreach {base stride range} [list 0x00500000 0x10000 $max64] {} }
        "M_TAPASCO" { foreach {base stride range} [list 0x02800000 0       0     ] {} }
        "M_HOST"    { foreach {base stride range} [list 0          0       $max64] {} }
        "M_ARCH"    { set base "skip" }
        default     { foreach {base stride range} [list 0 0 0]                     {} }
217
      }
218
      if {$base != "skip"} { set peam [assign_address $peam $m $base $stride $range] }
219
220
221
222
    }
    return $peam
  }

223
224
225
226
227
228
229
230
231
232
233
234
  proc assign_address {address_map master base {stride 0} {range 0}} {
    foreach seg [lsort [get_bd_addr_segs -addressables -of_objects $master]] {
      puts [format "  $master: $seg -> 0x%08x (range: 0x%08x)" $base $range]
      set sintf [get_bd_intf_pins -of_objects $seg]
      if {$range <= 0} { set range [get_property RANGE $seg] }
      set kind [get_property USAGE $seg]
      dict set address_map $sintf "interface $sintf offset $base range $range kind $kind"
      if {$stride == 0} { incr base $range } else { incr base $stride }
    }
    return $address_map
  }

235
236
237
238
239
240
  proc construct_address_map {{map ""}} {
    if {$map == ""} { set map [get_address_map [get_pe_base_address]] }
    puts "ADDRESS MAP: $map"
    set seg_i 0
    foreach space [get_bd_addr_spaces] {
      puts "space: $space"
241
      set intfs [get_bd_intf_pins -quiet -of_objects $space -filter { MODE == Master }]
242
243
244
      foreach intf $intfs {
        set segs [get_bd_addr_segs -addressables -of_objects $intf]
        foreach seg $segs {
245
          puts "  seg: $seg"
246
247
248
249
250
251
252
253
254
          set sintf [get_bd_intf_pins -quiet -of_objects $seg]
          if {[catch {dict get $map $intf}]} {
            if {[catch {dict get $map $sintf}]} {
              error "neither $intf nor $sintf were found in address map for $seg: $::errorInfo"
            }
            set me [dict get $map $sintf]
          } else {
            set me [dict get $map $intf]
          }
255
          puts "    address map info: $me]"
256
257
          set range  [dict get $me "range"]
          set offset [dict get $me "offset"]
258
259
260
261
262
          puts "      range: $range"
          puts "      offset: $offset"
          puts "      space: $space"
          puts "      seg: $seg"
          if {[expr "(1 << 64) == $range"]} { set range "16E" }
263
264
          create_bd_addr_seg \
            -offset $offset \
265
            -range $range \
266
267
268
269
270
271
272
273
            $space \
            $seg \
            [format "AM_SEG_%03d" $seg_i]
          incr seg_i
        }
      }
    }
  }
274
}