5 # Circuit pin layout program, for mapping sub-chip (or partially sub-chip)
6 # subcircuits to actual integrated circuit chips plus optional extra components,
7 # outside the chip. For example, the 'tinv' subcircuit has a complementary pair
8 # of MOSFETs, which this program maps to part of CD4007, assigning the pins,
9 # and mapping the other pair inside the CD4007 if another 'tinv' comes along.
21 PROGRAM_NAME
= "bb.py"
23 # Start chip numbering at this value.
24 CHIP_NO_START
= int(os
.environ
.get("JC_CHIP_START", 1))
26 # Subcircuits to map that should be mapped physical ICs
27 SUBCIRCUITS_TO_MAP
= ('tg', 'tinv', 'tnor', 'tnor3', 'tnand', 'tnand3', 'sp3t-1', 'sp3t-2', 'sp3t-3')
28 SUBCIRCUITS_CAN_MAP
= ('tg', 'tinv', 'tnor', 'tnand') # subcircuits we actually can map to ICs, as of yet
29 SUBCIRCUITS_PASS
= ('sp3t-1', 'sp3t-2', 'sp3t-3') # pass unchanged to pads.py
31 # If False, use discrete resistors
32 # If True, use the MDP140 resistor network
33 USE_RESISTOR_CHIP
= bool(int(os
.environ
.get("JC_USE_RESISTOR_CHIP", False)))
34 RESISTOR_CHIP
= "MDP1403" # Vishay isolated 7-resistor network
37 "CD4007", # dual complementary MOSFETs + binary inverter
38 "CD4016", # quad transmission gates
39 #RESISTOR_CHIP # handled above
43 RESISTOR_NETWORK_PINS
= ((1, 14), (2, 13), (3, 12), (4, 11), (5, 10), (6, 9), (7,8))
45 def combine_dicts(dict1
, dict2
):
46 """Combine two dictionaries; dict2 takes priority over dict1."""
47 ret
= copy
.deepcopy(dict1
)
51 def read_netlist(filename
):
52 """Read a SPICE input deck, returning subcircuit nodes and definitions."""
57 f
= file(filename
, "rt")
69 if line
.startswith(".subckt"):
74 subckt_nodes
[name
] = nodes
75 elif line
.startswith(".ends"):
79 if not subckt_defns
.has_key(name
):
80 subckt_defns
[name
] = []
81 subckt_defns
[name
].append(line
)
83 # Top-level elements, skip blank lines, commands and comments
84 if len(line
.strip()) != 0 and line
[0] not in ('.', '*'):
87 return subckt_nodes
, subckt_defns
, toplevel
89 def rewrite_subckt(subckt_defns
, s
):
90 """Partially rewrite subcircuit 's', using rules from a module of the same name.
92 Removes parts in mod.parts_consumed, keeps parts in mod.parts_kept.
94 Does not generate any new parts."""
98 for line
in subckt_defns
[s
]:
103 if name
in mod
.parts_consumed
:
106 elif name
in mod
.parts_kept
:
109 raise "Subcircuit %s defined in module %s has parts consumed list: %s and parts kept list: %s, but the name '%s' is in neither. Add it to either." % (s
, name
, mod
.parts_consumed
, mod
.parts_kept
, name
)
111 # Map node positions in arguments list (subckt invocation, X..), to node names
113 for i
in range(0, len(mod
.nodes
)):
114 pos2node
[mod
.nodes
[i
]] = i
117 subckt_defns
[s
] = lines
119 return mod
, subckt_defns
, pos2node
123 """Get a unique, increasing number."""
129 def get_floating(n
=None):
130 """Return a unique disconnected (floating) node name.
132 If n is given, return a dict of n floating node names. Otherwise returns one in a string."""
134 return get_floating_n(n
)
136 return "NC__%s" % (get_serial(), )
138 def get_floating_n(n
):
139 """Get n floating nodes, see get_floating()."""
141 for x
in range(1, n
+ 1):
142 fs
[x
] = get_floating()
145 def is_floating(node_name
):
146 """Return whether the given node name is probably not connected;
147 generated from get_floating()."""
148 return node_name
.startswith("NC_")
150 def chip_has_pins_available(pins_needed
, pins
):
151 """Return whether 'pins' has not-connected pins, all those required in pins_needed."""
152 for p
in pins_needed
:
153 if not is_floating(pins
[p
]):
157 # This program doesn't thoroughly parse SPICE cards, so you must
158 # give it parameters that are not nodes, to not map at all.
159 # For example, '12k' for the 12k resistors. TODO: better parsing
160 def find_chip(chips
, model_needed
, pins_needed_options
):
161 """Return an index into the chips array, and what pins, with the given model and the pins free.
163 pins_needed_options is a list of lists, of any acceptable set of pins to use.
165 A new chip is added if none are found. """
167 result
= find_chip_no_add(chips
, model_needed
, pins_needed_options
)
168 if result
is not None:
171 # No chips found with model model_needed and with pins free. Need more chips.
172 if model_needed
not in KNOWN_CHIPS
and not model_needed
.startswith(RESISTOR_CHIP
):
173 raise "Model %s not known, it is not in %s, not recognized!" % (model_needed
, KNOWN_CHIPS
)
176 # Assume all are 14-pin chips
177 chips
.append((model_needed
, get_floating(14)))
179 result
= find_chip_no_add(chips
, model_needed
, pins_needed_options
)
180 if result
is not None:
183 raise "Tried to find model %s with pins %s free, then added a new chip but couldn't find it!" % (
184 model_needed
, pins_needed_options
)
186 def find_chip_no_add(chips
, model_needed
, pins_needed_options
):
187 """Find chip to use (see find_chip), but return None if not found instead of adding."""
188 for i
, chip
in enumerate(chips
):
190 if model
!= model_needed
:
193 for option_num
, option
in enumerate(pins_needed_options
):
194 # Note: I do not yet check if the chip has pins that are used, but are assigned to
195 # the same node that is required. The pins must be unused.
196 if chip_has_pins_available(option
, pins
):
197 #print "* Found model %s with pins %s free: chip #%s" % (model_needed, option, i)
201 def find_pins_needed(pins
):
202 """From a mod.pins[x] dict, return the pins needed for each SPICE model, for find_chip()"""
204 for x
in pins
.values():
205 if type(x
) == types
.TupleType
:
207 if not need
.has_key(model
):
210 need
[model
].append(pin
)
211 elif type(x
) == types
.ListType
:
214 if not need
.has_key(model
):
217 need
[model
].append(pin
)
221 def assign_part(chips
, subckt_defns
, extra
, model_name
, external_nodes
, refdesg
):
222 """Assign a given model to a physical chip, using the names of the external nodes.
224 chips: array of existing physical chips that can be assigned from
225 mod: logical model to map to, like 'tinv'
226 external_nodes: dict mapping internal nodes in the model, to external nodes in the world
229 mod
= globals()[model_name
]
230 subckt_lines
= subckt_defns
[model_name
]
233 # Store new pin assignments
235 for p
in mod
.parts_generated
:
241 need
= find_pins_needed(p
)
243 raise "Sorry, more than one model is needed: %s, but only one is supported right now." % (need
,)
244 if the_model
is None:
245 the_model
= need
.keys()[0]
247 if the_model
!= need
.keys()[0]:
248 raise "Sorry, different models are needed: %s, but already decided on %s earlier. This is not yet supported." % (the_model
, need
[0])
250 need_options
.append(need
.values()[0])
252 #print "* Searching for model %s with one of pins: %s" % (the_model, need_options)
253 chip_num
, option_num
= find_chip(chips
, the_model
, need_options
)
254 #print "* FOUND CHIP:",chip_num
255 #print "* WITH PINS (option #%s):" % (option_num,), mod.pins[option_num]
258 for node_pin
in combine_dicts(mod
.global_pins
, mod
.pins
[option_num
]).iteritems():
261 if type(pin
) == types
.TupleType
:
263 findings
.append((node
, part
, pin
))
264 elif type(pin
) == types
.ListType
:
267 findings
.append((node
, part
, p
))
270 findings
.append((node
, part
, pin
))
272 for node
, part
, pin
in findings
:
273 #print "* %s -> %s:%s" % (node, part, pin)
276 if node
.startswith("$G_") or node
== "0":
277 new_node
= node
# global node (LTspice)
278 elif external_nodes
.has_key(node
):
279 #sys.stderr.write("Mapping external node %s, map = %s\n" % (node, external_nodes))
280 new_node
= external_nodes
[node
] # map internal to external node
282 #sys.stderr.write("Mapping internal-only node %s\n" % (node,))
283 # 'refdesg' here is prefixed with X, for a subcircuit instantation,
284 # but we only need the subcircuit prefix for a node, without the
286 assert refdesg
[0:2] == 'X$', "Assumed refdesg %s began with X$, but it didn't" % (refdesg
,)
287 refdesg_without_letter
= refdesg
[2:]
288 new_node
= rewrite_node("", refdesg_without_letter
, node
)
289 #sys.stderr.write("Rewriting to node = %s\n" % (new_node,))
291 #sys.stderr.write("Adding to chips: %s\n" % (new_node,))
292 chips
[chip_num
][1][pin
] = new_node
294 internal_only_nodes
= {}
296 # Now place any ++additional parts++ (resistors, etc.) within the subcircuit model
297 # that connect to the chip, but are not part of the chip.
298 for line
in subckt_lines
:
302 if words
[0][0] == "M":
303 raise ("This line:\t%s\nIn the subcircuit '%s', has a MOSFET left " +
304 "over that wasn't converted. Probably it was meant to be converted to an IC? " +
305 "Comment out this line in %s if you are sure you want this, otherwise " +
306 "double-check the model definition for '%s', specifically, " +
307 "parts_consumed and parts_kept.\nAlso, check if the model was rewritten!") % (line
, model_name
, PROGRAM_NAME
, model_name
)
310 #name = "%s_%s_%s_%s" % (words[0], model_name, chip_num, refdesg)
311 name
= "%s%s$%s" % (words
[0][0], refdesg
, words
[0])
313 new_words
.append(name
)
316 model_name
= words
[-1]
318 # Replace internal nodes with external nodes.
320 if w
in external_nodes
.keys():
321 new_words
.append(external_nodes
[w
])
324 new_words
.append(get_floating())
326 if not internal_only_nodes
.has_key(w
):
327 #internal_only_nodes[w] = "%s$%s$%s" % (w[0], refdesg, w)
328 assert refdesg
[0:2] == 'X$', "Reference designator %s expected to begin with X$, but didn't" % (refdesg
,)
329 refdesg_without_letter
= refdesg
[2:]
330 internal_only_nodes
[w
] = rewrite_node("", refdesg_without_letter
, w
)
331 new_words
.append(internal_only_nodes
[w
])
333 # TODO: comment this out, if the above works
334 #raise "Could not map argument '%s' in subcircuit line %s, not found in %s" % (w, line, external_nodes)
336 new_words
.append(model_name
)
338 if words
[0][0] == "R" and USE_RESISTOR_CHIP
:
339 resistor_value
= words
[3]
340 # Find resistor chip, named after resistor value.
341 chip_num
, option_num
= find_chip(chips
, RESISTOR_CHIP
+ "-" + resistor_value
.upper(), RESISTOR_NETWORK_PINS
)
342 pins
= RESISTOR_NETWORK_PINS
[option_num
]
344 # Assign pins on resistor network to nodes
345 # Order doesn't matter for electrical purposes, but
346 # for RN, swap pins since often RP and RN are back-to-back.
347 # Doesn't affect electrical connections, though better
348 # for routing purposes.
349 if words
[0].endswith("RN"):
350 chips
[chip_num
][1][pins
[0]] = new_words
[2]
351 chips
[chip_num
][1][pins
[1]] = new_words
[1]
353 chips
[chip_num
][1][pins
[0]] = new_words
[1]
354 chips
[chip_num
][1][pins
[1]] = new_words
[2]
357 extra
.append(" ".join(new_words
))
361 def any_pins_used(pins
):
362 """Return whether any of the pins on a chip are used. If False, chip isn't used."""
363 for p
in pins
.values():
364 if not is_floating(p
):
368 def dump_chips(chips
):
369 """Show the current chips and their pin connections."""
370 for i
, c
in enumerate(chips
):
373 if not any_pins_used(p
):
374 print "* Chip #%s - %s no pins used, skipping" % (i
+ CHIP_NO_START
, m
)
377 print "* Chip #%s - %s pinout:" % (i
+ CHIP_NO_START
, m
)
378 for k
, v
in p
.iteritems():
379 print "* \t%s: %s" % (k
, v
)
381 print "IC_%s_%s" % (m
, i
+ CHIP_NO_START
),
382 # Assumes all chips are 14-pin, arguments from 1 to 14 positional
383 for k
in range(1, 14+1):
388 def dump_extra(extra
):
389 """Shows the extra, supporting subcircuit parts that support the IC and are part of the subcircuit."""
390 print "* Parts to support subcircuits:"
394 def make_node_mapping(internal
, external
):
395 """Make a node mapping dictionary from internal to external nodes.
396 Keys of the returned dictionary are internal nodes (of subcircuit), values are external."""
398 d
.update(zip(internal
, external
))
401 def rewrite_refdesg(original
, prefix
):
402 """Prefix a reference designator, preserving the first character."""
403 new_refdesg
= "%s%s$%s" % (original
[0], prefix
, original
)
405 #sys.stderr.write("@ rewrite_refdesg = %s\n" % (new_refdesg,))
408 def rewrite_node(prefix
, circuit_inside
, original_node_name
):
409 """Rewrite a node name inside a subcircuit, prefixing it with
410 prefix and the name of the circuit that it is inside (both
413 # Globals never rewritten
414 if original_node_name
.startswith("$G_") or original_node_name
== "0":
415 return original_node_name
417 new_name
= original_node_name
419 new_name
= "%s$%s" % (circuit_inside
, new_name
)
422 new_name
= "%s$%s" % (prefix
, new_name
)
424 # Nodes don't need to begin with spurious '$'s (can happen if no prefix)
425 if new_name
[0] == '$':
426 new_name
= new_name
[1:]
428 #sys.stderr.write("@@ rewrite_node = %s\n" % (new_name,))
431 def is_expandable_subcircuit(refdesg
, model
):
432 """Return whether the SPICE reference designator and model is
433 a) a subcircuit, b) _and_ it can be hierarchically expanded further."""
434 return refdesg
[0] == 'X' and model
not in SUBCIRCUITS_TO_MAP
436 def expand(subckt_defns
, subckt_nodes
, line
, prefix
, outer_nodes
, outer_prefixes
):
437 """Recursively expand a subcircuit instantiation if needed."""
439 outer_refdesg
= words
[0]
440 outer_model
= words
[-1]
441 outer_args
= words
[1:-1]
443 #sys.stderr.write("expand(%s,%s,%s,%s)\n" % (line, prefix, outer_nodes, outer_prefixes))
444 if is_expandable_subcircuit(outer_refdesg
, outer_model
):
445 nodes
= make_node_mapping(subckt_nodes
[outer_model
], outer_args
)
447 new_lines
.append(("* %s: Instance of subcircuit %s: %s" % (outer_refdesg
, outer_model
, " ".join(outer_args
))))
449 # Notes that are internal to the subcircuit, not exposed in any ports
450 internal_only_nodes
= {}
452 for sline
in subckt_defns
[outer_model
]:
453 swords
= sline
.split()
454 inner_refdesg
= swords
[0]
455 inner_model
= swords
[-1]
456 inner_args
= swords
[1:-1]
458 if is_expandable_subcircuit(inner_refdesg
, inner_model
):
459 # Recursively expand subcircuits, to transistor-level subcircuits (SUBCIRCUITS_TO_MAP)
461 prefixes_to_pass
= {}
463 if outer_nodes
.has_key(nodes
[n
]):
464 nodes_to_pass
[n
] = outer_nodes
[nodes
[n
]]
465 prefixes_to_pass
[nodes_to_pass
[n
]] = outer_prefixes
[nodes_to_pass
[n
]]
467 nodes_to_pass
[n
] = nodes
[n
]
468 prefixes_to_pass
[nodes_to_pass
[n
]] = prefix
469 # Only append separator if not empty
471 prefixes_to_pass
[nodes_to_pass
[n
]] += "$"
473 # Chop '$' if begins with it
474 if len(prefixes_to_pass
[nodes_to_pass
[n
]]) >= 1 and prefixes_to_pass
[nodes_to_pass
[n
]][0] == '$':
475 prefixes_to_pass
[nodes_to_pass
[n
]] = prefixes_to_pass
[nodes_to_pass
[n
]][1:]
476 #sys.stderr.write("PASSING NODES: %s (outer=%s, inner=%s), outer_refdesg=%s, prefix=%s\n" % (nodes_to_pass, outer_nodes, nodes, outer_refdesg, prefix))
477 #sys.stderr.write("\tPASSING PREFIXES: %s (outer=%s)\n" % (prefixes_to_pass, outer_prefixes))
478 new_lines
.extend(expand(subckt_defns
, subckt_nodes
, sline
, prefix
+
479 "$" + outer_refdesg
, nodes_to_pass
, prefixes_to_pass
))
482 # Nest reference designator
483 new_words
.append(rewrite_refdesg(inner_refdesg
, prefix
+ "$" + outer_refdesg
))
485 # Map internal to external nodes
488 if w
in nodes
.keys():
489 # Follow up the hierarchy. Without doing this, leads to:
490 # incomplete nets. For example, dtflop-ms_test.net maps:
492 # In nodes {'Q': 'Q', 'C': 'CLK', 'D': 'D'}, rewrite C -> CLK, prefix [correct]
493 # In nodes {'Q': 'Q', 'C': 'CLK', 'D': 'D'}, rewrite C -> CLK, prefix [correct]
495 # but because the 'nodes' dict is only for the parent, it
496 # doesn't map this correctly, leading to an unconnected node:
498 # In nodes {'OUT': '_C', 'IN': 'C'}, rewrite IN -> C, prefix Xflipflop [wrong]
500 # It should be CLK, not Xflipflop$C. These problems will occur
501 # with more nesting of subcircuits
502 if nodes
[w
] in outer_nodes
:
503 # This is a port of this subcircuit, ascends hierarchy
504 new_words
.append(outer_prefixes
[outer_nodes
[nodes
[w
]]] + outer_nodes
[nodes
[w
]])
505 #new_words.append(outer_nodes[nodes[w]])
506 #sys.stderr.write("Node %s -> %s -> %s (outer nodes=%s, prefixes=%s) (prefix=%s, refdesgs=%s,%s)\n" %
507 # (w, nodes[w], outer_nodes[nodes[w]], outer_nodes, outer_prefixes, prefix,
508 # outer_refdesg, inner_refdesg))
510 new_words
.append(rewrite_node(prefix
, "", nodes
[w
]))
513 # This is a port, but that is not connected on the outside, but
514 # still may be internally-connected so it needs a node name.
515 # Name it what it is called inside, hierarchically nested.
516 inner_node_map
= make_node_mapping(inner_args
, subckt_nodes
[inner_model
])
517 new_words
.append(rewrite_node(prefix
, outer_refdesg
, inner_node_map
[w
]))
518 #print "Floating:",w," now=",new_words,"node map=",inner_node_map
520 # A signal only connected within this subcircuit, but not a port.
521 # Make a new node name for it and replace it.
522 if not internal_only_nodes
.has_key(w
):
523 internal_only_nodes
[w
] = rewrite_node(prefix
, outer_refdesg
, w
)
524 #print "* sline: %s, Subcircuit %s, mapping internal-only node %s -> %s" % (sline, outer_model, w, internal_only_nodes[w])
526 new_words
.append(internal_only_nodes
[w
])
528 #raise "Expanding subcircuit line '%s' (for line '%s'), couldn't map word %s, nodes=%s" % (sline, line, w, nodes)
530 new_words
.append(inner_model
)
532 new_lines
.append(" ".join(new_words
))
533 #new_lines.append("")
540 """Demonstrate flattening of a hierarchical subcircuit."""
541 if os
.access("testcases", os
.R_OK | os
.X_OK
):
542 testdir
= "testcases"
547 for case_in
in sorted(os
.listdir(testdir
)):
548 if ".in" not in case_in
or ".swp" in case_in
:
550 case
= case_in
.replace(".in", "")
552 subckt_nodes
, subckt_defns
, toplevel
= read_netlist("%s/%s.in" % (testdir
, case
))
555 for line
in toplevel
:
556 actual_out
.extend(expand(subckt_defns
, subckt_nodes
, line
, "", {}, {}))
558 outfile
= file("%s/%s.act" % (testdir
, case
), "wt")
559 for line
in actual_out
:
562 outfile
.write("%s\n" % (line
,))
565 if os
.system("diff -u %s/%s.exp %s/%s.act" % (testdir
, case
, testdir
, case
)) != 0:
566 print "%2d. FAILED: %s" % (i
, case
)
569 print "%2d. Passed: %s" % (i
, case
)
573 def test_assignment():
574 """Demonstrate subcircuit assignment."""
575 subckt_nodes
, subckt_defns
, toplevel
= read_netlist("mux3-1_test.net")
577 mod_tinv
, subckt_defns
, pos2node_tinv
= rewrite_subckt(subckt_defns
, "tinv")
578 tg_tinv
, subckt_defns
, pos2node_tg
= rewrite_subckt(subckt_defns
, "tg")
583 ("CD4007", get_floating(14) ),
584 ("CD4016", get_floating(14) ),
585 #("CD4007", get_floating(14) )
589 chips
, extra
= assign_part(chips
, subckt_defns
, extra
, "tinv",
592 "PTI_Out": "PTI_Out_1",
593 "NTI_Out": "NTI_Out_1",
594 "STI_Out": "STI_Out_1",
597 chips
, extra
= assign_part(chips
, subckt_defns
, extra
, "tinv",
600 "PTI_Out": "PTI_Out_2",
601 "NTI_Out": "NTI_Out_2",
602 "STI_Out": "STI_Out_2",
605 chips
, extra
= assign_part(chips
, subckt_defns
, extra
, "tg",
611 chips
, extra
= assign_part(chips
, subckt_defns
, extra
, "tg",
617 chips
, extra
= assign_part(chips
, subckt_defns
, extra
, "tg",
623 chips
, extra
= assign_part(chips
, subckt_defns
, extra
, "tg",
634 print """usage: %s input-filename [output-filename | -p]
636 input-filename A transistor-level SPICE netlist (.net)
637 output-filename Chip-level SPICE netlist (.net2)
639 If output-filename is omitted, input-filename is used but
640 with '2' appended, so .net becomes .net2 by convention.
642 Either filenames can be "-" for stdin or stdout, respectively.
644 The -p flag, instead of an output filename will also run pads.py
645 so that both .net2 and .pads files will be generated.
646 """ % (PROGRAM_NAME
, )
650 if len(sys
.argv
) < 2:
652 input_filename
= sys
.argv
[1]
654 generate_pads
= len(sys
.argv
) > 2 and sys
.argv
[2] == "-p"
656 subckt_nodes
, subckt_defns
, toplevel
= read_netlist(input_filename
)
658 # Redirect stdout to output file
659 if len(sys
.argv
) > 2 and sys
.argv
[2] != "-p":
660 output_filename
= sys
.argv
[2]
662 output_filename
= input_filename
+ "2"
664 if output_filename
!= "-":
665 sys
.stdout
= file(output_filename
, "wt")
667 print "* Chip-level netlist, converted from %s by %s" % (input_filename
, PROGRAM_NAME
)
669 # Circuits to rewrite need to be loaded first. Any transistor-level circuits
670 # you want to replace with ICs, are loaded here.
671 modules
= pos2node
= {}
672 for s
in SUBCIRCUITS_CAN_MAP
:
673 if subckt_defns
.has_key(s
):
674 modules
[s
], subckt_defns
, pos2node
[s
] = rewrite_subckt(subckt_defns
, s
)
676 # First semi-flatten the circuit
678 for line
in toplevel
:
679 flat_toplevel
.extend((expand(subckt_defns
, subckt_nodes
, line
, "", {}, {})))
681 print "* Flattened top-level, before part assignment:"
682 for f
in flat_toplevel
:
684 print "* Begin converted circuit"
691 for line
in flat_toplevel
:
693 if words
[0][0] == 'X':
698 #print "MODEL=%s, args=%s" % (model, args)
700 #print subckt_defns[model]
701 #print subckt_nodes[model]
703 if model
in SUBCIRCUITS_CAN_MAP
:
704 nodes
= make_node_mapping(subckt_nodes
[model
], args
)
706 chips
, extra
= assign_part(chips
, subckt_defns
, extra
, model
, nodes
, refdesg
)
707 elif model
in SUBCIRCUITS_PASS
:
710 raise "Cannot synthesize model: %s, line: %s" % (model
, line
)
717 sys
.stdout
= sys
.stderr
721 os
.system("python pads.py %s" % (output_filename
,))
723 if __name__
== "__main__":
724 if len(sys
.argv
) > 1 and sys
.argv
[1] == "-t":