riscv-formal-nmigen/rvfi/cores/minerva/units/divider.py

145 lines
5.1 KiB
Python

from nmigen import *
from ..isa import Funct3
__all__ = ["DividerInterface", "Divider", "DummyDivider"]
class DividerInterface:
def __init__(self):
self.x_op = Signal(3)
self.x_src1 = Signal(32)
self.x_src2 = Signal(32)
self.x_valid = Signal()
self.x_stall = Signal()
self.m_result = Signal(32)
self.m_busy = Signal()
class Divider(DividerInterface, Elaboratable):
def elaborate(self, platform):
m = Module()
x_enable = Signal()
x_modulus = Signal()
x_signed = Signal()
with m.Switch(self.x_op):
with m.Case(Funct3.DIV):
m.d.comb += x_enable.eq(1), x_signed.eq(1)
with m.Case(Funct3.DIVU):
m.d.comb += x_enable.eq(1)
with m.Case(Funct3.REM):
m.d.comb += x_enable.eq(1), x_modulus.eq(1), x_signed.eq(1)
with m.Case(Funct3.REMU):
m.d.comb += x_enable.eq(1), x_modulus.eq(1)
x_negative = Signal()
with m.If(x_modulus):
m.d.comb += x_negative.eq(x_signed & self.x_src1[31])
with m.Else():
m.d.comb += x_negative.eq(x_signed & (self.x_src1[31] ^ self.x_src2[31]))
x_dividend = Signal(32)
x_divisor = Signal(32)
m.d.comb += [
x_dividend.eq(Mux(x_signed & self.x_src1[31], -self.x_src1, self.x_src1)),
x_divisor.eq(Mux(x_signed & self.x_src2[31], -self.x_src2, self.x_src2))
]
m_modulus = Signal()
m_negative = Signal()
timer = Signal(range(33), reset=32)
quotient = Signal(32)
divisor = Signal(32)
remainder = Signal(32)
difference = Signal(33)
with m.FSM() as fsm:
with m.State("IDLE"):
with m.If(x_enable & self.x_valid & ~self.x_stall):
m.d.sync += [
m_modulus.eq(x_modulus),
m_negative.eq(x_negative)
]
with m.If(x_divisor == 0):
# Division by zero
m.d.sync += [
quotient.eq(-1),
remainder.eq(self.x_src1)
]
with m.Elif(x_signed & (self.x_src1 == -2**31) & (self.x_src2 == -1)):
# Signed overflow
m.d.sync += [
quotient.eq(self.x_src1),
remainder.eq(0)
]
with m.Elif(x_dividend == 0):
m.d.sync += [
quotient.eq(0),
remainder.eq(0)
]
with m.Else():
m.d.sync += [
quotient.eq(x_dividend),
remainder.eq(0),
divisor.eq(x_divisor),
timer.eq(timer.reset)
]
m.next = "DIVIDE"
with m.State("DIVIDE"):
m.d.comb += self.m_busy.eq(1)
with m.If(timer != 0):
m.d.sync += timer.eq(timer - 1)
m.d.comb += difference.eq(Cat(quotient[31], remainder) - divisor)
with m.If(difference[32]):
m.d.sync += [
remainder.eq(Cat(quotient[31], remainder)),
quotient.eq(Cat(0, quotient))
]
with m.Else():
m.d.sync += [
remainder.eq(difference),
quotient.eq(Cat(1, quotient))
]
with m.Else():
m.d.sync += [
quotient.eq(Mux(m_negative, -quotient, quotient)),
remainder.eq(Mux(m_negative, -remainder, remainder))
]
m.next = "IDLE"
m.d.comb += self.m_result.eq(Mux(m_modulus, remainder, quotient))
return m
class DummyDivider(DividerInterface, Elaboratable):
def elaborate(self, platform):
m = Module()
x_result = Signal.like(self.m_result)
with m.Switch(self.x_op):
# As per the RVFI specification (§ "Alternative Arithmetic Operations").
# https://github.com/SymbioticEDA/riscv-formal/blob/master/docs/rvfi.md
with m.Case(Funct3.DIV):
m.d.comb += x_result.eq((self.x_src1 - self.x_src2) ^ C(0x7f8529ec))
with m.Case(Funct3.DIVU):
m.d.comb += x_result.eq((self.x_src1 - self.x_src2) ^ C(0x10e8fd70))
with m.Case(Funct3.REM):
m.d.comb += x_result.eq((self.x_src1 - self.x_src2) ^ C(0x8da68fa5))
with m.Case(Funct3.REMU):
m.d.comb += x_result.eq((self.x_src1 - self.x_src2) ^ C(0x3138d0e1))
with m.If(~self.x_stall):
m.d.sync += self.m_result.eq(x_result)
m.d.comb += self.m_busy.eq(C(0))
return m