f9dc2dc16b232001d3a0ad3c0d029715ee1c8654
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
95 self
.sv_a_nz
.eq(i
.sv_a_nz
)
96 self
.state
.eq(i
.state
)
97 self
.raw_insn_i
.eq(i
.raw_insn_i
)
98 self
.bigendian_i
.eq(i
.bigendian_i
)
101 self
.sv_rm
.eq(i
.sv_rm
)
102 self
.is_svp64_mode
.eq(i
.is_svp64_mode
)
103 self
.use_svp64_ldst_dec
.eq(i
.use_svp64_ldst_dec
)
104 self
.sv_pred_sm
.eq(i
.sv_pred_sm
)
105 self
.sv_pred_dm
.eq(i
.sv_pred_dm
)
110 # start/stop and terminated signalling
111 self
.core_terminate_o
= Signal(reset
=0) # indicates stopped
112 self
.exc_happened
= Signal() # exception happened
115 self
.core_terminate_o
.eq(i
.core_terminate_o
)
116 self
.exc_happened
.eq(i
.exc_happened
)
119 # derive from ControlBase rather than have a separate Stage instance,
120 # this is simpler to do
121 class NonProductionCore(ControlBase
):
122 def __init__(self
, pspec
):
125 # test is SVP64 is to be enabled
126 self
.svp64_en
= hasattr(pspec
, "svp64") and (pspec
.svp64
== True)
128 # test to see if regfile ports should be reduced
129 self
.regreduce_en
= (hasattr(pspec
, "regreduce") and
130 (pspec
.regreduce
== True))
132 super().__init
__(stage
=self
)
134 # single LD/ST funnel for memory access
135 self
.l0
= l0
= TstL0CacheBuffer(pspec
, n_units
=1)
138 # function units (only one each)
139 # only include mmu if enabled in pspec
140 self
.fus
= AllFunctionUnits(pspec
, pilist
=[pi
])
142 # link LoadStore1 into MMU
143 mmu
= self
.fus
.get_fu('mmu0')
144 print ("core pspec", pspec
.ldst_ifacetype
)
145 print ("core mmu", mmu
)
146 print ("core lsmem.lsi", l0
.cmpi
.lsmem
.lsi
)
148 mmu
.alu
.set_ldst_interface(l0
.cmpi
.lsmem
.lsi
)
150 # register files (yes plural)
151 self
.regs
= RegFiles(pspec
)
153 # set up input and output: unusual requirement to set data directly
154 # (due to the way that the core is set up in a different domain,
155 # see TestIssuer.setup_peripherals
156 self
.i
, self
.o
= self
.new_specs(None)
157 self
.i
, self
.o
= self
.p
.i_data
, self
.n
.o_data
159 # create per-FU instruction decoders (subsetted)
163 for funame
, fu
in self
.fus
.fus
.items():
164 f_name
= fu
.fnunit
.name
165 fnunit
= fu
.fnunit
.value
166 opkls
= fu
.opsubsetkls
168 # TRAP decoder is the *main* decoder
169 self
.trapunit
= funame
171 self
.decoders
[funame
] = PowerDecodeSubset(None, opkls
, f_name
,
174 svp64_en
=self
.svp64_en
,
175 regreduce_en
=self
.regreduce_en
)
176 self
.des
[funame
] = self
.decoders
[funame
].do
178 if "mmu0" in self
.decoders
:
179 self
.decoders
["mmu0"].mmu0_spr_dec
= self
.decoders
["spr0"]
181 def setup(self
, m
, i
):
185 return CoreInput(self
.pspec
, self
.svp64_en
, self
.regreduce_en
)
190 def elaborate(self
, platform
):
191 m
= super().elaborate(platform
)
193 # for testing purposes, to cut down on build time in coriolis2
194 if hasattr(self
.pspec
, "nocore") and self
.pspec
.nocore
== True:
195 x
= Signal() # dummy signal
200 m
.submodules
.fus
= self
.fus
201 m
.submodules
.l0
= l0
= self
.l0
202 self
.regs
.elaborate_into(m
, platform
)
207 for k
, v
in self
.decoders
.items():
208 # connect each satellite decoder and give it the instruction.
209 # as subset decoders this massively reduces wire fanout given
210 # the large number of ALUs
211 setattr(m
.submodules
, "dec_%s" % v
.fn_name
, v
)
212 comb
+= v
.dec
.raw_opcode_in
.eq(self
.i
.raw_insn_i
)
213 comb
+= v
.dec
.bigendian
.eq(self
.i
.bigendian_i
)
214 # sigh due to SVP64 RA_OR_ZERO detection connect these too
215 comb
+= v
.sv_a_nz
.eq(self
.i
.sv_a_nz
)
217 comb
+= v
.pred_sm
.eq(self
.i
.sv_pred_sm
)
218 comb
+= v
.pred_dm
.eq(self
.i
.sv_pred_dm
)
219 if k
!= self
.trapunit
:
220 comb
+= v
.sv_rm
.eq(self
.i
.sv_rm
) # pass through SVP64 ReMap
221 comb
+= v
.is_svp64_mode
.eq(self
.i
.is_svp64_mode
)
222 # only the LDST PowerDecodeSubset *actually* needs to
223 # know to use the alternative decoder. this is all
225 if k
.lower().startswith("ldst"):
226 comb
+= v
.use_svp64_ldst_dec
.eq(
227 self
.i
.use_svp64_ldst_dec
)
229 # ssh, cheat: trap uses the main decoder because of the rewriting
230 self
.des
[self
.trapunit
] = self
.i
.e
.do
232 # connect up Function Units, then read/write ports
233 fu_bitdict
= self
.connect_instruction(m
)
234 self
.connect_rdports(m
, fu_bitdict
)
235 self
.connect_wrports(m
, fu_bitdict
)
237 # note if an exception happened. in a pipelined or OoO design
238 # this needs to be accompanied by "shadowing" (or stalling)
240 for exc
in self
.fus
.excs
.values():
241 el
.append(exc
.happened
)
242 if len(el
) > 0: # at least one exception
243 comb
+= self
.o
.exc_happened
.eq(Cat(*el
).bool())
247 def connect_instruction(self
, m
):
248 """connect_instruction
250 uses decoded (from PowerOp) function unit information from CSV files
251 to ascertain which Function Unit should deal with the current
254 some (such as OP_ATTN, OP_NOP) are dealt with here, including
255 ignoring it and halting the processor. OP_NOP is a bit annoying
256 because the issuer expects busy flag still to be raised then lowered.
257 (this requires a fake counter to be set).
259 comb
, sync
= m
.d
.comb
, m
.d
.sync
262 # indicate if core is busy
263 busy_o
= Signal(name
="corebusy_o", reset_less
=True)
265 # enable-signals for each FU, get one bit for each FU (by name)
266 fu_enable
= Signal(len(fus
), reset_less
=True)
268 for i
, funame
in enumerate(fus
.keys()):
269 fu_bitdict
[funame
] = fu_enable
[i
]
271 # enable the required Function Unit based on the opcode decode
272 # note: this *only* works correctly for simple core when one and
273 # *only* one FU is allocated per instruction. what is actually
274 # required is one PriorityPicker per group of matching fnunits,
275 # and for only one actual FU to be "picked". this basically means
276 # when ReservationStations are enabled it will be possible to
277 # monitor multiple outstanding processing properly.
278 for funame
, fu
in fus
.items():
279 fnunit
= fu
.fnunit
.value
280 enable
= Signal(name
="en_%s" % funame
, reset_less
=True)
281 comb
+= enable
.eq((self
.i
.e
.do
.fn_unit
& fnunit
).bool())
282 comb
+= fu_bitdict
[funame
].eq(enable
)
284 # sigh - need a NOP counter
286 with m
.If(counter
!= 0):
287 sync
+= counter
.eq(counter
- 1)
290 with m
.If(self
.p
.i_valid
): # run only when valid
291 with m
.Switch(self
.i
.e
.do
.insn_type
):
292 # check for ATTN: halt if true
293 with m
.Case(MicrOp
.OP_ATTN
):
294 m
.d
.sync
+= self
.o
.core_terminate_o
.eq(1)
296 # fake NOP - this isn't really used (Issuer detects NOP)
297 with m
.Case(MicrOp
.OP_NOP
):
298 sync
+= counter
.eq(2)
302 # connect up instructions. only one enabled at a time
303 for funame
, fu
in fus
.items():
304 do
= self
.des
[funame
]
305 enable
= fu_bitdict
[funame
]
307 # run this FunctionUnit if enabled
308 # route op, issue, busy, read flags and mask to FU
310 # operand comes from the *local* decoder
311 comb
+= fu
.oper_i
.eq_from(do
)
312 comb
+= fu
.issue_i
.eq(1) # issue when input valid
313 comb
+= busy_o
.eq(fu
.busy_o
)
314 # rdmask, which is for registers, needs to come
315 # from the *main* decoder
316 rdmask
= get_rdflags(self
.i
.e
, fu
)
317 comb
+= fu
.rdmaskn
.eq(~rdmask
)
319 # if instruction is busy, set busy output for core. also
320 # continue to hold each fu rdmask
321 for funame
, fu
in fus
.items():
322 with m
.If(fu
.busy_o
):
323 comb
+= busy_o
.eq(fu
.busy_o
)
324 # rdmask, which is for registers, needs to come
325 # from the *main* decoder
326 rdmask
= get_rdflags(self
.i
.e
, fu
)
327 comb
+= fu
.rdmaskn
.eq(~rdmask
)
329 # set ready/valid signalling. if busy, means refuse incoming issue
330 # XXX note: for an in-order core this is far too simple. busy must
331 # be gated with the *availability* of the incoming (requested)
332 # instruction, where Core must be prepared to store-and-hold
333 # an instruction if no FU is available.
334 comb
+= self
.p
.o_ready
.eq(~busy_o
)
338 def connect_rdport(self
, m
, fu_bitdict
, rdpickers
, regfile
, regname
, fspec
):
339 comb
, sync
= m
.d
.comb
, m
.d
.sync
345 # select the required read port. these are pre-defined sizes
346 rfile
= regs
.rf
[regfile
.lower()]
347 rport
= rfile
.r_ports
[rpidx
]
348 print("read regfile", rpidx
, regfile
, regs
.rf
.keys(),
352 if not isinstance(fspecs
, list):
359 for i
, fspec
in enumerate(fspecs
):
360 # get the regfile specs for this regfile port
361 (rf
, read
, write
, wid
, fuspec
) = fspec
362 print ("fpsec", i
, fspec
, len(fuspec
))
363 ppoffs
.append(pplen
) # record offset for picker
365 name
= "rdflag_%s_%s_%d" % (regfile
, regname
, i
)
366 rdflag
= Signal(name
=name
, reset_less
=True)
367 comb
+= rdflag
.eq(rf
)
368 rdflags
.append(rdflag
)
371 print ("pplen", pplen
)
373 # create a priority picker to manage this port
374 rdpickers
[regfile
][rpidx
] = rdpick
= PriorityPicker(pplen
)
375 setattr(m
.submodules
, "rdpick_%s_%s" % (regfile
, rpidx
), rdpick
)
379 for i
, fspec
in enumerate(fspecs
):
380 (rf
, read
, write
, wid
, fuspec
) = fspec
381 # connect up the FU req/go signals, and the reg-read to the FU
382 # and create a Read Broadcast Bus
383 for pi
, (funame
, fu
, idx
) in enumerate(fuspec
):
386 # connect request-read to picker input, and output to go-rd
387 fu_active
= fu_bitdict
[funame
]
388 name
= "%s_%s_%s_%i" % (regfile
, rpidx
, funame
, pi
)
389 addr_en
= Signal
.like(reads
[i
], name
="addr_en_"+name
)
390 pick
= Signal(name
="pick_"+name
) # picker input
391 rp
= Signal(name
="rp_"+name
) # picker output
392 delay_pick
= Signal(name
="dp_"+name
) # read-enable "underway"
394 # exclude any currently-enabled read-request (mask out active)
395 comb
+= pick
.eq(fu
.rd_rel_o
[idx
] & fu_active
& rdflags
[i
] &
397 comb
+= rdpick
.i
[pi
].eq(pick
)
398 comb
+= fu
.go_rd_i
[idx
].eq(delay_pick
) # pass in *delayed* pick
400 # if picked, select read-port "reg select" number to port
401 comb
+= rp
.eq(rdpick
.o
[pi
] & rdpick
.en_o
)
402 sync
+= delay_pick
.eq(rp
) # delayed "pick"
403 comb
+= addr_en
.eq(Mux(rp
, reads
[i
], 0))
405 # the read-enable happens combinatorially (see mux-bus below)
406 # but it results in the data coming out on a one-cycle delay.
410 addrs
.append(addr_en
)
413 # use the *delayed* pick signal to put requested data onto bus
414 with m
.If(delay_pick
):
415 # connect regfile port to input, creating fan-out Bus
417 print("reg connect widths",
418 regfile
, regname
, pi
, funame
,
419 src
.shape(), rport
.o_data
.shape())
420 # all FUs connect to same port
421 comb
+= src
.eq(rport
.o_data
)
423 # or-reduce the muxed read signals
425 # for unary-addressed
426 comb
+= rport
.ren
.eq(ortreereduce_sig(rens
))
428 # for binary-addressed
429 comb
+= rport
.addr
.eq(ortreereduce_sig(addrs
))
430 comb
+= rport
.ren
.eq(Cat(*rens
).bool())
431 print ("binary", regfile
, rpidx
, rport
, rport
.ren
, rens
, addrs
)
433 def connect_rdports(self
, m
, fu_bitdict
):
434 """connect read ports
436 orders the read regspecs into a dict-of-dicts, by regfile, by
437 regport name, then connects all FUs that want that regport by
438 way of a PriorityPicker.
440 comb
, sync
= m
.d
.comb
, m
.d
.sync
444 # dictionary of lists of regfile read ports
445 byregfiles_rd
, byregfiles_rdspec
= self
.get_byregfiles(True)
447 # okaay, now we need a PriorityPicker per regfile per regfile port
448 # loootta pickers... peter piper picked a pack of pickled peppers...
450 for regfile
, spec
in byregfiles_rd
.items():
451 fuspecs
= byregfiles_rdspec
[regfile
]
452 rdpickers
[regfile
] = {}
454 # argh. an experiment to merge RA and RB in the INT regfile
455 # (we have too many read/write ports)
456 if self
.regreduce_en
:
458 fuspecs
['rabc'] = [fuspecs
.pop('rb')]
459 fuspecs
['rabc'].append(fuspecs
.pop('rc'))
460 fuspecs
['rabc'].append(fuspecs
.pop('ra'))
461 if regfile
== 'FAST':
462 fuspecs
['fast1'] = [fuspecs
.pop('fast1')]
463 if 'fast2' in fuspecs
:
464 fuspecs
['fast1'].append(fuspecs
.pop('fast2'))
465 if 'fast3' in fuspecs
:
466 fuspecs
['fast1'].append(fuspecs
.pop('fast3'))
468 # for each named regfile port, connect up all FUs to that port
469 for (regname
, fspec
) in sort_fuspecs(fuspecs
):
470 print("connect rd", regname
, fspec
)
471 self
.connect_rdport(m
, fu_bitdict
, rdpickers
, regfile
,
474 def connect_wrport(self
, m
, fu_bitdict
, wrpickers
, regfile
, regname
, fspec
):
475 comb
, sync
= m
.d
.comb
, m
.d
.sync
479 print("connect wr", regname
, fspec
)
482 # select the required write port. these are pre-defined sizes
483 print(regfile
, regs
.rf
.keys())
484 rfile
= regs
.rf
[regfile
.lower()]
485 wport
= rfile
.w_ports
[rpidx
]
488 if not isinstance(fspecs
, list):
494 for i
, fspec
in enumerate(fspecs
):
495 # get the regfile specs for this regfile port
496 (rf
, read
, write
, wid
, fuspec
) = fspec
497 print ("fpsec", i
, fspec
, len(fuspec
))
498 ppoffs
.append(pplen
) # record offset for picker
501 # create a priority picker to manage this port
502 wrpickers
[regfile
][rpidx
] = wrpick
= PriorityPicker(pplen
)
503 setattr(m
.submodules
, "wrpick_%s_%s" % (regfile
, rpidx
), wrpick
)
508 for i
, fspec
in enumerate(fspecs
):
509 # connect up the FU req/go signals and the reg-read to the FU
510 # these are arbitrated by Data.ok signals
511 (rf
, read
, write
, wid
, fuspec
) = fspec
512 for pi
, (funame
, fu
, idx
) in enumerate(fuspec
):
515 # write-request comes from dest.ok
516 dest
= fu
.get_out(idx
)
517 fu_dest_latch
= fu
.get_fu_out(idx
) # latched output
518 name
= "wrflag_%s_%s_%d" % (funame
, regname
, idx
)
519 wrflag
= Signal(name
=name
, reset_less
=True)
520 comb
+= wrflag
.eq(dest
.ok
& fu
.busy_o
)
522 # connect request-write to picker input, and output to go-wr
523 fu_active
= fu_bitdict
[funame
]
524 pick
= fu
.wr
.rel_o
[idx
] & fu_active
# & wrflag
525 comb
+= wrpick
.i
[pi
].eq(pick
)
526 # create a single-pulse go write from the picker output
527 wr_pick
= Signal(name
="wpick_%s_%s_%d" % (funame
, regname
, idx
))
528 comb
+= wr_pick
.eq(wrpick
.o
[pi
] & wrpick
.en_o
)
529 comb
+= fu
.go_wr_i
[idx
].eq(rising_edge(m
, wr_pick
))
531 # connect the regspec write "reg select" number to this port
532 # only if one FU actually requests (and is granted) the port
533 # will the write-enable be activated
534 addr_en
= Signal
.like(write
)
536 comb
+= wp
.eq(wr_pick
& wrpick
.en_o
)
537 comb
+= addr_en
.eq(Mux(wp
, write
, 0))
541 addrs
.append(addr_en
)
544 # connect regfile port to input
545 print("reg connect widths",
546 regfile
, regname
, pi
, funame
,
547 dest
.shape(), wport
.i_data
.shape())
548 wsigs
.append(fu_dest_latch
)
550 # here is where we create the Write Broadcast Bus. simple, eh?
551 comb
+= wport
.i_data
.eq(ortreereduce_sig(wsigs
))
553 # for unary-addressed
554 comb
+= wport
.wen
.eq(ortreereduce_sig(wens
))
556 # for binary-addressed
557 comb
+= wport
.addr
.eq(ortreereduce_sig(addrs
))
558 comb
+= wport
.wen
.eq(ortreereduce_sig(wens
))
560 def connect_wrports(self
, m
, fu_bitdict
):
561 """connect write ports
563 orders the write regspecs into a dict-of-dicts, by regfile,
564 by regport name, then connects all FUs that want that regport
565 by way of a PriorityPicker.
567 note that the write-port wen, write-port data, and go_wr_i all need to
568 be on the exact same clock cycle. as there is a combinatorial loop bug
569 at the moment, these all use sync.
571 comb
, sync
= m
.d
.comb
, m
.d
.sync
574 # dictionary of lists of regfile write ports
575 byregfiles_wr
, byregfiles_wrspec
= self
.get_byregfiles(False)
577 # same for write ports.
578 # BLECH! complex code-duplication! BLECH!
580 for regfile
, spec
in byregfiles_wr
.items():
581 fuspecs
= byregfiles_wrspec
[regfile
]
582 wrpickers
[regfile
] = {}
584 if self
.regreduce_en
:
585 # argh, more port-merging
587 fuspecs
['o'] = [fuspecs
.pop('o')]
588 fuspecs
['o'].append(fuspecs
.pop('o1'))
589 if regfile
== 'FAST':
590 fuspecs
['fast1'] = [fuspecs
.pop('fast1')]
591 if 'fast2' in fuspecs
:
592 fuspecs
['fast1'].append(fuspecs
.pop('fast2'))
593 if 'fast3' in fuspecs
:
594 fuspecs
['fast1'].append(fuspecs
.pop('fast3'))
596 for (regname
, fspec
) in sort_fuspecs(fuspecs
):
597 self
.connect_wrport(m
, fu_bitdict
, wrpickers
,
598 regfile
, regname
, fspec
)
600 def get_byregfiles(self
, readmode
):
602 mode
= "read" if readmode
else "write"
605 e
= self
.i
.e
# decoded instruction to execute
607 # dictionary of lists of regfile ports
610 for (funame
, fu
) in fus
.items():
611 print("%s ports for %s" % (mode
, funame
))
612 for idx
in range(fu
.n_src
if readmode
else fu
.n_dst
):
614 (regfile
, regname
, wid
) = fu
.get_in_spec(idx
)
616 (regfile
, regname
, wid
) = fu
.get_out_spec(idx
)
617 print(" %d %s %s %s" % (idx
, regfile
, regname
, str(wid
)))
619 rdflag
, read
= regspec_decode_read(e
, regfile
, regname
)
622 rdflag
, read
= None, None
623 wrport
, write
= regspec_decode_write(e
, regfile
, regname
)
624 if regfile
not in byregfiles
:
625 byregfiles
[regfile
] = {}
626 byregfiles_spec
[regfile
] = {}
627 if regname
not in byregfiles_spec
[regfile
]:
628 byregfiles_spec
[regfile
][regname
] = \
629 (rdflag
, read
, write
, wid
, [])
630 # here we start to create "lanes"
631 if idx
not in byregfiles
[regfile
]:
632 byregfiles
[regfile
][idx
] = []
633 fuspec
= (funame
, fu
, idx
)
634 byregfiles
[regfile
][idx
].append(fuspec
)
635 byregfiles_spec
[regfile
][regname
][4].append(fuspec
)
637 # ok just print that out, for convenience
638 for regfile
, spec
in byregfiles
.items():
639 print("regfile %s ports:" % mode
, regfile
)
640 fuspecs
= byregfiles_spec
[regfile
]
641 for regname
, fspec
in fuspecs
.items():
642 [rdflag
, read
, write
, wid
, fuspec
] = fspec
643 print(" rf %s port %s lane: %s" % (mode
, regfile
, regname
))
644 print(" %s" % regname
, wid
, read
, write
, rdflag
)
645 for (funame
, fu
, idx
) in fuspec
:
646 fusig
= fu
.src_i
[idx
] if readmode
else fu
.dest
[idx
]
647 print(" ", funame
, fu
, idx
, fusig
)
650 return byregfiles
, byregfiles_spec
653 yield from self
.fus
.ports()
654 yield from self
.i
.e
.ports()
655 yield from self
.l0
.ports()
662 if __name__
== '__main__':
663 pspec
= TestMemPspec(ldst_ifacetype
='testpi',
668 dut
= NonProductionCore(pspec
)
669 vl
= rtlil
.convert(dut
, ports
=dut
.ports())
670 with
open("test_core.il", "w") as f
: