add minerva source from https://github.com/lambdaconcept/minerva
[soc.git] / src / soc / minerva / units / divider.py
1 from nmigen import *
2
3 from ..isa import Funct3
4
5
6 __all__ = ["DividerInterface", "Divider", "DummyDivider"]
7
8
9 class DividerInterface:
10 def __init__(self):
11 self.x_op = Signal(3)
12 self.x_src1 = Signal(32)
13 self.x_src2 = Signal(32)
14 self.x_valid = Signal()
15 self.x_stall = Signal()
16
17 self.m_result = Signal(32)
18 self.m_busy = Signal()
19
20
21 class Divider(DividerInterface, Elaboratable):
22 def elaborate(self, platform):
23 m = Module()
24
25 x_enable = Signal()
26 x_modulus = Signal()
27 x_signed = Signal()
28
29 with m.Switch(self.x_op):
30 with m.Case(Funct3.DIV):
31 m.d.comb += x_enable.eq(1), x_signed.eq(1)
32 with m.Case(Funct3.DIVU):
33 m.d.comb += x_enable.eq(1)
34 with m.Case(Funct3.REM):
35 m.d.comb += x_enable.eq(1), x_modulus.eq(1), x_signed.eq(1)
36 with m.Case(Funct3.REMU):
37 m.d.comb += x_enable.eq(1), x_modulus.eq(1)
38
39 x_negative = Signal()
40 with m.If(x_modulus):
41 m.d.comb += x_negative.eq(x_signed & self.x_src1[31])
42 with m.Else():
43 m.d.comb += x_negative.eq(x_signed & (self.x_src1[31] ^ self.x_src2[31]))
44
45 x_dividend = Signal(32)
46 x_divisor = Signal(32)
47 m.d.comb += [
48 x_dividend.eq(Mux(x_signed & self.x_src1[31], -self.x_src1, self.x_src1)),
49 x_divisor.eq(Mux(x_signed & self.x_src2[31], -self.x_src2, self.x_src2))
50 ]
51
52 m_modulus = Signal()
53 m_negative = Signal()
54
55 timer = Signal(range(33), reset=32)
56 quotient = Signal(32)
57 divisor = Signal(32)
58 remainder = Signal(32)
59 difference = Signal(33)
60
61 with m.FSM() as fsm:
62 with m.State("IDLE"):
63 with m.If(x_enable & self.x_valid & ~self.x_stall):
64 m.d.sync += [
65 m_modulus.eq(x_modulus),
66 m_negative.eq(x_negative)
67 ]
68 with m.If(x_divisor == 0):
69 # Division by zero
70 m.d.sync += [
71 quotient.eq(-1),
72 remainder.eq(self.x_src1)
73 ]
74 with m.Elif(x_signed & (self.x_src1 == -2**31) & (self.x_src2 == -1)):
75 # Signed overflow
76 m.d.sync += [
77 quotient.eq(self.x_src1),
78 remainder.eq(0)
79 ]
80 with m.Elif(x_dividend == 0):
81 m.d.sync += [
82 quotient.eq(0),
83 remainder.eq(0)
84 ]
85 with m.Else():
86 m.d.sync += [
87 quotient.eq(x_dividend),
88 remainder.eq(0),
89 divisor.eq(x_divisor),
90 timer.eq(timer.reset)
91 ]
92 m.next = "DIVIDE"
93
94 with m.State("DIVIDE"):
95 m.d.comb += self.m_busy.eq(1)
96 with m.If(timer != 0):
97 m.d.sync += timer.eq(timer - 1)
98 m.d.comb += difference.eq(Cat(quotient[31], remainder) - divisor)
99 with m.If(difference[32]):
100 m.d.sync += [
101 remainder.eq(Cat(quotient[31], remainder)),
102 quotient.eq(Cat(0, quotient))
103 ]
104 with m.Else():
105 m.d.sync += [
106 remainder.eq(difference),
107 quotient.eq(Cat(1, quotient))
108 ]
109 with m.Else():
110 m.d.sync += [
111 quotient.eq(Mux(m_negative, -quotient, quotient)),
112 remainder.eq(Mux(m_negative, -remainder, remainder))
113 ]
114 m.next = "IDLE"
115
116 m.d.comb += self.m_result.eq(Mux(m_modulus, remainder, quotient))
117
118 return m
119
120
121 class DummyDivider(DividerInterface, Elaboratable):
122 def elaborate(self, platform):
123 m = Module()
124
125 x_result = Signal.like(self.m_result)
126
127 with m.Switch(self.x_op):
128 # As per the RVFI specification (ยง "Alternative Arithmetic Operations").
129 # https://github.com/SymbioticEDA/riscv-formal/blob/master/docs/rvfi.md
130 with m.Case(Funct3.DIV):
131 m.d.comb += x_result.eq((self.x_src1 - self.x_src2) ^ C(0x7f8529ec))
132 with m.Case(Funct3.DIVU):
133 m.d.comb += x_result.eq((self.x_src1 - self.x_src2) ^ C(0x10e8fd70))
134 with m.Case(Funct3.REM):
135 m.d.comb += x_result.eq((self.x_src1 - self.x_src2) ^ C(0x8da68fa5))
136 with m.Case(Funct3.REMU):
137 m.d.comb += x_result.eq((self.x_src1 - self.x_src2) ^ C(0x3138d0e1))
138
139 with m.If(~self.x_stall):
140 m.d.sync += self.m_result.eq(x_result)
141
142 m.d.comb += self.m_busy.eq(C(0))
143
144 return m