#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from hwt.code import If, Switch, Concat, In, And, replicate
from hwt.code_utils import rename_signal
from hwt.hdl.types.bits import HBits
from hwt.hdl.types.defs import BIT
from hwt.hwIOs.std import HwIOSignal, HwIOClk
from hwt.hwModule import HwModule
from hwt.hwParam import HwParam
from hwt.pyUtils.typingFuture import override
from hwt.serializer.mode import serializeExclude
from hwtLib.xilinx.primitive.dsp48e1_constants import LOGIC_MODES_DRC_deassign_xyz_mux_if_PREG_eq_1, \
LOGIC_MODES_DRC_deassign_xyz_mux, ARITHMETIC_MODES_DRC_deassign_xyz_mux, \
ARITHMETIC_MODES_DRC_deassign_xyz_mux_if_PREG_eq_1, CARRYIN_SEL
from pyMathBitPrecise.bit_utils import mask
[docs]
@serializeExclude
class DSP48E1(HwModule):
"""
DSP hardblock in Xilinx 7 series (2x pre adder, multiplier, ALU)
:see: https://www.xilinx.com/support/documentation/user_guides/ug479_7Series_DSP48E1.pdf
.. figure:: ./_static/xilinx_DSP48E1_basic.png
.. hwt-autodoc::
"""
@override
def hwConfig(self):
self.ACASCREG = HwParam(1)
self.ADREG = HwParam(1)
self.ALUMODEREG = HwParam(1)
self.AREG = HwParam(1)
self.AUTORESET_PATDET = HwParam("NO_RESET")
self.A_INPUT = HwParam("DIRECT")
self.BCASCREG = HwParam(1)
self.BREG = HwParam(1)
self.B_INPUT = HwParam("DIRECT")
self.CARRYINREG = HwParam(1)
self.CARRYINSELREG = HwParam(1)
self.CREG = HwParam(1)
self.DREG = HwParam(1)
self.INMODEREG = HwParam(1)
self.IS_ALUMODE_INVERTED = HwParam(HBits(4).from_py(0b0000))
self.IS_CARRYIN_INVERTED = HwParam(BIT.from_py(0b0))
self.IS_CLK_INVERTED = HwParam(BIT.from_py(0b0))
self.IS_INMODE_INVERTED = HwParam(HBits(5).from_py(0b00000))
self.IS_OPMODE_INVERTED = HwParam(HBits(7).from_py(0b0000000))
self.MASK = HwParam(HBits(48).from_py(0x3fffffffffff))
self.MREG = HwParam(1)
self.OPMODEREG = HwParam(1)
self.PATTERN = HwParam(HBits(48).from_py(0x000000000000))
self.PREG = HwParam(1)
self.SEL_MASK = HwParam("MASK")
self.SEL_PATTERN = HwParam("PATTERN")
self.USE_DPORT = HwParam("FALSE")
self.USE_MULT = HwParam("MULTIPLY")
self.USE_PATTERN_DETECT = HwParam("NO_PATDET")
self.USE_SIMD = HwParam("ONE48")
[docs]
def deassign_xyz_mux(self):
return [
self.opmode_valid_flag(1),
self.invalid_opmode(1)
]
[docs]
def display_invalid_opmode(self):
return [
self.opmode_valid_flag(0),
self.invalid_opmode(0),
# print("OPMODE Input Warning : The OPMODE %b requires attribute PREG set to 1.", qopmode_o_mux, sim.now // 1000.000000)
]
@override
def hwDeclr(self):
self.CLK = HwIOClk()
# inputs
self.A = HwIOSignal(HBits(30))
self.B = HwIOSignal(HBits(18))
self.C = HwIOSignal(HBits(48))
self.D = HwIOSignal(HBits(25))
# selects the operands for main ALU
# [2:0] X
# [4:2] Y
# [7:4] Z
self.OPMODE = HwIOSignal(HBits(7))
# :ivar ALUMODE: selects the operation performed by main ALU
self.ALUMODE = HwIOSignal(HBits(4))
self.CECARRYIN = HwIOSignal()
self.CARRYINSEL = HwIOSignal(HBits(3))
# :ivar INMODE: Select the functionality of the pre-adder, the A,
# B, and D inputs, and the input registers. These bits should default to
# 5’b00000 if left unconnected. These are optionally invertible,
# providing routing flexibility.
self.INMODE = HwIOSignal(HBits(5))
self.CARRYIN = HwIOSignal()
# main outputs
self.OVERFLOW = HwIOSignal()._m()
self.P = HwIOSignal(HBits(48))._m()
self.PATTERNBDETECT = HwIOSignal()._m()
self.PATTERNDETECT = HwIOSignal()._m()
self.UNDERFLOW = HwIOSignal()._m()
self.CARRYOUT = HwIOSignal(HBits(4))._m()
# clock enable for internal registers
self.CEA1 = HwIOSignal()
self.CEA2 = HwIOSignal()
self.CEAD = HwIOSignal()
self.CEB1 = HwIOSignal()
self.CEB2 = HwIOSignal()
self.CEC = HwIOSignal()
self.CED = HwIOSignal()
self.CEM = HwIOSignal()
self.CEP = HwIOSignal()
self.CEALUMODE = HwIOSignal()
self.CECTRL = HwIOSignal()
self.CEINMODE = HwIOSignal()
# reset for internal registers
self.RSTA = HwIOSignal()
self.RSTALLCARRYIN = HwIOSignal()
self.RSTALUMODE = HwIOSignal()
self.RSTB = HwIOSignal()
self.RSTC = HwIOSignal()
self.RSTCTRL = HwIOSignal()
self.RSTD = HwIOSignal()
self.RSTINMODE = HwIOSignal()
self.RSTM = HwIOSignal()
self.RSTP = HwIOSignal()
# Column ports are used to connect the DSP blocks in the column
# and they have an equivalent port for fabric (e.g. A and ACIN).
self.ACIN = HwIOSignal(HBits(30))
self.ACOUT = HwIOSignal(HBits(30))._m()
self.BCIN = HwIOSignal(HBits(18))
self.BCOUT = HwIOSignal(HBits(18))._m()
# cary in/out for main ALU
self.CARRYCASCIN = HwIOSignal()
self.CARRYCASCOUT = HwIOSignal()._m()
self.PCIN = HwIOSignal(HBits(48))
self.PCOUT = HwIOSignal(HBits(48))._m()
# Sign of the multiplied result from the previous DSP48E1 slice for MACC extension.
self.MULTSIGNIN = HwIOSignal()
self.MULTSIGNOUT = HwIOSignal()._m()
self.input_check()
@override
def hwImpl(self):
# internal signals
ACASCREG, ADREG, ALUMODEREG, AREG, AUTORESET_PATDET, A_INPUT, BCASCREG, BREG, B_INPUT, CARRYINREG, CARRYINSELREG, \
CREG, DREG, INMODEREG, IS_ALUMODE_INVERTED, IS_CARRYIN_INVERTED, IS_CLK_INVERTED, IS_INMODE_INVERTED, IS_OPMODE_INVERTED, MASK, MREG, \
OPMODEREG, PATTERN, PREG, SEL_MASK, SEL_PATTERN, USE_DPORT, USE_MULT, USE_PATTERN_DETECT, USE_SIMD, ACOUT, \
BCOUT, CARRYCASCOUT, CARRYOUT, MULTSIGNOUT, OVERFLOW, P, PATTERNBDETECT, PATTERNDETECT, PCOUT, UNDERFLOW, \
A, ACIN, ALUMODE, B, BCIN, C, CARRYCASCIN, CARRYIN, CARRYINSEL, CEA1, \
CEA2, CEAD, CEALUMODE, CEB1, CEB2, CEC, CECARRYIN, CECTRL, CED, CEINMODE, \
CEM, CEP, CLK, D, INMODE, MULTSIGNIN, OPMODE, PCIN, RSTA, RSTALLCARRYIN, \
RSTALUMODE, RSTB, RSTC, RSTCTRL, RSTD, RSTINMODE, RSTM, RSTP = \
self.ACASCREG, self.ADREG, self.ALUMODEREG, self.AREG, self.AUTORESET_PATDET, self.A_INPUT, self.BCASCREG, self.BREG, self.B_INPUT, self.CARRYINREG, self.CARRYINSELREG, \
self.CREG, self.DREG, self.INMODEREG, self.IS_ALUMODE_INVERTED, self.IS_CARRYIN_INVERTED, self.IS_CLK_INVERTED, self.IS_INMODE_INVERTED, self.IS_OPMODE_INVERTED, self.MASK, self.MREG, \
self.OPMODEREG, self.PATTERN, self.PREG, self.SEL_MASK, self.SEL_PATTERN, self.USE_DPORT, self.USE_MULT, self.USE_PATTERN_DETECT, self.USE_SIMD, self.ACOUT, \
self.BCOUT, self.CARRYCASCOUT, self.CARRYOUT, self.MULTSIGNOUT, self.OVERFLOW, self.P, self.PATTERNBDETECT, self.PATTERNDETECT, self.PCOUT, self.UNDERFLOW, \
self.A, self.ACIN, self.ALUMODE, self.B, self.BCIN, self.C, self.CARRYCASCIN, self.CARRYIN, self.CARRYINSEL, self.CEA1, \
self.CEA2, self.CEAD, self.CEALUMODE, self.CEB1, self.CEB2, self.CEC, self.CECARRYIN, self.CECTRL, self.CED, self.CEINMODE, \
self.CEM, self.CEP, self.CLK, self.D, self.INMODE, self.MULTSIGNIN, self.OPMODE, self.PCIN, self.RSTA, self.RSTALLCARRYIN, \
self.RSTALUMODE, self.RSTB, self.RSTC, self.RSTCTRL, self.RSTD, self.RSTINMODE, self.RSTM, self.RSTP
#------------------- constants -------------------------
CARRYOUT_W = 4
A_W = 30
ALUMODE_W = 4
A_MULT_W = 25
B_W = 18
B_MULT_W = 18
D_W = 25
INMODE_W = 5
OPMODE_W = 7
ALU_FULL_W = 48
IS_ALUMODE_INVERTED_BIN = self._sig("IS_ALUMODE_INVERTED_BIN", HBits(4), def_val=IS_ALUMODE_INVERTED)
IS_CARRYIN_INVERTED_BIN = self._sig("IS_CARRYIN_INVERTED_BIN", def_val=IS_CARRYIN_INVERTED)
IS_CLK_INVERTED_BIN = self._sig("IS_CLK_INVERTED_BIN", def_val=IS_CLK_INVERTED)
IS_INMODE_INVERTED_BIN = self._sig("IS_INMODE_INVERTED_BIN", HBits(5), def_val=IS_INMODE_INVERTED)
IS_OPMODE_INVERTED_BIN = self._sig("IS_OPMODE_INVERTED_BIN", HBits(7), def_val=IS_OPMODE_INVERTED)
a_o_mux = self._sig("a_o_mux", HBits(30))
qa_o_mux = self._sig("qa_o_mux", HBits(30))
qa_o_reg1 = self._sig("qa_o_reg1", HBits(30))
qa_o_reg2 = self._sig("qa_o_reg2", HBits(30))
qacout_o_mux = self._sig("qacout_o_mux", HBits(30))
# new
qinmode_o_mux = self._sig("qinmode_o_mux", HBits(5))
qinmode_o_reg = self._sig("qinmode_o_reg", HBits(5))
# new
a_preaddsub = self._sig("a_preaddsub", HBits(25))
b_o_mux = self._sig("b_o_mux", HBits(18))
qb_o_mux = self._sig("qb_o_mux", HBits(18))
qb_o_reg1 = self._sig("qb_o_reg1", HBits(18))
qb_o_reg2 = self._sig("qb_o_reg2", HBits(18))
qbcout_o_mux = self._sig("qbcout_o_mux", HBits(18))
qcarryinsel_o_mux = self._sig("qcarryinsel_o_mux", HBits(3))
qcarryinsel_o_reg1 = self._sig("qcarryinsel_o_reg1", HBits(3))
# new
#d_o_mux = self._sig("d_o_mux", HBits(D_W))
qd_o_mux = self._sig("qd_o_mux", HBits(D_W))
qd_o_reg1 = self._sig("qd_o_reg1", HBits(D_W))
qmult_o_mux = self._sig("qmult_o_mux", HBits(A_MULT_W + B_MULT_W))
qmult_o_reg = self._sig("qmult_o_reg", HBits(A_MULT_W + B_MULT_W))
# 42:0
qc_o_mux = self._sig("qc_o_mux", HBits(48))
qc_o_reg1 = self._sig("qc_o_reg1", HBits(48))
qp_o_mux = self._sig("qp_o_mux", HBits(48))
qp_o_reg1 = self._sig("qp_o_reg1", HBits(48))
qx_o_mux = self._sig("qx_o_mux", HBits(48))
qy_o_mux = self._sig("qy_o_mux", HBits(48))
qz_o_mux = self._sig("qz_o_mux", HBits(48))
qopmode_o_mux = self._sig("qopmode_o_mux", HBits(7))
qopmode_o_reg1 = self._sig("qopmode_o_reg1", HBits(7))
qcarryin_o_mux0 = self._sig("qcarryin_o_mux0")
qcarryin_o_reg0 = self._sig("qcarryin_o_reg0")
qcarryin_o_mux7 = self._sig("qcarryin_o_mux7")
qcarryin_o_reg7 = self._sig("qcarryin_o_reg7")
qcarryin_o_mux = self._sig("qcarryin_o_mux")
qalumode_o_mux = self._sig("qalumode_o_mux", HBits(4))
qalumode_o_reg1 = self._sig("qalumode_o_reg1", HBits(4))
self.invalid_opmode = self._sig("invalid_opmode", def_val=1)
self.opmode_valid_flag = opmode_valid_flag = self._sig("opmode_valid_flag", def_val=1)
# reg [47:0] alu_o;
alu_o = self._sig("alu_o", HBits(48))
qmultsignout_o_reg = self._sig("qmultsignout_o_reg")
multsignout_o_mux = self._sig("multsignout_o_mux")
multsignout_o_opmode = self._sig("multsignout_o_opmode")
pdet_o_mux = self._sig("pdet_o_mux")
pdetb_o_mux = self._sig("pdetb_o_mux")
the_pattern = self._sig("the_pattern", HBits(48))
the_mask = self._sig("the_mask", HBits(48), def_val=0)
carrycascout_o = self._sig("carrycascout_o")
the_auto_reset_patdet = self._sig("the_auto_reset_patdet")
carrycascout_o_reg = self._sig("carrycascout_o_reg", def_val=0)
carrycascout_o_mux = self._sig("carrycascout_o_mux", def_val=0)
# CR 588861
carryout_o_reg = self._sig("carryout_o_reg", HBits(4), def_val=0)
carryout_o_mux = self._sig("carryout_o_mux", HBits(4))
carryout_x_o = self._sig("carryout_x_o", HBits(4))
pdet_o = self._sig("pdet_o")
pdetb_o = self._sig("pdetb_o")
pdet_o_reg1 = self._sig("pdet_o_reg1")
pdet_o_reg2 = self._sig("pdet_o_reg2")
pdetb_o_reg1 = self._sig("pdetb_o_reg1")
pdetb_o_reg2 = self._sig("pdetb_o_reg2")
overflow_o = self._sig("overflow_o")
underflow_o = self._sig("underflow_o")
mult_o = self._sig("mult_o", HBits(A_MULT_W + B_MULT_W))
# reg [(MSB_A_MULT+MSB_B_MULT+1):0] mult_o; // 42:0
# new
ad_addsub = self._sig("ad_addsub", HBits(A_MULT_W))
ad_mult = self._sig("ad_mult", HBits(A_MULT_W))
qad_o_reg1 = self._sig("qad_o_reg1", HBits(A_MULT_W))
qad_o_mux = self._sig("qad_o_mux", HBits(A_MULT_W))
b_mult = self._sig("b_mult", HBits(B_MULT_W))
# cci_drc_msg = self._sig("cci_drc_msg", def_val=0b0)
# cis_drc_msg = self._sig("cis_drc_msg", def_val=0b0)
opmode_in = self._sig("opmode_in", HBits(OPMODE_W))
alumode_in = self._sig("alumode_in", HBits(ALUMODE_W))
carryin_in = self._sig("carryin_in")
clk_in = self._sig("clk_in")
inmode_in = self._sig("inmode_in", HBits(INMODE_W))
#*** Y mux
# 08-06-08
# IR 478378
y_mac_cascd = rename_signal(self, qopmode_o_mux[7:4]._eq(0b100)._ternary(replicate(48, MULTSIGNIN), HBits(48).from_py(mask(48))), "y_mac_cascd")
#--####################################################################
#--##### ALU #####
#--####################################################################
co = self._sig("co", HBits(ALU_FULL_W))
s = self._sig("s", HBits(ALU_FULL_W))
comux = self._sig("comux", HBits(ALU_FULL_W))
smux = self._sig("smux", HBits(ALU_FULL_W))
carryout_o = self._sig("carryout_o", HBits(CARRYOUT_W))
# FINAL ADDER
s0 = rename_signal(self, Concat(BIT.from_py(0), comux[11:0], qcarryin_o_mux) + Concat(BIT.from_py(0), smux[12:0]), "s0")
cout0 = rename_signal(self, comux[11] + s0[12], "cout0")
C1 = rename_signal(self, BIT.from_py(0b0) if USE_SIMD == "FOUR12" else s0[12], "C1")
co11_lsb = rename_signal(self, BIT.from_py(0b0) if USE_SIMD == "FOUR12" else comux[11], "co11_lsb")
s1 = rename_signal(self, Concat(BIT.from_py(0), comux[23:12], co11_lsb) + Concat(BIT.from_py(0), smux[24:12]) + Concat(HBits(12).from_py(0), C1), "s1")
cout1 = rename_signal(self, comux[23] + s1[12], "cout1")
C2 = rename_signal(self, BIT.from_py(0b0) if (USE_SIMD in ["TWO24", "FOUR12"]) else s1[12], "C2")
co23_lsb = rename_signal(self, BIT.from_py(0b0) if (USE_SIMD in ["TWO24", "FOUR12"]) else comux[23], "co23_lsb")
s2 = rename_signal(self, Concat(BIT.from_py(0), comux[35:24], co23_lsb) + Concat(BIT.from_py(0), smux[36:24]) + Concat(HBits(12).from_py(0), C2), "s2")
cout2 = rename_signal(self, comux[35] + s2[12], "cout2")
C3 = rename_signal(self, BIT.from_py(0b0) if USE_SIMD == "FOUR12" else s2[12], "C3")
co35_lsb = rename_signal(self, BIT.from_py(0b0) if USE_SIMD == "FOUR12" else comux[35], "co35_lsb")
s3 = rename_signal(self, Concat(BIT.from_py(0), comux[48:36], co35_lsb) + Concat(HBits(2).from_py(0), smux[48:36]) + Concat(HBits(13).from_py(0), C3), "s3")
cout3 = rename_signal(self, s3[12], "cout3")
#cout4 = rename_signal(self, s3[13], "cout4")
qcarryin_o_mux_tmp = self._sig("qcarryin_o_mux_tmp")
ACOUT(qacout_o_mux)
BCOUT(qbcout_o_mux)
CARRYCASCOUT(carrycascout_o_mux)
CARRYOUT(carryout_x_o)
MULTSIGNOUT(multsignout_o_mux)
OVERFLOW(overflow_o)
P(qp_o_mux)
PCOUT(qp_o_mux)
PATTERNDETECT(pdet_o_mux)
PATTERNBDETECT(pdetb_o_mux)
UNDERFLOW(underflow_o)
alumode_in(ALUMODE ^ IS_ALUMODE_INVERTED_BIN)
carryin_in(CARRYIN ^ IS_CARRYIN_INVERTED_BIN)
clk_in(CLK ^ IS_CLK_INVERTED_BIN)
inmode_in(INMODE ^ IS_INMODE_INVERTED_BIN)
opmode_in(OPMODE ^ IS_OPMODE_INVERTED_BIN)
#*********************************************************
#********** INMODE signal registering ************
#*********************************************************
If(clk_in._onRisingEdge(),
If(RSTINMODE,
qinmode_o_reg(0b0)
).Elif(CEINMODE,
qinmode_o_reg(inmode_in)
)
)
if INMODEREG == 0:
qinmode_o_mux(inmode_in)
elif INMODEREG == 1:
qinmode_o_mux(qinmode_o_reg)
else:
raise AssertionError()
if A_INPUT == "DIRECT":
a_o_mux(A)
elif A_INPUT == "CASCADE":
a_o_mux(ACIN)
else:
raise AssertionError()
if AREG in (1, 2):
If(clk_in._onRisingEdge(),
If(RSTA,
qa_o_reg1(0b0),
qa_o_reg2(0b0)
).Else(
If(CEA1,
qa_o_reg1(a_o_mux)
),
If(CEA2,
qa_o_reg2(a_o_mux if AREG == 1 else
qa_o_reg1 if AREG == 2 else
None)
)
)
)
else:
qa_o_reg1(None)
if AREG == 0:
qa_o_mux(a_o_mux)
elif AREG == 1:
qa_o_mux(qa_o_reg2)
elif AREG == 2:
qa_o_mux(qa_o_reg2)
else:
raise AssertionError()
if ACASCREG == 1:
qacout_o_mux(qa_o_reg1 if AREG == 2 else qa_o_mux)
elif ACASCREG == 0:
qacout_o_mux(qa_o_mux)
elif ACASCREG == 2:
qacout_o_mux(qa_o_mux)
else:
raise AssertionError()
If(qinmode_o_mux[1],
a_preaddsub(0b0)
).Elif(qinmode_o_mux[0],
a_preaddsub(qa_o_reg1[25:0]),
).Else(
a_preaddsub(qa_o_mux[25:0]),
)
if B_INPUT == "DIRECT":
b_o_mux(B)
elif B_INPUT == "CASCADE":
b_o_mux(BCIN)
else:
raise AssertionError()
if BREG in (1, 2):
If(clk_in._onRisingEdge(),
If(RSTB,
qb_o_reg1(0b0),
qb_o_reg2(0b0)
).Else(
If(CEB1,
qb_o_reg1(b_o_mux)
),
If(CEB2,
qb_o_reg2(b_o_mux if BREG == 1 else
qb_o_reg1 if BREG == 1 else
None)
)
)
)
else:
qb_o_reg1(None)
if BREG == 0:
qb_o_mux(b_o_mux)
elif BREG == 1:
qb_o_mux(qb_o_reg2)
elif BREG == 2:
qb_o_mux(qb_o_reg2)
else:
raise AssertionError()
if BCASCREG == 1:
qbcout_o_mux(qb_o_reg1 if BREG == 2 else qb_o_mux)
elif BCASCREG == 0:
qbcout_o_mux(qb_o_mux)
elif BCASCREG == 2:
qbcout_o_mux(qb_o_mux)
else:
raise AssertionError()
b_mult(qinmode_o_mux[4]._ternary(qb_o_reg1, qb_o_mux))
#*********************************************************
#*** Input register C with 1 level deep of register
#*********************************************************
If(clk_in._onRisingEdge(),
If(RSTC,
qc_o_reg1(0b0)
).Elif(CEC,
qc_o_reg1(C)
)
)
if CREG == 0:
qc_o_mux(C)
elif CREG == 1:
qc_o_mux(qc_o_reg1)
else:
raise AssertionError()
#*********************************************************
#*** Input register D with 1 level deep of register
#*********************************************************
If(clk_in._onRisingEdge(),
If(RSTD,
qd_o_reg1(0b0)
).Elif(CED,
qd_o_reg1(D)
)
)
if DREG == 0:
qd_o_mux(D)
elif DREG == 1:
qd_o_mux(qd_o_reg1)
else:
raise AssertionError()
ad_addsub(qinmode_o_mux[3]._ternary(-a_preaddsub + qinmode_o_mux[2]._ternary(qd_o_mux, 0b0),
a_preaddsub + qinmode_o_mux[2]._ternary(qd_o_mux, 0b0)))
If(clk_in._onRisingEdge(),
If(RSTD,
qad_o_reg1(0b0)
).Elif(CEAD,
qad_o_reg1(ad_addsub)
)
)
if ADREG == 0:
qad_o_mux(ad_addsub)
elif ADREG == 1:
qad_o_mux(qad_o_reg1)
else:
raise AssertionError()
ad_mult(qad_o_mux if USE_DPORT == "TRUE" else a_preaddsub)
#*********************************************************
#*********************************************************
#*************** 25x18 Multiplier ***************
#*********************************************************
# 05/26/05 -- FP -- Added warning for invalid mult when USE_MULT=NONE
# SIMD=FOUR12 and SIMD=TWO24
# Made mult_o to be "X"
if USE_MULT == "NONE" or USE_SIMD != "ONE48":
mult_o(0b0)
else:
If(CARRYINSEL._eq(0b010),
mult_o(None)
).Else(
mult_o(replicate(18, ad_mult[24])._concat(ad_mult[25:0]) *
replicate(25, b_mult[17])._concat(b_mult))
)
If(clk_in._onRisingEdge(),
If(RSTM,
qmult_o_reg(0b0)
).Elif(CEM,
qmult_o_reg(mult_o)
)
)
If(qcarryinsel_o_mux._eq(0b010),
qmult_o_mux(None)
).Else(
qmult_o_mux(qmult_o_reg if MREG == 1 else mult_o)
)
#*** X mux
# ask jmt
# add post 2014.4
# else
Switch(qopmode_o_mux[2:0])\
.Case(0b00,
# X_SEL.ZERO
qx_o_mux(0b0))\
.Case(0b01,
# X_SEL.M
qx_o_mux(replicate(5, qmult_o_mux[A_MULT_W + B_MULT_W - 1])._concat(qmult_o_mux)))\
.Case(0b10,
# X_SEL.P
qx_o_mux(qp_o_mux if PREG == 1 else None))\
.Case(0b11,
# X_SEL.A_B
qx_o_mux(None)
if USE_MULT == "MULTIPLY" and (
(AREG == 0 and BREG == 0 and MREG == 0) or
(AREG == 0 and BREG == 0 and PREG == 0) or
(MREG == 0 and PREG == 0))
# print("OPMODE Input Warning : The OPMODE[1:0] %b to DSP48E1 instance %m is invalid when using attributes USE_MULT = MULTIPLY at %.3f ns. Please set USE_MULT to either NONE or DYNAMIC.", qopmode_o_mux[slice(2, 0)], sim.now // 1000.000000)
else qx_o_mux(qa_o_mux[A_W:0]._concat(qb_o_mux[B_W:0]))
)
# add post 2014.4
Switch(qopmode_o_mux[4:2])\
.Case(0b00,
qy_o_mux(0b0))\
.Case(0b01,
qy_o_mux(0b0))\
.Case(0b10,
qy_o_mux(y_mac_cascd))\
.Case(0b11,
qy_o_mux(qc_o_mux))
#*** Z mux
# ask jmt
# add post 2014.4
Switch(qopmode_o_mux[7:4])\
.Case(0b000,
qz_o_mux(0b0))\
.Case(0b001,
qz_o_mux(PCIN))\
.Case(0b010,
qz_o_mux(qp_o_mux))\
.Case(0b011,
qz_o_mux(qc_o_mux))\
.Case(0b100,
qz_o_mux(qp_o_mux))\
.Case(0b101,
qz_o_mux(replicate(17, PCIN[47])._concat(PCIN[48:17])))\
.Case(0b110,
qz_o_mux(replicate(17, qp_o_mux[47])._concat(qp_o_mux[48:17])))\
.Case(0b111,
qz_o_mux(replicate(17, qp_o_mux[47])._concat(qp_o_mux[48:17])))
#*** CarryInSel and OpMode with 1 level of register
If(clk_in._onRisingEdge(),
If(RSTCTRL,
qcarryinsel_o_reg1(0b0),
qopmode_o_reg1(0b0)
).Elif(CECTRL,
qcarryinsel_o_reg1(CARRYINSEL),
qopmode_o_reg1(opmode_in)
)
)
if CARRYINSELREG == 0:
qcarryinsel_o_mux(CARRYINSEL)
elif CARRYINSELREG == 1:
qcarryinsel_o_mux(qcarryinsel_o_reg1)
else:
raise AssertionError()
# CR 219047 (3)
# If(qcarryinsel_o_mux._eq(0b010),
# If(~((cci_drc_msg._eq(0b1) | qopmode_o_mux._eq(0b1001000)) | (MULTSIGNIN._eq(0b0) & CARRYCASCIN._eq(0b0))),
# #print("DRC warning : CARRYCASCIN can only be used in the current DSP48E1 instance %m if the previous DSP48E1 is performing a two input ADD or SUBTRACT operation, or the current DSP48E1 is configured in the MAC extend opmode 7'b1001000 at %.3f ns.", sim.now // 1000.000000),
# cci_drc_msg(0b1)
# ),
# If(~((qopmode_o_mux[4:0] != 0b0101)._isOn())._isOn(),
# #print("DRC warning : CARRYINSEL is set to 010 with OPMODE set to multiplication (xxx0101). This is an illegal mode and may show deviation between simulation results and hardware behavior. DSP48E1 instance %m at %.3f ns.", sim.now // 1000.000000)
# ),
# If(~cis_drc_msg._eq(0b1),
# #print("DRC warning : CARRYINSEL is set to 010 with OPMODEREG set to 0. This causes unknown values after reset occurs. It is suggested to use OPMODEREG = 1 when cascading large adders. DSP48E1 instance %m at %.3f ns.", sim.now // 1000.000000),
# cis_drc_msg(0b1)
# ) if OPMODEREG == 0b1 else []
# )
if OPMODEREG == 0:
qopmode_o_mux(opmode_in)
elif OPMODEREG == 1:
qopmode_o_mux(qopmode_o_reg1)
else:
raise AssertionError()
#*** ALUMODE with 1 level of register
If(clk_in._onRisingEdge(),
If(RSTALUMODE,
qalumode_o_reg1(0b0)
).Elif(CEALUMODE,
qalumode_o_reg1(alumode_in)
)
)
if ALUMODEREG == 0:
qalumode_o_mux(alumode_in)
elif ALUMODEREG == 1:
qalumode_o_mux(qalumode_o_reg1)
else:
raise AssertionError()
def deassign_xyz_mux_if_PREG_eq_1():
if PREG != 1:
return self.display_invalid_opmode()
else:
return self.deassign_xyz_mux()
def DCR_check_logic_modes():
# -- LOGIC MODES DRC
return If(In(qopmode_o_mux, LOGIC_MODES_DRC_deassign_xyz_mux),
self.deassign_xyz_mux()
).Elif(In(qopmode_o_mux, LOGIC_MODES_DRC_deassign_xyz_mux_if_PREG_eq_1),
deassign_xyz_mux_if_PREG_eq_1(),
).Else(
# print("OPMODE Input Warning : The OPMODE %b to DSP48E1 instance %m is invalid for LOGIC MODES at %.3f ns.", qopmode_o_mux, sim.now // 1000.000000)
)
# display_invalid_opmode
arith_mode_tmp = qopmode_o_mux._concat(qcarryinsel_o_mux)
# no check at first 100ns
Switch(qalumode_o_mux[4:2])\
.Case(0b00,
# -- ARITHMETIC MODES DRC
If(In(arith_mode_tmp, ARITHMETIC_MODES_DRC_deassign_xyz_mux),
self.deassign_xyz_mux()
).Elif(In(arith_mode_tmp, ARITHMETIC_MODES_DRC_deassign_xyz_mux_if_PREG_eq_1),
deassign_xyz_mux_if_PREG_eq_1()
).Else(
# CR 444150
# If(qopmode_o_mux._concat(qcarryinsel_o_mux)._eq(0b0000000010)._isOn() & (OPMODEREG._eq(1)._isOn() & CARRYINSELREG._eq(0)._isOn())._isOn(),
# print("DRC warning : CARRYINSELREG is set to %d. It is required to have CARRYINSELREG be set to 1 to match OPMODEREG, in order to ensure that the simulation model will match the hardware behavior in all use cases.", CARRYINSELREG)
# ),
# print("OPMODE Input Warning : The OPMODE %b to DSP48E1 instance %m is either invalid or the CARRYINSEL %b for that specific OPMODE is invalid at %.3f ns. This warning may be due to a mismatch in the OPMODEREG and CARRYINSELREG attribute settings. It is recommended that OPMODEREG and CARRYINSELREG always be set to the same value. ", qopmode_o_mux, qcarryinsel_o_mux, sim.now // 1000.000000)
)
)\
.Case(0b01,
DCR_check_logic_modes()
)\
.Case(0b11,
DCR_check_logic_modes()
)\
.Default(
# print("OPMODE Input Warning : The OPMODE %b to DSP48E1 instance %m is invalid for LOGIC MODES at %.3f ns.", qopmode_o_mux, sim.now // 1000.000000)
)
If(qalumode_o_mux[0],
co(qx_o_mux & qy_o_mux | ~qz_o_mux & qy_o_mux | qx_o_mux & ~qz_o_mux),
s(~qz_o_mux ^ qx_o_mux ^ qy_o_mux)
).Else(
co(qx_o_mux & qy_o_mux | qz_o_mux & qy_o_mux | qx_o_mux & qz_o_mux),
s(qz_o_mux ^ qx_o_mux ^ qy_o_mux)
)
If(qalumode_o_mux[2],
comux(0),
).Else(
comux(co),
)
smux(qalumode_o_mux[3]._ternary(co, s))
carryout_o_hw = self._sig("carryout_o_hw", HBits(CARRYOUT_W))
carryout_o_hw[0]((qalumode_o_mux[0] & qalumode_o_mux[1])._ternary(~cout0, cout0))
carryout_o_hw[1]((qalumode_o_mux[0] & qalumode_o_mux[1])._ternary(~cout1, cout1))
carryout_o_hw[2]((qalumode_o_mux[0] & qalumode_o_mux[1])._ternary(~cout2, cout2))
carryout_o_hw[3]((qalumode_o_mux[0] & qalumode_o_mux[1])._ternary(~cout3, cout3))
alu_o(qalumode_o_mux[1]._ternary(
~Concat(s3[12:0], s2[12:0], s1[12:0], s0[12:0]),
Concat(s3[12:0], s2[12:0], s1[12:0], s0[12:0])
))
carrycascout_o(cout3)
multsignout_o_opmode((qopmode_o_mux[7:4]._eq(0b100))._ternary(MULTSIGNIN, qmult_o_mux[42]))
If((qopmode_o_mux[4:0]._eq(0b0101) | (qalumode_o_mux[4:2] != 0b00)),
carryout_o[3](None),
carryout_o[2](None),
carryout_o[1](None),
carryout_o[0](None),
).Else(
carryout_o[3](carryout_o_hw[3]),
carryout_o[2](carryout_o_hw[2] if USE_SIMD == "FOUR12" else None),
carryout_o[1](carryout_o_hw[1] if USE_SIMD in ["TWO24", "FOUR12"] else None),
carryout_o[0](carryout_o_hw[0] if USE_SIMD == "FOUR12" else None),
)
#--########################### END ALU ################################
#*** CarryIn Mux and Register
#------- input 0
If(clk_in._onRisingEdge(),
If(RSTALLCARRYIN,
qcarryin_o_reg0(0b0)
).Elif(CECARRYIN,
qcarryin_o_reg0(carryin_in)
)
)
if CARRYINREG == 0:
qcarryin_o_mux0(carryin_in)
elif CARRYINREG == 1:
qcarryin_o_mux0(qcarryin_o_reg0)
else:
raise AssertionError()
#------- input 7
If(clk_in._onRisingEdge(),
If(RSTALLCARRYIN,
qcarryin_o_reg7(0b0)
).Elif(CEM,
qcarryin_o_reg7(ad_mult[24]._eq(b_mult[17]))
)
)
if MREG == 0:
qcarryin_o_mux7(ad_mult[24]._eq(b_mult[17]))
elif MREG == 1:
qcarryin_o_mux7(qcarryin_o_reg7)
else:
raise ValueError("MREG is set to %d. Legal values for this attribute are 0 or 1.", MREG)
Switch(qcarryinsel_o_mux)\
.Case(CARRYIN_SEL.CARRYIN.value,
qcarryin_o_mux_tmp(qcarryin_o_mux0))\
.Case(CARRYIN_SEL.PCIN_47_n.value,
qcarryin_o_mux_tmp(~PCIN[47]))\
.Case(CARRYIN_SEL.CARRYCASCIN.value,
qcarryin_o_mux_tmp(CARRYCASCIN))\
.Case(CARRYIN_SEL.PCIN_47.value,
qcarryin_o_mux_tmp(PCIN[47]))\
.Case(CARRYIN_SEL.CARRYCASCOUT.value,
qcarryin_o_mux_tmp(carrycascout_o_mux))\
.Case(CARRYIN_SEL.P_47_n.value,
qcarryin_o_mux_tmp(~qp_o_mux[47]))\
.Case(CARRYIN_SEL.A_27_eq_B_17.value,
qcarryin_o_mux_tmp(qcarryin_o_mux7))\
.Case(CARRYIN_SEL.P_47.value,
qcarryin_o_mux_tmp(qp_o_mux[47]))
# disable carryin when performing logic operation
If(qalumode_o_mux[3] | qalumode_o_mux[2],
qcarryin_o_mux(0b0)
).Else(
qcarryin_o_mux(qcarryin_o_mux_tmp)
)
if AUTORESET_PATDET == "RESET_MATCH":
the_auto_reset_patdet(pdet_o_reg1)
elif AUTORESET_PATDET == "RESET_NOT_MATCH":
the_auto_reset_patdet(pdet_o_reg2 & ~pdet_o_reg1)
else:
the_auto_reset_patdet(0)
#--####################################################################
#--##### CARRYOUT, CARRYCASCOUT. MULTSIGNOUT and PCOUT ######
#--####################################################################
#*** register with 1 level of register
If(clk_in._onRisingEdge(),
If(RSTP._isOn() | the_auto_reset_patdet._isOn(),
carryout_o_reg(0b0),
carrycascout_o_reg(0b0),
qmultsignout_o_reg(0b0),
qp_o_reg1(0b0)
).Elif(CEP,
carryout_o_reg(carryout_o),
carrycascout_o_reg(carrycascout_o),
qmultsignout_o_reg(multsignout_o_opmode),
qp_o_reg1(alu_o)
)
)
if PREG == 0:
carryout_o_mux(carryout_o)
carrycascout_o_mux(carrycascout_o)
multsignout_o_mux(multsignout_o_opmode)
qp_o_mux(alu_o)
elif PREG == 1:
carryout_o_mux(carryout_o_reg)
carrycascout_o_mux(carrycascout_o_reg)
multsignout_o_mux(qmultsignout_o_reg)
qp_o_mux(qp_o_reg1)
else:
raise AssertionError()
carryout_x_o(Concat(
carryout_o_mux[3],
carryout_o_mux[2] if USE_SIMD == "FOUR12" else BIT.from_py(None),
carryout_o_mux[1] if USE_SIMD in ["TWO24", "FOUR12"] else BIT.from_py(None),
carryout_o_mux[0] if USE_SIMD == "FOUR12" else BIT.from_py(None),
))
the_pattern(PATTERN if SEL_PATTERN == "PATTERN" else qc_o_mux)
# selet mask
if USE_PATTERN_DETECT == "NO_PATDET":
the_mask(mask(48))
elif SEL_MASK == "MASK":
the_mask(MASK)
elif SEL_MASK == "C":
the_mask(qc_o_mux)
elif SEL_MASK == "ROUNDING_MODE1":
the_mask(~qc_o_mux << 1)
elif SEL_MASK == "ROUNDING_MODE2":
the_mask(~qc_o_mux << 2)
else:
raise AssertionError()
If(opmode_valid_flag,
pdet_o(And(*(~(the_pattern ^ alu_o) | the_mask))),
pdetb_o(And(*(the_pattern ^ alu_o | the_mask))),
).Else(
pdet_o(None),
pdetb_o(None),
)
pdet_o_mux(pdet_o_reg1 if PREG == 1 else pdet_o)
pdetb_o_mux(pdetb_o_reg1 if PREG == 1 else pdetb_o)
#*** Output register PATTERN DETECT and UNDERFLOW / OVERFLOW
If(clk_in._onRisingEdge(),
If(RSTP._isOn() | the_auto_reset_patdet._isOn(),
pdet_o_reg1(0b0),
pdet_o_reg2(0b0),
pdetb_o_reg1(0b0),
pdetb_o_reg2(0b0)
).Elif(CEP,
pdet_o_reg2(pdet_o_reg1),
pdet_o_reg1(pdet_o),
pdetb_o_reg2(pdetb_o_reg1),
pdetb_o_reg1(pdetb_o)
)
)
if PREG == 1 or USE_PATTERN_DETECT == "PATDET":
overflow_o(pdet_o_reg2 & ~pdet_o_reg1 & ~pdetb_o_reg1),
underflow_o(pdetb_o_reg2 & ~pdet_o_reg1 & ~pdetb_o_reg1)
else:
overflow_o(None),
underflow_o(None)
if __name__ == "__main__":
from hwt.synth import to_rtl_str
m = DSP48E1()
print("# note that nothing should be printed out because the DSP48E1 has dissabled serialization (because it is part of UNISIM library)")
print(to_rtl_str(m))