add in fast regs support in decoder and into regspec_decode
[soc.git] / src / soc / fu / regspec.py
1 """RegSpecs
2
3 see https://libre-soc.org/3d_gpu/architecture/regfile/ section on regspecs
4
5 this module is a key strategic module that links pipeline specifications
6 (soc.fu.*.pipe_data and soc.fo.*.pipeline) to MultiCompUnits. MultiCompUnits
7 know absolutely nothing about the data passing through them: all they know
8 is: how many inputs they need to manage, and how many outputs.
9
10 regspecs tell MultiCompUnit what the ordering of the inputs is, how many to
11 create, and how to connect them up to the ALU being "managed" by this CompUnit.
12 likewise for outputs.
13
14 later (TODO) the Register Files will be connected to MultiCompUnits, and,
15 again, the regspecs will say which Regfile (which type) is connected to
16 which MultiCompUnit port, how wide the connection is, and so on.
17
18 """
19 from nmigen import Const
20 from soc.regfile.regfiles import XERRegs, FastRegs
21
22 def get_regspec_bitwidth(regspec, srcdest, idx):
23 print ("get_regspec_bitwidth", regspec, srcdest, idx)
24 bitspec = regspec[srcdest][idx]
25 wid = 0
26 print (bitspec)
27 for ranges in bitspec[2].split(","):
28 ranges = ranges.split(":")
29 print (ranges)
30 if len(ranges) == 1: # only one bit
31 wid += 1
32 else:
33 start, end = map(int, ranges)
34 wid += (end-start)+1
35 return wid
36
37
38 class RegSpec:
39 def __init__(self, rwid, n_src=None, n_dst=None, name=None):
40 self._rwid = rwid
41 if isinstance(rwid, int):
42 # rwid: integer (covers all registers)
43 self._n_src, self._n_dst = n_src, n_dst
44 else:
45 # rwid: a regspec.
46 self._n_src, self._n_dst = len(rwid[0]), len(rwid[1])
47
48 def _get_dstwid(self, i):
49 if isinstance(self._rwid, int):
50 return self._rwid
51 return get_regspec_bitwidth(self._rwid, 1, i)
52
53 def _get_srcwid(self, i):
54 if isinstance(self._rwid, int):
55 return self._rwid
56 return get_regspec_bitwidth(self._rwid, 0, i)
57
58
59 class RegSpecALUAPI:
60 def __init__(self, rwid, alu):
61 """RegSpecAPI
62
63 * :rwid: regspec
64 * :alu: ALU covered by this regspec
65 """
66 self.rwid = rwid
67 self.alu = alu # actual ALU - set as a "submodule" of the CU
68
69 def get_in_name(self, i):
70 return self.rwid[0][i][1]
71
72 def get_out_name(self, i):
73 return self.rwid[1][i][1]
74
75 def get_out(self, i):
76 if isinstance(self.rwid, int): # old - testing - API (rwid is int)
77 return self.alu.out[i]
78 # regspec-based API: look up variable through regspec thru row number
79 return getattr(self.alu.n.data_o, self.get_out_name(i))
80
81 def get_in(self, i):
82 if isinstance(self.rwid, int): # old - testing - API (rwid is int)
83 return self.alu.i[i]
84 # regspec-based API: look up variable through regspec thru row number
85 return getattr(self.alu.p.data_i, self.get_in_name(i))
86
87 def get_op(self):
88 if isinstance(self.rwid, int): # old - testing - API (rwid is int)
89 return self.alu.op
90 return self.alu.p.data_i.ctx.op
91
92
93 # function for the relationship between regspecs and Decode2Execute1Type
94 def regspec_decode(e, regfile, name):
95 """regspec_decode
96
97 this function encodes the understanding (relationship) between
98 Regfiles, Computation Units, and the Power ISA Decoder (PowerDecoder2).
99
100 based on the regspec, which contains the register file name and register
101 name, return a tuple of:
102
103 * how the decoder should determine whether the Function Unit needs
104 a Regport or not
105 * which Regfile port should be read to get that data
106 * when it comes to writing: likewise, which Regfile port should be written
107
108 Note that some of the port numbering encoding is *unary*. in the case
109 of "Full Condition Register", it's a full 8-bit mask of read/write-enables.
110 This actually matches directly with the XFX field in MTCR, and at
111 some point that 8-bit mask from the instruction could actually be passed directly through to full_cr (TODO).
112
113 For the INT and CR numbering, these are expressed in binary in the
114 instruction (note however that XFX in MTCR is unary-masked!)
115
116 XER is implicitly-encoded based on whether the operation has carry or
117 overflow.
118
119 FAST regfile is, again, implicitly encoded, back in PowerDecode2, based
120 on the type of operation (see DecodeB for an example).
121
122 The SPR regfile on the other hand is *binary*-encoded, and, furthermore,
123 has to be "remapped".
124 """
125
126 if regfile == 'INT':
127 # Int register numbering is *unary* encoded
128 if name == 'ra': # RA
129 return e.read_reg1.ok, 1<<e.read_reg1.data, None
130 if name == 'rb': # RB
131 return e.read_reg2.ok, 1<<e.read_reg2.data, None
132 if name == 'rc': # RS
133 return e.read_reg3.ok, 1<<e.read_reg3.data, None
134 if name == 'o': # RT
135 return e.write_reg.ok, None, 1<<e.write_reg.data
136 if name == 'o1': # RA (update mode: LD/ST EA)
137 return e.write_ea.ok, None, 1<<e.write_ea.data
138
139 if regfile == 'CR':
140 # CRRegs register numbering is *unary* encoded
141 if name == 'full_cr': # full CR
142 return e.read_cr_whole, 0b11111111, 0b11111111
143 if name == 'cr_a': # CR A
144 return e.read_cr1.ok, 1<<e.read_cr1.data, 1<<e.write_cr.data
145 if name == 'cr_b': # CR B
146 return e.read_cr2.ok, 1<<e.read_cr2.data, None
147 if name == 'cr_c': # CR C
148 return e.read_cr3.ok, 1<<e.read_cr2.data, None
149
150 if regfile == 'XER':
151 # XERRegs register numbering is *unary* encoded
152 SO = 1<<XERRegs.SO
153 CA = 1<<XERRegs.CA
154 OV = 1<<XERRegs.OV
155 if name == 'xer_so':
156 return e.oe.oe & e.oe.oe_ok, SO, SO
157 if name == 'xer_ov':
158 return e.oe.oe & e.oe.oe_ok, OV, OV
159 if name == 'xer_ca':
160 return e.input_carry, CA, CA
161
162 if regfile == 'FAST':
163 # FAST register numbering is *unary* encoded
164 PC = 1<<FastRegs.PC
165 MSR = 1<<FastRegs.MSR
166 CTR = 1<<FastRegs.CTR
167 LR = 1<<FastRegs.LR
168 TAR = 1<<FastRegs.TAR
169 SRR1 = 1<<FastRegs.SRR1
170 SRR2 = 1<<FastRegs.SRR2
171 if name in ['cia', 'nia']:
172 return Const(1), PC, PC # TODO: detect read-conditions
173 if name == 'msr':
174 return Const(1), MSR, MS # TODO: detect read-conditions
175 # TODO: remap the SPR numbers to FAST regs
176 if name == 'spr1':
177 return e.read_spr1.ok, 1<<e.read_spr1.data, 1<<e.write_fast1.data
178 if name == 'spr2':
179 return e.read_spr2.ok, 1<<e.read_spr2.data, 1<<e.write_fast2.data
180
181 assert False, "regspec not found %s %d" % (repr(regspec), idx)