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 from nmigen
import Elaboratable
, Module
, Signal
8 from nmigen
.cli
import rtlil
10 from nmutil
.picker
import PriorityPicker
11 from nmutil
.util
import treereduce
13 from soc
.fu
.compunits
.compunits
import AllFunctionUnits
14 from soc
.regfile
.regfiles
import RegFiles
15 from soc
.decoder
.power_decoder
import create_pdecode
16 from soc
.decoder
.power_decoder2
import PowerDecode2
20 def ortreereduce(tree
, attr
="data_o"):
21 return treereduce(tree
, operator
.or_
, lambda x
: getattr(x
, attr
))
24 class NonProductionCore(Elaboratable
):
26 self
.fus
= AllFunctionUnits()
27 self
.regs
= RegFiles()
28 self
.pdecode
= pdecode
= create_pdecode()
29 self
.pdecode2
= PowerDecode2(pdecode
) # instruction decoder
30 self
.ivalid_i
= self
.pdecode2
.e
.valid
# instruction is valid
32 def elaborate(self
, platform
):
36 m
.submodules
.pdecode2
= dec2
= self
.pdecode2
37 m
.submodules
.fus
= self
.fus
38 self
.regs
.elaborate_into(m
, platform
)
42 # enable-signals for each FU, get one bit for each FU (by name)
43 fu_enable
= Signal(len(fus
), reset_less
=True)
45 for i
, funame
in enumerate(fus
.keys()):
46 fu_bitdict
[funame
] = fu_enable
[i
]
48 # connect up instructions
49 for funame
, fu
in fus
.items():
50 fnunit
= fu
.fnunit
.value
51 enable
= Signal(name
="en_%s" % funame
, reset_less
=True)
52 comb
+= enable
.eq(self
.ivalid_i
& (dec2
.e
.fn_unit
& fnunit
).bool())
54 comb
+= fu
.oper_i
.eq_from_execute1(dec2
.e
)
55 comb
+= fu_bitdict
[funame
].eq(enable
)
57 # dictionary of lists of regfile read ports
59 byregfiles_rdspec
= {}
60 for (funame
, fu
) in fus
.items():
61 print ("read ports for %s" % funame
)
62 for idx
in range(fu
.n_src
):
63 (regfile
, regname
, wid
) = fu
.get_in_spec(idx
)
64 print (" %d %s %s %s" % (idx
, regfile
, regname
, str(wid
)))
65 rdflag
, read
, _
= dec2
.regspecmap(regfile
, regname
)
66 if regfile
not in byregfiles_rd
:
67 byregfiles_rd
[regfile
] = {}
68 byregfiles_rdspec
[regfile
] = {}
69 if regname
not in byregfiles_rdspec
[regfile
]:
70 byregfiles_rdspec
[regfile
][regname
] = \
71 [rdflag
, read
, wid
, []]
72 # here we start to create "lanes"
73 if idx
not in byregfiles_rd
[regfile
]:
74 byregfiles_rd
[regfile
][idx
] = []
75 fuspec
= (funame
, fu
, idx
)
76 byregfiles_rd
[regfile
][idx
].append(fuspec
)
77 byregfiles_rdspec
[regfile
][regname
][3].append(fuspec
)
79 # ok just print that out, for convenience
80 for regfile
, spec
in byregfiles_rd
.items():
81 print ("regfile read ports:", regfile
)
82 fuspecs
= byregfiles_rdspec
[regfile
]
83 for regname
, fspec
in fuspecs
.items():
84 [rdflag
, read
, wid
, fuspec
] = fspec
85 print (" regfile read port %s lane: %s" % (regfile
, regname
))
86 print (" %s" % regname
, wid
, read
, rdflag
)
87 for (funame
, fu
, idx
) in fuspec
:
88 print (" ", funame
, fu
, idx
, fu
.src_i
[idx
])
91 # okaay, now we need a PriorityPicker per regfile per regfile port
92 # loootta pickers... peter piper picked a pack of pickled peppers...
94 for regfile
, spec
in byregfiles_rd
.items():
95 fuspecs
= byregfiles_rdspec
[regfile
]
96 rdpickers
[regfile
] = {}
97 for rpidx
, (regname
, fspec
) in enumerate(fuspecs
.items()):
98 # get the regfile specs for this regfile port
99 (rf
, read
, wid
, fuspec
) = fspec
100 name
= "rdflag_%s_%s" % (regfile
, regname
)
101 rdflag
= Signal(name
=name
, reset_less
=True)
102 comb
+= rdflag
.eq(rf
)
104 # "munge" the regfile port index, due to full-port access
105 if regfile
in ['XER', 'CA']:
106 if regname
.startswith('full'):
107 rpidx
= 0 # by convention, first port
109 rpidx
+= 1 # start indexing port 0 from 1
111 # select the required read port. these are pre-defined sizes
112 print (regfile
, regs
.rf
.keys())
113 rport
= regs
.rf
[regfile
.lower()].r_ports
[rpidx
]
115 # create a priority picker to manage this port
116 rdpickers
[regfile
][rpidx
] = rdpick
= PriorityPicker(len(fuspec
))
117 setattr(m
.submodules
, "rdpick_%s_%d" % (regfile
, rpidx
), rdpick
)
119 # connect the regspec "reg select" number to this port
120 with m
.If(rdpick
.en_o
):
121 comb
+= rport
.ren
.eq(read
)
123 # connect up the FU req/go signals and the reg-read to the FU
124 for pi
, (funame
, fu
, idx
) in enumerate(fuspec
):
125 # connect request-read to picker input, and output to go-rd
126 fu_active
= fu_bitdict
[funame
]
127 pick
= fu
.rd_rel_o
[idx
] & fu_active
& rdflag
128 comb
+= rdpick
.i
[pi
].eq(pick
)
129 comb
+= fu
.go_rd_i
[idx
].eq(rdpick
.o
[pi
])
130 # connect regfile port to input
131 print ("reg connect widths",
132 regfile
, regname
, pi
, funame
,
133 fu
.src_i
[idx
].shape(), rport
.data_o
.shape())
134 comb
+= fu
.src_i
[idx
].eq(rport
.data_o
)
139 yield from self
.fus
.ports()
140 yield from self
.pdecode2
.ports()
147 if __name__
== '__main__':
148 dut
= NonProductionCore()
149 vl
= rtlil
.convert(dut
, ports
=dut
.ports())
150 with
open("non_production_core.il", "w") as f
: