67337460b407834b53e4249e6675d6d7889c1e57
3 not in any way intended for production use. connects up FunctionUnits to
4 Register Files in a brain-dead fashion that only permits one and only one
5 Function Unit to be operational.
7 the principle here is to take the Function Units, analyse their regspecs,
8 and turn their requirements for access to register file read/write ports
9 into groupings by Register File and Register File Port name.
11 under each grouping - by regfile/port - a list of Function Units that
12 need to connect to that port is created. as these are a contended
13 resource a "Broadcast Bus" per read/write port is then also created,
14 with access to it managed by a PriorityPicker.
16 the brain-dead part of this module is that even though there is no
17 conflict of access, regfile read/write hazards are *not* analysed,
18 and consequently it is safer to wait for the Function Unit to complete
19 before allowing a new instruction to proceed.
22 from nmigen
import Elaboratable
, Module
, Signal
, ResetSignal
, Cat
, Mux
23 from nmigen
.cli
import rtlil
25 from openpower
.decoder
.power_decoder2
import PowerDecodeSubset
26 from openpower
.decoder
.power_regspec_map
import regspec_decode_read
27 from openpower
.decoder
.power_regspec_map
import regspec_decode_write
28 from openpower
.sv
.svp64
import SVP64Rec
30 from nmutil
.picker
import PriorityPicker
31 from nmutil
.util
import treereduce
32 from nmutil
.singlepipe
import ControlBase
34 from soc
.fu
.compunits
.compunits
import AllFunctionUnits
35 from soc
.regfile
.regfiles
import RegFiles
36 from openpower
.decoder
.decode2execute1
import Decode2ToExecute1Type
37 from openpower
.decoder
.decode2execute1
import IssuerDecode2ToOperand
38 from openpower
.decoder
.power_decoder2
import get_rdflags
39 from openpower
.decoder
.decode2execute1
import Data
40 from soc
.experiment
.l0_cache
import TstL0CacheBuffer
# test only
41 from soc
.config
.test
.test_loadstore
import TestMemPspec
42 from openpower
.decoder
.power_enums
import MicrOp
43 from soc
.config
.state
import CoreState
47 from nmutil
.util
import rising_edge
50 # helper function for reducing a list of signals down to a parallel
52 def ortreereduce(tree
, attr
="o_data"):
53 return treereduce(tree
, operator
.or_
, lambda x
: getattr(x
, attr
))
56 def ortreereduce_sig(tree
):
57 return treereduce(tree
, operator
.or_
, lambda x
: x
)
60 # helper function to place full regs declarations first
61 def sort_fuspecs(fuspecs
):
63 for (regname
, fspec
) in fuspecs
.items():
64 if regname
.startswith("full"):
65 res
.append((regname
, fspec
))
66 for (regname
, fspec
) in fuspecs
.items():
67 if not regname
.startswith("full"):
68 res
.append((regname
, fspec
))
69 return res
# enumerate(res)
73 def __init__(self
, pspec
, svp64_en
, regreduce_en
):
75 self
.svp64_en
= svp64_en
76 self
.e
= Decode2ToExecute1Type("core", opkls
=IssuerDecode2ToOperand
,
77 regreduce_en
=regreduce_en
)
79 # SVP64 RA_OR_ZERO needs to know if the relevant EXTRA2/3 field is zero
80 self
.sv_a_nz
= Signal()
82 # state and raw instruction (and SVP64 ReMap fields)
83 self
.state
= CoreState("core")
84 self
.raw_insn_i
= Signal(32) # raw instruction
85 self
.bigendian_i
= Signal() # bigendian - TODO, set by MSR.BE
87 self
.sv_rm
= SVP64Rec(name
="core_svp64_rm") # SVP64 RM field
88 self
.is_svp64_mode
= Signal() # set if SVP64 mode is enabled
89 self
.use_svp64_ldst_dec
= Signal() # use alternative LDST decoder
90 self
.sv_pred_sm
= Signal() # TODO: SIMD width
91 self
.sv_pred_dm
= Signal() # TODO: SIMD width
93 # issue/valid/busy signalling
94 self
.ivalid_i
= Signal(reset_less
=True) # instruction is valid
95 self
.issue_i
= Signal(reset_less
=True)
99 self
.sv_a_nz
.eq(i
.sv_a_nz
)
100 self
.state
.eq(i
.state
)
101 self
.raw_insn_i
.eq(i
.raw_insn_i
)
102 self
.bigendian_i
.eq(i
.bigendian_i
)
103 if not self
.svp64_en
:
105 self
.sv_rm
.eq(i
.sv_rm
)
106 self
.is_svp64_mode
.eq(i
.is_svp64_mode
)
107 self
.use_svp64_ldst_dec
.eq(i
.use_svp64_ldst_dec
)
108 self
.sv_pred_sm
.eq(i
.sv_pred_sm
)
109 self
.sv_pred_dm
.eq(i
.sv_pred_dm
)
114 self
.busy_o
= Signal(name
="corebusy_o", reset_less
=True)
115 # start/stop and terminated signalling
116 self
.core_terminate_o
= Signal(reset
=0) # indicates stopped
119 self
.busy_o
.eq(i
.busy_o
)
120 self
.core_terminate_o
.eq(i
.core_terminate_o
)
123 # derive from ControlBase rather than have a separate Stage instance,
124 # this is simpler to do
125 class NonProductionCore(ControlBase
):
126 def __init__(self
, pspec
):
129 # test is SVP64 is to be enabled
130 self
.svp64_en
= hasattr(pspec
, "svp64") and (pspec
.svp64
== True)
132 # test to see if regfile ports should be reduced
133 self
.regreduce_en
= (hasattr(pspec
, "regreduce") and
134 (pspec
.regreduce
== True))
136 super().__init
__(stage
=self
)
138 # single LD/ST funnel for memory access
139 self
.l0
= l0
= TstL0CacheBuffer(pspec
, n_units
=1)
142 # function units (only one each)
143 # only include mmu if enabled in pspec
144 self
.fus
= AllFunctionUnits(pspec
, pilist
=[pi
])
146 # link LoadStore1 into MMU
147 mmu
= self
.fus
.get_fu('mmu0')
148 print ("core pspec", pspec
.ldst_ifacetype
)
149 print ("core mmu", mmu
)
150 print ("core lsmem.lsi", l0
.cmpi
.lsmem
.lsi
)
152 mmu
.alu
.set_ldst_interface(l0
.cmpi
.lsmem
.lsi
)
154 # register files (yes plural)
155 self
.regs
= RegFiles(pspec
)
157 # set up input and output: unusual requirement to set data directly
158 # (due to the way that the core is set up in a different domain,
159 # see TestIssuer.setup_peripherals
160 self
.i
, self
.o
= self
.new_specs(None)
161 self
.i
, self
.o
= self
.p
.i_data
, self
.n
.o_data
163 # create per-FU instruction decoders (subsetted)
167 for funame
, fu
in self
.fus
.fus
.items():
168 f_name
= fu
.fnunit
.name
169 fnunit
= fu
.fnunit
.value
170 opkls
= fu
.opsubsetkls
172 # TRAP decoder is the *main* decoder
173 self
.trapunit
= funame
175 self
.decoders
[funame
] = PowerDecodeSubset(None, opkls
, f_name
,
178 svp64_en
=self
.svp64_en
,
179 regreduce_en
=self
.regreduce_en
)
180 self
.des
[funame
] = self
.decoders
[funame
].do
182 if "mmu0" in self
.decoders
:
183 self
.decoders
["mmu0"].mmu0_spr_dec
= self
.decoders
["spr0"]
185 def setup(self
, m
, i
):
189 return CoreInput(self
.pspec
, self
.svp64_en
, self
.regreduce_en
)
194 def elaborate(self
, platform
):
195 m
= super().elaborate(platform
)
197 # for testing purposes, to cut down on build time in coriolis2
198 if hasattr(self
.pspec
, "nocore") and self
.pspec
.nocore
== True:
199 x
= Signal() # dummy signal
204 m
.submodules
.fus
= self
.fus
205 m
.submodules
.l0
= l0
= self
.l0
206 self
.regs
.elaborate_into(m
, platform
)
211 for k
, v
in self
.decoders
.items():
212 # connect each satellite decoder and give it the instruction.
213 # as subset decoders this massively reduces wire fanout given
214 # the large number of ALUs
215 setattr(m
.submodules
, "dec_%s" % v
.fn_name
, v
)
216 comb
+= v
.dec
.raw_opcode_in
.eq(self
.i
.raw_insn_i
)
217 comb
+= v
.dec
.bigendian
.eq(self
.i
.bigendian_i
)
218 # sigh due to SVP64 RA_OR_ZERO detection connect these too
219 comb
+= v
.sv_a_nz
.eq(self
.i
.sv_a_nz
)
221 comb
+= v
.pred_sm
.eq(self
.i
.sv_pred_sm
)
222 comb
+= v
.pred_dm
.eq(self
.i
.sv_pred_dm
)
223 if k
!= self
.trapunit
:
224 comb
+= v
.sv_rm
.eq(self
.i
.sv_rm
) # pass through SVP64 ReMap
225 comb
+= v
.is_svp64_mode
.eq(self
.i
.is_svp64_mode
)
226 # only the LDST PowerDecodeSubset *actually* needs to
227 # know to use the alternative decoder. this is all
229 if k
.lower().startswith("ldst"):
230 comb
+= v
.use_svp64_ldst_dec
.eq(
231 self
.i
.use_svp64_ldst_dec
)
233 # ssh, cheat: trap uses the main decoder because of the rewriting
234 self
.des
[self
.trapunit
] = self
.i
.e
.do
236 # connect up Function Units, then read/write ports
237 fu_bitdict
= self
.connect_instruction(m
)
238 self
.connect_rdports(m
, fu_bitdict
)
239 self
.connect_wrports(m
, fu_bitdict
)
243 def connect_instruction(self
, m
):
244 """connect_instruction
246 uses decoded (from PowerOp) function unit information from CSV files
247 to ascertain which Function Unit should deal with the current
250 some (such as OP_ATTN, OP_NOP) are dealt with here, including
251 ignoring it and halting the processor. OP_NOP is a bit annoying
252 because the issuer expects busy flag still to be raised then lowered.
253 (this requires a fake counter to be set).
255 comb
, sync
= m
.d
.comb
, m
.d
.sync
258 # enable-signals for each FU, get one bit for each FU (by name)
259 fu_enable
= Signal(len(fus
), reset_less
=True)
261 for i
, funame
in enumerate(fus
.keys()):
262 fu_bitdict
[funame
] = fu_enable
[i
]
264 # enable the required Function Unit based on the opcode decode
265 # note: this *only* works correctly for simple core when one and
266 # *only* one FU is allocated per instruction
267 for funame
, fu
in fus
.items():
268 fnunit
= fu
.fnunit
.value
269 enable
= Signal(name
="en_%s" % funame
, reset_less
=True)
270 comb
+= enable
.eq((self
.i
.e
.do
.fn_unit
& fnunit
).bool())
271 comb
+= fu_bitdict
[funame
].eq(enable
)
273 # sigh - need a NOP counter
275 with m
.If(counter
!= 0):
276 sync
+= counter
.eq(counter
- 1)
277 comb
+= self
.o
.busy_o
.eq(1)
279 with m
.If(self
.i
.ivalid_i
): # run only when valid
280 with m
.Switch(self
.i
.e
.do
.insn_type
):
281 # check for ATTN: halt if true
282 with m
.Case(MicrOp
.OP_ATTN
):
283 m
.d
.sync
+= self
.o
.core_terminate_o
.eq(1)
285 with m
.Case(MicrOp
.OP_NOP
):
286 sync
+= counter
.eq(2)
287 comb
+= self
.o
.busy_o
.eq(1)
290 # connect up instructions. only one enabled at a time
291 for funame
, fu
in fus
.items():
292 do
= self
.des
[funame
]
293 enable
= fu_bitdict
[funame
]
295 # run this FunctionUnit if enabled
296 # route op, issue, busy, read flags and mask to FU
298 # operand comes from the *local* decoder
299 comb
+= fu
.oper_i
.eq_from(do
)
300 #comb += fu.oper_i.eq_from_execute1(e)
301 comb
+= fu
.issue_i
.eq(self
.i
.issue_i
)
302 comb
+= self
.o
.busy_o
.eq(fu
.busy_o
)
303 # rdmask, which is for registers, needs to come
304 # from the *main* decoder
305 rdmask
= get_rdflags(self
.i
.e
, fu
)
306 comb
+= fu
.rdmaskn
.eq(~rdmask
)
310 def connect_rdport(self
, m
, fu_bitdict
, rdpickers
, regfile
, regname
, fspec
):
311 comb
, sync
= m
.d
.comb
, m
.d
.sync
317 # select the required read port. these are pre-defined sizes
318 rfile
= regs
.rf
[regfile
.lower()]
319 rport
= rfile
.r_ports
[rpidx
]
320 print("read regfile", rpidx
, regfile
, regs
.rf
.keys(),
324 if not isinstance(fspecs
, list):
331 for i
, fspec
in enumerate(fspecs
):
332 # get the regfile specs for this regfile port
333 (rf
, read
, write
, wid
, fuspec
) = fspec
334 print ("fpsec", i
, fspec
, len(fuspec
))
335 ppoffs
.append(pplen
) # record offset for picker
337 name
= "rdflag_%s_%s_%d" % (regfile
, regname
, i
)
338 rdflag
= Signal(name
=name
, reset_less
=True)
339 comb
+= rdflag
.eq(rf
)
340 rdflags
.append(rdflag
)
343 print ("pplen", pplen
)
345 # create a priority picker to manage this port
346 rdpickers
[regfile
][rpidx
] = rdpick
= PriorityPicker(pplen
)
347 setattr(m
.submodules
, "rdpick_%s_%s" % (regfile
, rpidx
), rdpick
)
351 for i
, fspec
in enumerate(fspecs
):
352 (rf
, read
, write
, wid
, fuspec
) = fspec
353 # connect up the FU req/go signals, and the reg-read to the FU
354 # and create a Read Broadcast Bus
355 for pi
, (funame
, fu
, idx
) in enumerate(fuspec
):
358 # connect request-read to picker input, and output to go-rd
359 fu_active
= fu_bitdict
[funame
]
360 name
= "%s_%s_%s_%i" % (regfile
, rpidx
, funame
, pi
)
361 addr_en
= Signal
.like(reads
[i
], name
="addr_en_"+name
)
362 pick
= Signal(name
="pick_"+name
) # picker input
363 rp
= Signal(name
="rp_"+name
) # picker output
364 delay_pick
= Signal(name
="dp_"+name
) # read-enable "underway"
366 # exclude any currently-enabled read-request (mask out active)
367 comb
+= pick
.eq(fu
.rd_rel_o
[idx
] & fu_active
& rdflags
[i
] &
369 comb
+= rdpick
.i
[pi
].eq(pick
)
370 comb
+= fu
.go_rd_i
[idx
].eq(delay_pick
) # pass in *delayed* pick
372 # if picked, select read-port "reg select" number to port
373 comb
+= rp
.eq(rdpick
.o
[pi
] & rdpick
.en_o
)
374 sync
+= delay_pick
.eq(rp
) # delayed "pick"
375 comb
+= addr_en
.eq(Mux(rp
, reads
[i
], 0))
377 # the read-enable happens combinatorially (see mux-bus below)
378 # but it results in the data coming out on a one-cycle delay.
382 addrs
.append(addr_en
)
385 # use the *delayed* pick signal to put requested data onto bus
386 with m
.If(delay_pick
):
387 # connect regfile port to input, creating fan-out Bus
389 print("reg connect widths",
390 regfile
, regname
, pi
, funame
,
391 src
.shape(), rport
.o_data
.shape())
392 # all FUs connect to same port
393 comb
+= src
.eq(rport
.o_data
)
395 # or-reduce the muxed read signals
397 # for unary-addressed
398 comb
+= rport
.ren
.eq(ortreereduce_sig(rens
))
400 # for binary-addressed
401 comb
+= rport
.addr
.eq(ortreereduce_sig(addrs
))
402 comb
+= rport
.ren
.eq(Cat(*rens
).bool())
403 print ("binary", regfile
, rpidx
, rport
, rport
.ren
, rens
, addrs
)
405 def connect_rdports(self
, m
, fu_bitdict
):
406 """connect read ports
408 orders the read regspecs into a dict-of-dicts, by regfile, by
409 regport name, then connects all FUs that want that regport by
410 way of a PriorityPicker.
412 comb
, sync
= m
.d
.comb
, m
.d
.sync
416 # dictionary of lists of regfile read ports
417 byregfiles_rd
, byregfiles_rdspec
= self
.get_byregfiles(True)
419 # okaay, now we need a PriorityPicker per regfile per regfile port
420 # loootta pickers... peter piper picked a pack of pickled peppers...
422 for regfile
, spec
in byregfiles_rd
.items():
423 fuspecs
= byregfiles_rdspec
[regfile
]
424 rdpickers
[regfile
] = {}
426 # argh. an experiment to merge RA and RB in the INT regfile
427 # (we have too many read/write ports)
428 if self
.regreduce_en
:
430 fuspecs
['rabc'] = [fuspecs
.pop('rb')]
431 fuspecs
['rabc'].append(fuspecs
.pop('rc'))
432 fuspecs
['rabc'].append(fuspecs
.pop('ra'))
433 if regfile
== 'FAST':
434 fuspecs
['fast1'] = [fuspecs
.pop('fast1')]
435 if 'fast2' in fuspecs
:
436 fuspecs
['fast1'].append(fuspecs
.pop('fast2'))
437 if 'fast3' in fuspecs
:
438 fuspecs
['fast1'].append(fuspecs
.pop('fast3'))
440 # for each named regfile port, connect up all FUs to that port
441 for (regname
, fspec
) in sort_fuspecs(fuspecs
):
442 print("connect rd", regname
, fspec
)
443 self
.connect_rdport(m
, fu_bitdict
, rdpickers
, regfile
,
446 def connect_wrport(self
, m
, fu_bitdict
, wrpickers
, regfile
, regname
, fspec
):
447 comb
, sync
= m
.d
.comb
, m
.d
.sync
451 print("connect wr", regname
, fspec
)
454 # select the required write port. these are pre-defined sizes
455 print(regfile
, regs
.rf
.keys())
456 rfile
= regs
.rf
[regfile
.lower()]
457 wport
= rfile
.w_ports
[rpidx
]
460 if not isinstance(fspecs
, list):
466 for i
, fspec
in enumerate(fspecs
):
467 # get the regfile specs for this regfile port
468 (rf
, read
, write
, wid
, fuspec
) = fspec
469 print ("fpsec", i
, fspec
, len(fuspec
))
470 ppoffs
.append(pplen
) # record offset for picker
473 # create a priority picker to manage this port
474 wrpickers
[regfile
][rpidx
] = wrpick
= PriorityPicker(pplen
)
475 setattr(m
.submodules
, "wrpick_%s_%s" % (regfile
, rpidx
), wrpick
)
480 for i
, fspec
in enumerate(fspecs
):
481 # connect up the FU req/go signals and the reg-read to the FU
482 # these are arbitrated by Data.ok signals
483 (rf
, read
, write
, wid
, fuspec
) = fspec
484 for pi
, (funame
, fu
, idx
) in enumerate(fuspec
):
487 # write-request comes from dest.ok
488 dest
= fu
.get_out(idx
)
489 fu_dest_latch
= fu
.get_fu_out(idx
) # latched output
490 name
= "wrflag_%s_%s_%d" % (funame
, regname
, idx
)
491 wrflag
= Signal(name
=name
, reset_less
=True)
492 comb
+= wrflag
.eq(dest
.ok
& fu
.busy_o
)
494 # connect request-write to picker input, and output to go-wr
495 fu_active
= fu_bitdict
[funame
]
496 pick
= fu
.wr
.rel_o
[idx
] & fu_active
# & wrflag
497 comb
+= wrpick
.i
[pi
].eq(pick
)
498 # create a single-pulse go write from the picker output
499 wr_pick
= Signal(name
="wpick_%s_%s_%d" % (funame
, regname
, idx
))
500 comb
+= wr_pick
.eq(wrpick
.o
[pi
] & wrpick
.en_o
)
501 comb
+= fu
.go_wr_i
[idx
].eq(rising_edge(m
, wr_pick
))
503 # connect the regspec write "reg select" number to this port
504 # only if one FU actually requests (and is granted) the port
505 # will the write-enable be activated
506 addr_en
= Signal
.like(write
)
508 comb
+= wp
.eq(wr_pick
& wrpick
.en_o
)
509 comb
+= addr_en
.eq(Mux(wp
, write
, 0))
513 addrs
.append(addr_en
)
516 # connect regfile port to input
517 print("reg connect widths",
518 regfile
, regname
, pi
, funame
,
519 dest
.shape(), wport
.i_data
.shape())
520 wsigs
.append(fu_dest_latch
)
522 # here is where we create the Write Broadcast Bus. simple, eh?
523 comb
+= wport
.i_data
.eq(ortreereduce_sig(wsigs
))
525 # for unary-addressed
526 comb
+= wport
.wen
.eq(ortreereduce_sig(wens
))
528 # for binary-addressed
529 comb
+= wport
.addr
.eq(ortreereduce_sig(addrs
))
530 comb
+= wport
.wen
.eq(ortreereduce_sig(wens
))
532 def connect_wrports(self
, m
, fu_bitdict
):
533 """connect write ports
535 orders the write regspecs into a dict-of-dicts, by regfile,
536 by regport name, then connects all FUs that want that regport
537 by way of a PriorityPicker.
539 note that the write-port wen, write-port data, and go_wr_i all need to
540 be on the exact same clock cycle. as there is a combinatorial loop bug
541 at the moment, these all use sync.
543 comb
, sync
= m
.d
.comb
, m
.d
.sync
546 # dictionary of lists of regfile write ports
547 byregfiles_wr
, byregfiles_wrspec
= self
.get_byregfiles(False)
549 # same for write ports.
550 # BLECH! complex code-duplication! BLECH!
552 for regfile
, spec
in byregfiles_wr
.items():
553 fuspecs
= byregfiles_wrspec
[regfile
]
554 wrpickers
[regfile
] = {}
556 if self
.regreduce_en
:
557 # argh, more port-merging
559 fuspecs
['o'] = [fuspecs
.pop('o')]
560 fuspecs
['o'].append(fuspecs
.pop('o1'))
561 if regfile
== 'FAST':
562 fuspecs
['fast1'] = [fuspecs
.pop('fast1')]
563 if 'fast2' in fuspecs
:
564 fuspecs
['fast1'].append(fuspecs
.pop('fast2'))
565 if 'fast3' in fuspecs
:
566 fuspecs
['fast1'].append(fuspecs
.pop('fast3'))
568 for (regname
, fspec
) in sort_fuspecs(fuspecs
):
569 self
.connect_wrport(m
, fu_bitdict
, wrpickers
,
570 regfile
, regname
, fspec
)
572 def get_byregfiles(self
, readmode
):
574 mode
= "read" if readmode
else "write"
577 e
= self
.i
.e
# decoded instruction to execute
579 # dictionary of lists of regfile ports
582 for (funame
, fu
) in fus
.items():
583 print("%s ports for %s" % (mode
, funame
))
584 for idx
in range(fu
.n_src
if readmode
else fu
.n_dst
):
586 (regfile
, regname
, wid
) = fu
.get_in_spec(idx
)
588 (regfile
, regname
, wid
) = fu
.get_out_spec(idx
)
589 print(" %d %s %s %s" % (idx
, regfile
, regname
, str(wid
)))
591 rdflag
, read
= regspec_decode_read(e
, regfile
, regname
)
594 rdflag
, read
= None, None
595 wrport
, write
= regspec_decode_write(e
, regfile
, regname
)
596 if regfile
not in byregfiles
:
597 byregfiles
[regfile
] = {}
598 byregfiles_spec
[regfile
] = {}
599 if regname
not in byregfiles_spec
[regfile
]:
600 byregfiles_spec
[regfile
][regname
] = \
601 (rdflag
, read
, write
, wid
, [])
602 # here we start to create "lanes"
603 if idx
not in byregfiles
[regfile
]:
604 byregfiles
[regfile
][idx
] = []
605 fuspec
= (funame
, fu
, idx
)
606 byregfiles
[regfile
][idx
].append(fuspec
)
607 byregfiles_spec
[regfile
][regname
][4].append(fuspec
)
609 # ok just print that out, for convenience
610 for regfile
, spec
in byregfiles
.items():
611 print("regfile %s ports:" % mode
, regfile
)
612 fuspecs
= byregfiles_spec
[regfile
]
613 for regname
, fspec
in fuspecs
.items():
614 [rdflag
, read
, write
, wid
, fuspec
] = fspec
615 print(" rf %s port %s lane: %s" % (mode
, regfile
, regname
))
616 print(" %s" % regname
, wid
, read
, write
, rdflag
)
617 for (funame
, fu
, idx
) in fuspec
:
618 fusig
= fu
.src_i
[idx
] if readmode
else fu
.dest
[idx
]
619 print(" ", funame
, fu
, idx
, fusig
)
622 return byregfiles
, byregfiles_spec
625 yield from self
.fus
.ports()
626 yield from self
.i
.e
.ports()
627 yield from self
.l0
.ports()
634 if __name__
== '__main__':
635 pspec
= TestMemPspec(ldst_ifacetype
='testpi',
640 dut
= NonProductionCore(pspec
)
641 vl
= rtlil
.convert(dut
, ports
=dut
.ports())
642 with
open("test_core.il", "w") as f
: