1 # Proof of correctness for trap pipeline, main stage
6 * https://bugs.libre-soc.org/show_bug.cgi?id=421
7 * https://libre-soc.org/openpower/isa/fixedtrap/
8 * https://libre-soc.org/openpower/isa/sprset/
9 * https://libre-soc.org/openpower/isa/system/
15 from nmigen
import Cat
, Const
, Elaboratable
, Module
, Signal
, signed
16 from nmigen
.asserts
import Assert
, AnyConst
17 from nmigen
.cli
import rtlil
19 from nmutil
.extend
import exts
20 from nmutil
.formaltest
import FHDLTestCase
22 from soc
.consts
import MSR
, MSRb
, PI
, TT
, field
24 from soc
.decoder
.power_enums
import MicrOp
26 from soc
.fu
.trap
.main_stage
import TrapMainStage
27 from soc
.fu
.trap
.pipe_data
import TrapPipeSpec
28 from soc
.fu
.trap
.trap_input_record
import CompTrapOpSubset
31 class Driver(Elaboratable
):
35 def elaborate(self
, platform
):
39 rec
= CompTrapOpSubset()
40 pspec
= TrapPipeSpec(id_wid
=2)
42 m
.submodules
.dut
= dut
= TrapMainStage(pspec
)
44 # frequently used aliases
46 msr_o
, msr_i
= dut
.o
.msr
, op
.msr
47 srr0_o
, srr0_i
= dut
.o
.srr0
, dut
.i
.srr0
48 srr1_o
, srr1_i
= dut
.o
.srr1
, dut
.i
.srr1
53 d_fields
= dut
.fields
.FormD
54 sc_fields
= dut
.fields
.FormSC
57 with m
.Switch(op
.insn_type
):
60 # TDI/TWI/TD/TW. v3.0B p90-91
62 with m
.Case(MicrOp
.OP_TRAP
):
63 to
= Signal(len(d_fields
.TO
))
64 comb
+= to
.eq(d_fields
.TO
[0:-1])
68 comb
+= a_i
.eq(dut
.i
.a
)
69 comb
+= b_i
.eq(dut
.i
.b
)
71 a_s
= Signal(signed(64), reset_less
=True)
72 b_s
= Signal(signed(64), reset_less
=True)
73 a
= Signal(64, reset_less
=True)
74 b
= Signal(64, reset_less
=True)
76 with m
.If(op
.is_32bit
):
77 comb
+= a_s
.eq(exts(a_i
, 32, 64))
78 comb
+= b_s
.eq(exts(b_i
, 32, 64))
79 comb
+= a
.eq(a_i
[0:32])
80 comb
+= b
.eq(b_i
[0:32])
87 lt_s
= Signal(reset_less
=True)
88 gt_s
= Signal(reset_less
=True)
89 lt_u
= Signal(reset_less
=True)
90 gt_u
= Signal(reset_less
=True)
91 equal
= Signal(reset_less
=True)
93 comb
+= lt_s
.eq(a_s
< b_s
)
94 comb
+= gt_s
.eq(a_s
> b_s
)
95 comb
+= lt_u
.eq(a
< b
)
96 comb
+= gt_u
.eq(a
> b
)
97 comb
+= equal
.eq(a
== b
)
99 trapbits
= Signal(5, reset_less
=True)
100 comb
+= trapbits
.eq(Cat(gt_u
, lt_u
, equal
, gt_s
, lt_s
))
103 traptype
= op
.traptype
104 comb
+= take_trap
.eq(traptype
.any() |
(trapbits
& to
).any())
106 with m
.If(take_trap
):
107 expected_msr
= Signal(len(msr_o
.data
))
108 comb
+= expected_msr
.eq(op
.msr
)
110 comb
+= field(expected_msr
, MSRb
.IR
).eq(0)
111 comb
+= field(expected_msr
, MSRb
.DR
).eq(0)
112 comb
+= field(expected_msr
, MSRb
.FE0
).eq(0)
113 comb
+= field(expected_msr
, MSRb
.FE1
).eq(0)
114 comb
+= field(expected_msr
, MSRb
.EE
).eq(0)
115 comb
+= field(expected_msr
, MSRb
.RI
).eq(0)
116 comb
+= field(expected_msr
, MSRb
.SF
).eq(1)
117 comb
+= field(expected_msr
, MSRb
.TM
).eq(0)
118 comb
+= field(expected_msr
, MSRb
.VEC
).eq(0)
119 comb
+= field(expected_msr
, MSRb
.VSX
).eq(0)
120 comb
+= field(expected_msr
, MSRb
.PR
).eq(0)
121 comb
+= field(expected_msr
, MSRb
.FP
).eq(0)
122 comb
+= field(expected_msr
, MSRb
.PMM
).eq(0)
125 # see https://bugs.libre-soc.org/show_bug.cgi?id=325#c120
126 comb
+= field(expected_msr
, MSRb
.TEs
, MSRb
.TEe
).eq(0)
128 comb
+= field(expected_msr
, MSRb
.UND
).eq(0)
129 comb
+= field(expected_msr
, MSRb
.LE
).eq(1)
131 expected_srr1
= Signal(len(srr1_o
.data
))
132 comb
+= expected_srr1
.eq(op
.msr
)
134 # note here: 36 is ***LESS*** than 32 ***BUT***
135 # ***63-36*** is less than 63-32
136 # could do with using field_slice here however
137 # *get the number order right*.
139 # however before doing that: why are these bits
140 # initialised to zero then every single one of them
141 # is over-ridden? 5 bits, 32-36 (36-32, haha)
142 # are set to zero, then 5 bits are set to expressions.
144 # redundant comb += expected_srr1[63-36:63-32].eq(0)
146 comb
+= expected_srr1
[PI
.TRAP
].eq(traptype
== 0)
147 comb
+= expected_srr1
[PI
.PRIV
].eq(traptype
[1])
148 comb
+= expected_srr1
[PI
.FP
].eq(traptype
[0])
149 comb
+= expected_srr1
[PI
.ADR
].eq(traptype
[3])
150 comb
+= expected_srr1
[PI
.ILLEG
].eq(traptype
[4])
151 comb
+= expected_srr1
[PI
.TM_BAD_THING
].eq(0)
155 Assert(msr_o
.data
== expected_msr
),
157 Assert(srr0_o
.data
== op
.cia
),
159 Assert(srr1_o
.data
== expected_srr1
),
161 Assert(nia_o
.data
== op
.trapaddr
<< 4),
167 with m
.Case(MicrOp
.OP_SC
):
168 expected_msr
= Signal(len(msr_o
.data
))
169 comb
+= expected_msr
.eq(op
.msr
)
170 # Unless otherwise documented, these exceptions to the MSR bits
171 # are documented in Power ISA V3.0B, page 1063 or 1064.
172 # We are not supporting hypervisor or transactional semantics,
173 # so we skip enforcing those fields' properties.
174 comb
+= field(expected_msr
, MSRb
.IR
).eq(0)
175 comb
+= field(expected_msr
, MSRb
.DR
).eq(0)
176 comb
+= field(expected_msr
, MSRb
.FE0
).eq(0)
177 comb
+= field(expected_msr
, MSRb
.FE1
).eq(0)
178 comb
+= field(expected_msr
, MSRb
.EE
).eq(0)
179 comb
+= field(expected_msr
, MSRb
.RI
).eq(0)
180 comb
+= field(expected_msr
, MSRb
.SF
).eq(1)
181 comb
+= field(expected_msr
, MSRb
.TM
).eq(0)
182 comb
+= field(expected_msr
, MSRb
.VEC
).eq(0)
183 comb
+= field(expected_msr
, MSRb
.VSX
).eq(0)
184 comb
+= field(expected_msr
, MSRb
.PR
).eq(0)
185 comb
+= field(expected_msr
, MSRb
.FP
).eq(0)
186 comb
+= field(expected_msr
, MSRb
.PMM
).eq(0)
187 # XXX no. slice quantity still inverted producing an empty list
188 # https://bugs.libre-soc.org/show_bug.cgi?id=325#c120
189 # also add a comment explaining this very non-obvious
191 comb
+= field(expected_msr
, MSRb
.TEs
, MSRb
.TEe
).eq(0)
192 comb
+= field(expected_msr
, MSRb
.UND
).eq(0)
193 comb
+= field(expected_msr
, MSRb
.LE
).eq(1)
196 Assert(dut
.o
.srr0
.ok
),
200 Assert(dut
.o
.srr0
.data
== (op
.cia
+ 4)[0:64]),
201 Assert(field(srr1_o
, 33, 36) == 0),
202 Assert(field(srr1_o
, 42, 47) == 0),
203 Assert(field(srr1_o
, 0, 32) == field(msr_i
, 0, 32)),
204 Assert(field(srr1_o
, 37, 41) == field(msr_i
, 37, 41)),
205 Assert(field(srr1_o
, 48, 63) == field(msr_i
, 48, 63)),
207 Assert(msr_o
.data
== expected_msr
),
213 with m
.Case(MicrOp
.OP_RFID
):
219 # XXX code comment has been removed, which explains
220 # why the code is written the way it is written
221 # see https://bugs.libre-soc.org/show_bug.cgi?id=325#c127
223 # XXX restore HV check
224 # https://bugs.libre-soc.org/show_bug.cgi?id=325#c125
226 # if (MSR[29:31] != 0b010) | (SRR1[29:31] != 0b000) then
227 # MSR[29:31] <- SRR1[29:31]
228 with m
.If((field(msr_i
, 29, 31) != 0b010) |
229 (field(srr1_i
, 29, 31) != 0b000)):
230 comb
+= Assert(field(msr_o
.data
, 29, 31) ==
231 field(srr1_i
, 29, 31))
233 comb
+= Assert(field(msr_o
.data
, 29, 31) ==
234 field(msr_i
, 29, 31))
236 # check EE (48) IR (58), DR (59): PR (49) will over-ride
238 # XXX does not look as clear. revert
239 # see https://bugs.libre-soc.org/show_bug.cgi?id=325#c122
240 for bit
in [48, 58, 59]:
243 (field(srr1_i
, bit
) |
field(srr1_i
, 49))
246 # remaining bits: straight copy. don't know what these are:
247 # just trust the v3.0B spec is correct.
249 Assert(field(msr_o
, 0, 2) == field(srr1_i
, 0, 2)),
250 Assert(field(msr_o
, 4, 28) == field(srr1_i
, 4, 28)),
251 Assert(field(msr_o
, 32) == field(srr1_i
, 32)),
252 Assert(field(msr_o
, 37, 41) == field(srr1_i
, 37, 41)),
253 Assert(field(msr_o
, 49, 50) == field(srr1_i
, 49, 50)),
254 Assert(field(msr_o
, 52, 57) == field(srr1_i
, 52, 57)),
255 Assert(field(msr_o
, 60, 63) == field(srr1_i
, 60, 63)),
258 # check NIA against SRR0. 2 LSBs are set to zero (word-align)
259 comb
+= Assert(nia_o
.data
== Cat(Const(0, 2), dut
.i
.srr0
[2:]))
261 comb
+= dut
.i
.ctx
.matches(dut
.o
.ctx
)
266 class TrapMainStageTestCase(FHDLTestCase
):
267 def test_formal(self
):
268 self
.assertFormal(Driver(), mode
="bmc", depth
=10)
269 self
.assertFormal(Driver(), mode
="cover", depth
=10)
271 def test_ilang(self
):
272 vl
= rtlil
.convert(Driver(), ports
=[])
273 with
open("trap_main_stage.il", "w") as f
:
277 if __name__
== '__main__':