1 # Proof of correctness for FSGNJ module
2 # Copyright (C) 2020 Michael Nolan <mtnolan2640@gmail.com>
4 from nmigen
import Module
, Signal
, Elaboratable
5 from nmigen
.asserts
import Assert
, Assume
6 from nmigen
.cli
import rtlil
8 from ieee754
.fsgnj
.fsgnj
import FSGNJPipeMod
9 from ieee754
.pipeline
import PipelineSpec
13 # This defines a module to drive the device under test and assert
14 # properties about its outputs
15 class FSGNJDriver(Elaboratable
):
16 def __init__(self
, pspec
):
19 self
.a
= Signal(pspec
.width
)
20 self
.b
= Signal(pspec
.width
)
21 self
.z
= Signal(pspec
.width
)
22 self
.opc
= Signal(pspec
.op_wid
)
23 self
.muxid
= Signal(pspec
.id_wid
)
25 def elaborate(self
, platform
):
28 m
.submodules
.dut
= dut
= FSGNJPipeMod(self
.pspec
)
30 # connect up the inputs and outputs. I think these could
31 # theoretically be $anyconst/$anysync but I'm not sure nmigen
32 # has support for that
33 m
.d
.comb
+= dut
.i
.a
.eq(self
.a
)
34 m
.d
.comb
+= dut
.i
.b
.eq(self
.b
)
35 m
.d
.comb
+= dut
.i
.ctx
.op
.eq(self
.opc
)
36 m
.d
.comb
+= dut
.i
.muxid
.eq(self
.muxid
)
37 m
.d
.comb
+= self
.z
.eq(dut
.o
.z
)
39 # Since the RISCV spec doesn't define what FSGNJ with a funct3
40 # field of 0b011 throug 0b111 does, they should be ignored.
41 m
.d
.comb
+= Assume(self
.opc
!= 0b11)
43 # The RISCV spec (page 70) says FSGNJ "produces a result that
44 # takes all buts except the sign bit from [operand 1]". This
45 # asserts that that holds true
46 m
.d
.comb
+= Assert(self
.z
[0:31] == self
.a
[0:31])
48 with m
.Switch(self
.opc
):
50 # The RISCV Spec (page 70) states that for FSGNJ (opcode
51 # 0b00 in this case) "the result's sign bit is [operand
54 m
.d
.comb
+= Assert(self
.z
[-1] == self
.b
[-1])
56 # The RISCV Spec (page 70) states that for FSGNJN (opcode
57 # 0b01 in this case) "the result's sign bit is the opposite
58 # of [operand 2's] sign bit"
60 m
.d
.comb
+= Assert(self
.z
[-1] == ~self
.b
[-1])
61 # The RISCV Spec (page 70) states that for FSGNJX (opcode
62 # 0b10 in this case) "the result's sign bit is the XOR of
63 # the sign bits of [operand 1] and [operand 2]"
65 m
.d
.comb
+= Assert(self
.z
[-1] == (self
.a
[-1] ^ self
.b
[-1]))
70 return [self
.a
, self
.b
, self
.z
, self
.opc
, self
.muxid
]
74 m
= FSGNJDriver(PipelineSpec(32, 2, 2))
76 il
= rtlil
.convert(m
, ports
=m
.ports())
77 with
open("proof.il", "w") as f
:
79 p
= subprocess
.Popen(['sby', '-f', 'proof.sby'],
80 stdout
=subprocess
.PIPE
,
81 stderr
=subprocess
.PIPE
)
83 out
, err
= p
.communicate()
84 print("Proof successful!")
85 print(out
.decode('utf-8'))
88 out
, err
= p
.communicate()
89 print(out
.decode('utf-8'))
90 print(err
.decode('utf-8'))
93 if __name__
== "__main__":