1 # This is the proof for the computation unit/Function Unit/ALU
2 # manager. Description here:
3 # https://libre-soc.org/3d_gpu/architecture/compunit/
5 # This attempts to prove most of the bullet points on that page
8 from nmigen
import (Module
, Signal
, Elaboratable
, Mux
, Cat
, Repl
,
10 from nmigen
.asserts
import (Assert
, AnyConst
, Assume
, Cover
, Initial
,
11 Rose
, Fell
, Stable
, Past
)
12 from nmigen
.test
.utils
import FHDLTestCase
13 from nmigen
.cli
import rtlil
16 from soc
.fu
.compunits
.compunits
import FunctionUnitBaseSingle
17 from soc
.experiment
.alu_hier
import DummyALU
18 from soc
.experiment
.compalu_multi
import MultiCompUnit
19 from soc
.fu
.alu
.alu_input_record
import CompALUOpSubset
21 class Driver(Elaboratable
):
25 def elaborate(self
, platform
):
30 m
.submodules
.dut
= dut
= MultiCompUnit(16, alu
,
43 shadow
= dut
.shadown_i
49 has_issued
= Signal(reset
=0)
54 comb
+= Assume(has_issued
== 0)
55 comb
+= Assume(issue
== 0)
56 comb
+= Assume(go_rd
== 0)
57 comb
+= Assume(rst
== 1)
59 comb
+= Assume(rst
== 0)
61 # detect when issue has been raised and remember it
63 sync
+= has_issued
.eq(1)
64 comb
+= Cover(has_issued
)
66 # Property 1: after an issue, busy should be raised
67 with m
.If(Past(issue
)):
70 # Property 2: After a wr_rel and go_wr, busy should be lowered
71 with m
.If(Past(wr_rel
) & Past(go_wr
)):
72 # Shadow interferes with this and I'm not sure what is
74 with m
.If(~
Past(shadow
)):
75 comb
+= Assert(busy
== 0)
76 with m
.Elif(Past(busy
) == 1):
77 comb
+= Assert(busy
== 1)
79 # Property 3: Rd_rel should never be asserted before issue
81 # If issue has never been raised, then rd_rel should never
83 with m
.If(rd_rel
!= 0):
84 comb
+= Assert(has_issued
)
86 # Property 4: when rd_rel is asserted, it should stay
87 # that way until a go_rd
88 with m
.If((Past(go_rd
) == 0) & ~
Past(go_die
)):
89 comb
+= Assert(~
Fell(rd_rel
))
91 # Property 5: when a bit in rd_rel is asserted, and
92 # the corresponding bit in go_rd is asserted, then that
93 # bit of rd_rel should be deasserted
95 with m
.If(Past(go_rd
)[i
] & (Past(rd_rel
) != 0)):
96 comb
+= Assert(rd_rel
[i
] == ~
Past(go_rd
)[i
])
98 # Property 6: Similarly, if rd_rel is asserted,
99 # asserting go_die should make rd_rel be deasserted
101 with m
.If(Past(rd_rel
) != 0):
102 with m
.If(Past(go_die
)):
103 comb
+= Assert(rd_rel
== 0)
105 comb
+= Cover(Fell(rd_rel
))
107 # Property 7: Similar to property 3, wr_rel should
108 # never be asserted unless there was a preceeding issue
110 with m
.If(wr_rel
!= 0):
111 comb
+= Assert(has_issued
)
113 # Property 8: Similar to property 4, wr_rel should stay
114 # asserted until a go_rd, go_die, or shadow
116 with m
.If((Past(go_wr
) == 0) & ~
Past(go_die
, 2) &
118 comb
+= Assert(~
Fell(wr_rel
))
119 # Assume go_wr is not asserted unless wr_rel is
120 with m
.If(wr_rel
== 0):
121 comb
+= Assume(go_wr
== 0)
124 # Property 9: Similar to property 5, when wr_rel is
125 # asserted and go_wr is asserted, then wr_rel should be
127 with m
.If(Past(wr_rel
) & Past(go_wr
)):
128 comb
+= Assert(wr_rel
== 0)
131 # Property 10: Similar to property 6, wr_rel should be
132 # deasserted when go_die is asserted
133 with m
.If(Past(wr_rel
) & Past(go_die
)):
134 comb
+= Assert(wr_rel
== 0)
136 # Property 11: wr_rel should not fall while shadow is
138 with m
.If(wr_rel
& shadow
):
139 comb
+= Assert(~
Fell(wr_rel
))
141 # Assume no instruction is issued until rd_rel is
142 # released. Idk if this is valid
145 comb
+= Assume(issue
== 0)
149 class FUTestCase(FHDLTestCase
):
150 def test_formal(self
):
152 self
.assertFormal(module
, mode
="bmc", depth
=5)
153 self
.assertFormal(module
, mode
="cover", depth
=5)
154 def test_ilang(self
):
155 dut
= MultiCompUnit(16, DummyALU(16), CompALUOpSubset
)
156 vl
= rtlil
.convert(dut
, ports
=dut
.ports())
157 with
open("multicompunit.il", "w") as f
:
161 if __name__
== '__main__':